Skip to content

Commit 9809522

Browse files
committed
Code refactoring, removed duplicate types
1 parent d68f9d2 commit 9809522

File tree

13 files changed

+121
-197
lines changed

13 files changed

+121
-197
lines changed

Microsoft.Toolkit.Mvvm/ComponentModel/ObservableRecipient.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public bool IsActive
7979
/// <remarks>
8080
/// The base implementation registers all messages for this recipients that have been declared
8181
/// explicitly through the <see cref="IRecipient{TMessage}"/> interface, using the default channel.
82-
/// For more details on how this works, see the <see cref="MessengerExtensions.RegisterAll"/> method.
82+
/// For more details on how this works, see the <see cref="IMessengerExtensions.RegisterAll"/> method.
8383
/// If you need more fine tuned control, want to register messages individually or just prefer
8484
/// the lambda-style syntax for message registration, override this method and register manually.
8585
/// </remarks>

Microsoft.Toolkit.Mvvm/Messaging/IMessenger.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,12 @@ public delegate void MessageHandler<in TRecipient, in TMessage>(TRecipient recip
6464
/// Messenger.Default.Register(this, Receive);
6565
/// </code>
6666
/// The C# compiler will automatically convert that expression to a <see cref="MessageHandler{TRecipient,TMessage}"/> instance
67-
/// compatible with <see cref="MessengerExtensions.Register{TRecipient,TMessage}(IMessenger,TRecipient,MessageHandler{TRecipient,TMessage})"/>.
67+
/// compatible with <see cref="IMessengerExtensions.Register{TRecipient,TMessage}(IMessenger,TRecipient,MessageHandler{TRecipient,TMessage})"/>.
6868
/// This will also work if multiple overloads of that method are available, each handling a different
6969
/// message type: the C# compiler will automatically pick the right one for the current message type.
7070
/// It is also possible to register message handlers explicitly using the <see cref="IRecipient{TMessage}"/> interface.
7171
/// To do so, the recipient just needs to implement the interface and then call the
72-
/// <see cref="MessengerExtensions.RegisterAll(IMessenger,object)"/> extension, which will automatically register
72+
/// <see cref="IMessengerExtensions.RegisterAll(IMessenger,object)"/> extension, which will automatically register
7373
/// all the handlers that are declared by the recipient type. Registration for individual handlers is supported as well.
7474
/// </summary>
7575
public interface IMessenger

Microsoft.Toolkit.Mvvm/Messaging/MessengerExtensions.cs renamed to Microsoft.Toolkit.Mvvm/Messaging/IMessengerExtensions.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,20 @@
88
using System.Linq.Expressions;
99
using System.Reflection;
1010
using System.Runtime.CompilerServices;
11+
using Microsoft.Toolkit.Mvvm.Messaging.Internals;
1112

1213
namespace Microsoft.Toolkit.Mvvm.Messaging
1314
{
1415
/// <summary>
1516
/// Extensions for the <see cref="IMessenger"/> type.
1617
/// </summary>
17-
public static partial class MessengerExtensions
18+
public static class IMessengerExtensions
1819
{
1920
/// <summary>
2021
/// A class that acts as a container to load the <see cref="MethodInfo"/> instance linked to
2122
/// the <see cref="Register{TMessage,TToken}(IMessenger,IRecipient{TMessage},TToken)"/> method.
2223
/// This class is needed to avoid forcing the initialization code in the static constructor to run as soon as
23-
/// the <see cref="MessengerExtensions"/> type is referenced, even if that is done just to use methods
24+
/// the <see cref="IMessengerExtensions"/> type is referenced, even if that is done just to use methods
2425
/// that do not actually require this <see cref="MethodInfo"/> instance to be available.
2526
/// We're effectively using this type to leverage the lazy loading of static constructors done by the runtime.
2627
/// </summary>
@@ -32,7 +33,7 @@ private static class MethodInfos
3233
static MethodInfos()
3334
{
3435
RegisterIRecipient = (
35-
from methodInfo in typeof(MessengerExtensions).GetMethods()
36+
from methodInfo in typeof(IMessengerExtensions).GetMethods()
3637
where methodInfo.Name == nameof(Register) &&
3738
methodInfo.IsGenericMethod &&
3839
methodInfo.GetGenericArguments().Length == 2

Microsoft.Toolkit.Mvvm/Messaging/Microsoft.Collections.Extensions/DictionarySlim{TKey,TValue}.cs renamed to Microsoft.Toolkit.Mvvm/Messaging/Internals/Microsoft.Collections.Extensions/DictionarySlim{TKey,TValue}.cs

File renamed without changes.

Microsoft.Toolkit.Mvvm/Messaging/Microsoft.Collections.Extensions/HashHelpers.cs renamed to Microsoft.Toolkit.Mvvm/Messaging/Internals/Microsoft.Collections.Extensions/HashHelpers.cs

File renamed without changes.

Microsoft.Toolkit.Mvvm/Messaging/Microsoft.Collections.Extensions/IDictionarySlim.cs renamed to Microsoft.Toolkit.Mvvm/Messaging/Internals/Microsoft.Collections.Extensions/IDictionarySlim.cs

File renamed without changes.

Microsoft.Toolkit.Mvvm/Messaging/Microsoft.Collections.Extensions/IDictionarySlim{TKey,TValue}.cs renamed to Microsoft.Toolkit.Mvvm/Messaging/Internals/Microsoft.Collections.Extensions/IDictionarySlim{TKey,TValue}.cs

File renamed without changes.

Microsoft.Toolkit.Mvvm/Messaging/Microsoft.Collections.Extensions/IDictionarySlim{TKey}.cs renamed to Microsoft.Toolkit.Mvvm/Messaging/Internals/Microsoft.Collections.Extensions/IDictionarySlim{TKey}.cs

File renamed without changes.
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using System;
2+
using System.Runtime.CompilerServices;
3+
4+
namespace Microsoft.Toolkit.Mvvm.Messaging.Internals
5+
{
6+
/// <summary>
7+
/// A simple type representing an immutable pair of types.
8+
/// </summary>
9+
/// <remarks>
10+
/// This type replaces a simple <see cref="ValueTuple{T1,T2}"/> as it's faster in its
11+
/// <see cref="GetHashCode"/> and <see cref="IEquatable{T}.Equals(T)"/> methods, and because
12+
/// unlike a value tuple it exposes its fields as immutable. Additionally, the
13+
/// <see cref="TMessage"/> and <see cref="TToken"/> fields provide additional clarity reading
14+
/// the code compared to <see cref="ValueTuple{T1,T2}.Item1"/> and <see cref="ValueTuple{T1,T2}.Item2"/>.
15+
/// </remarks>
16+
internal readonly struct Type2 : IEquatable<Type2>
17+
{
18+
/// <summary>
19+
/// The type of registered message.
20+
/// </summary>
21+
public readonly Type TMessage;
22+
23+
/// <summary>
24+
/// The type of registration token.
25+
/// </summary>
26+
public readonly Type TToken;
27+
28+
/// <summary>
29+
/// Initializes a new instance of the <see cref="Type2"/> struct.
30+
/// </summary>
31+
/// <param name="tMessage">The type of registered message.</param>
32+
/// <param name="tToken">The type of registration token.</param>
33+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
34+
public Type2(Type tMessage, Type tToken)
35+
{
36+
TMessage = tMessage;
37+
TToken = tToken;
38+
}
39+
40+
/// <inheritdoc/>
41+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
42+
public bool Equals(Type2 other)
43+
{
44+
// We can't just use reference equality, as that's technically not guaranteed
45+
// to work and might fail in very rare cases (eg. with type forwarding between
46+
// different assemblies). Instead, we can use the == operator to compare for
47+
// equality, which still avoids the callvirt overhead of calling Type.Equals,
48+
// and is also implemented as a JIT intrinsic on runtimes such as .NET Core.
49+
return
50+
TMessage == other.TMessage &&
51+
TToken == other.TToken;
52+
}
53+
54+
/// <inheritdoc/>
55+
public override bool Equals(object? obj)
56+
{
57+
return obj is Type2 other && Equals(other);
58+
}
59+
60+
/// <inheritdoc/>
61+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
62+
public override int GetHashCode()
63+
{
64+
unchecked
65+
{
66+
// To combine the two hashes, we can simply use the fast djb2 hash algorithm.
67+
// This is not a problem in this case since we already know that the base
68+
// RuntimeHelpers.GetHashCode method is providing hashes with a good enough distribution.
69+
int hash = RuntimeHelpers.GetHashCode(TMessage);
70+
71+
hash = (hash << 5) + hash;
72+
73+
hash += RuntimeHelpers.GetHashCode(TToken);
74+
75+
return hash;
76+
}
77+
}
78+
}
79+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using System.Runtime.CompilerServices;
3+
4+
namespace Microsoft.Toolkit.Mvvm.Messaging.Internals
5+
{
6+
/// <summary>
7+
/// An empty type representing a generic token with no specific value.
8+
/// </summary>
9+
internal readonly struct Unit : IEquatable<Unit>
10+
{
11+
/// <inheritdoc/>
12+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
13+
public bool Equals(Unit other)
14+
{
15+
return true;
16+
}
17+
18+
/// <inheritdoc/>
19+
public override bool Equals(object? obj)
20+
{
21+
return obj is Unit;
22+
}
23+
24+
/// <inheritdoc/>
25+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
26+
public override int GetHashCode()
27+
{
28+
return 0;
29+
}
30+
}
31+
}

0 commit comments

Comments
 (0)