本篇定位 前三篇分析了 WeakReferenceMessenger 和 StrongReferenceMessenger 的内部实现。这篇聚焦接口层设计 。
1. IMessenger 接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public interface IMessenger { bool IsRegistered <TMessage , TToken >(object recipient, TToken token ) where TMessage : class where TToken : IEquatable <TToken > ; void Register <TRecipient , TMessage , TToken >(TRecipient recipient, TToken token, MessageHandler<TRecipient, TMessage> handler ) where TRecipient : class where TMessage : class where TToken : IEquatable <TToken > ; void UnregisterAll (object recipient ) ; void UnregisterAll <TToken >(object recipient, TToken token ) where TToken : IEquatable <TToken > ; void Unregister <TMessage , TToken >(object recipient, TToken token ) where TMessage : class where TToken : IEquatable <TToken > ; TMessage Send <TMessage , TToken >(TMessage message, TToken token ) where TMessage : class where TToken : IEquatable<TToken> ; void Cleanup () ; void Reset () ; }
约束说明:
TMessage : class — 消息必须是引用类型
TToken : IEquatable<TToken> — 通道标识必须可比较
2. 示例:五种注册方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 WeakReferenceMessenger.Default.Register<MyMessage>(this , (r, m) => { Console.WriteLine($"收到消息: {m.Text} " ); }); WeakReferenceMessenger.Default.Register<MyMessage>(this , static (r, m) => ((MyViewModel)r).HandleMessage(m)); WeakReferenceMessenger.Default.Register<MyMessage>(this , HandleMessage); private void HandleMessage (object recipient, MyMessage message ) { }public class MyViewModel : IRecipient <MyMessage >, IRecipient <OtherMessage >{ public MyViewModel () { WeakReferenceMessenger.Default.RegisterAll(this ); } public void Receive (MyMessage message ) { } public void Receive (OtherMessage message ) { } } WeakReferenceMessenger.Default.Register<MyMessage, string >( this , "ChannelA" , (r, m) => { });
3. 示例:MessageHandler 委托的设计意图 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public delegate void MessageHandler <TRecipient , in TMessage >( TRecipient recipient, TMessage message ) ;button.Click += (s, e) => this .HandleClick(e); Messenger.Register<MyMessage>(this , static (r, m) => ((MyViewModel)r).Handle(m));
4. 示例:Unit Token — 默认通道 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public static void Register <TMessage >(this IMessenger messenger, IRecipient<TMessage> recipient ){ messenger.Register<IRecipient<TMessage>, TMessage, Unit>( recipient, default , static (r, m) => r.Receive(m)); } internal readonly struct Unit : IEquatable<Unit>{ public bool Equals (Unit other ) => true ; public override int GetHashCode () => 0 ; }
5. RegisterAll 双路径策略 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public static void RegisterAll (this IMessenger messenger, object recipient ){ var registrationAction = DiscoveredRecipients.RegistrationMethods.GetValue( recipient.GetType(), type => { if (type.Assembly.GetType( "CommunityToolkit.Mvvm.Messaging.__Internals.__IMessengerExtensions" ) is Type t && t.GetMethod("CreateAllMessagesRegistrator" , new [] { type }) is MethodInfo mi) { return (Action<IMessenger, object >)mi.Invoke(null , null )!; } return null ; }); if (registrationAction is not null ) registrationAction(messenger, recipient); else messenger.RegisterAll(recipient, default (Unit)); }
6. 性能总结
注册方式
分配
调用方式
推荐场景
Register(this, (r,m)=>...)
委托 + 闭包
间接调用
日常使用
Register(this, static (r,m)=>...)
静态委托
间接调用
性能敏感路径
RegisterAll + IRecipient<T>
零
直接虚方法
接口清晰时
带 Token
多一个 Dictionary
同上的*
频道隔离
下一篇预告:系列总结 — 从源码看 CommunityToolkit.Mvvm 的设计哲学