1
0
mirror of https://github.com/chylex/.NET-Community-Toolkit.git synced 2025-08-16 23:31:47 +02:00
Files
.github
CommunityToolkit.Common
CommunityToolkit.Diagnostics
CommunityToolkit.HighPerformance
CommunityToolkit.Mvvm
Collections
ComponentModel
DependencyInjection
Input
Messaging
Internals
System
ArrayPoolBufferWriter{T}.cs
MessageHandlerDispatcher.cs
Type2.cs
Unit.cs
Messages
IMessenger.cs
IMessengerExtensions.cs
IRecipient{TMessage}.cs
MessageHandler{TRecipient,TMessage}.cs
StrongReferenceMessenger.cs
WeakReferenceMessenger.cs
Properties
CommunityToolkit.Mvvm.csproj
CommunityToolkit.Mvvm.targets
CommunityToolkit.Mvvm.SourceGenerators
build
tests
.editorconfig
.git-blame-ignore-revs
.gitattributes
.gitignore
.runsettings
CODE_OF_CONDUCT.md
Contributing.md
Directory.Build.props
Directory.Build.targets
License.md
README.md
ThirdPartyNotices.txt
azure-pipelines.yml
dotnet Community Toolkit.sln
toolkit.snk
version.json
2022-06-11 16:28:44 +02:00

83 lines
3.2 KiB
C#

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.CompilerServices;
namespace CommunityToolkit.Mvvm.Messaging.Internals;
/// <summary>
/// A simple type representing an immutable pair of types.
/// </summary>
/// <remarks>
/// This type replaces a simple <see cref="ValueTuple{T1,T2}"/> as it's faster in its
/// <see cref="GetHashCode"/> and <see cref="IEquatable{T}.Equals(T)"/> methods, and because
/// unlike a value tuple it exposes its fields as immutable. Additionally, the
/// <see cref="TMessage"/> and <see cref="TToken"/> fields provide additional clarity reading
/// the code compared to <see cref="ValueTuple{T1,T2}.Item1"/> and <see cref="ValueTuple{T1,T2}.Item2"/>.
/// </remarks>
internal readonly struct Type2 : IEquatable<Type2>
{
/// <summary>
/// The type of registered message.
/// </summary>
public readonly Type TMessage;
/// <summary>
/// The type of registration token.
/// </summary>
public readonly Type TToken;
/// <summary>
/// Initializes a new instance of the <see cref="Type2"/> struct.
/// </summary>
/// <param name="tMessage">The type of registered message.</param>
/// <param name="tToken">The type of registration token.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Type2(Type tMessage, Type tToken)
{
this.TMessage = tMessage;
this.TToken = tToken;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Type2 other)
{
// We can't just use reference equality, as that's technically not guaranteed
// to work and might fail in very rare cases (eg. with type forwarding between
// different assemblies). Instead, we can use the == operator to compare for
// equality, which still avoids the callvirt overhead of calling Type.Equals,
// and is also implemented as a JIT intrinsic on runtimes such as .NET Core.
return
this.TMessage == other.TMessage &&
this.TToken == other.TToken;
}
/// <inheritdoc/>
public override bool Equals(object? obj)
{
return obj is Type2 other && Equals(other);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
{
// To combine the two hashes, we can simply use the fast djb2 hash algorithm. Unfortunately we
// can't really skip the callvirt here (eg. by using RuntimeHelpers.GetHashCode like in other
// cases), as there are some niche cases mentioned above that might break when doing so.
// However since this method is not generally used in a hot path (eg. the message broadcasting
// only invokes this a handful of times when initially retrieving the target mapping), this
// doesn't actually make a noticeable difference despite the minor overhead of the virtual call.
int hash = this.TMessage.GetHashCode();
hash = (hash << 5) + hash;
hash += this.TToken.GetHashCode();
return hash;
}
}