我正在尝试将this动态双重调度的示例移植到C#。我已经有了实例,但我觉得我通过使用Reflection来创建所需的处理程序并调用适当的方法,使DynamicDispatch
类中的MessageBase
方法略微快捷。可以提供一些关于如何改变它的建议吗?该示例使用C ++ dynamic_cast运算符,我不确定C#的等价物是什么。我不确定我的解决方案是正确/最好的方式。
注意:我使用的是3.5,因此我无法使用动态关键字
以下是代码:
即时聊天
public interface IMessage
{
void Dispatch(IHandler handler);
}
MessageBase
public abstract class MessageBase : IMessage
{
public abstract void Dispatch(IHandler handler);
// This is my concern, doesnt feel like the right way to do this
protected void DynamicDispatch<MessageType>(IHandler handler, MessageType self)
{
// Get the messages derived type
Type self_type = self.GetType();
// Create actual message specific handler
Type message_handler = typeof(IMessageHandler<>).MakeGenericType(self_type);
// Get the ProcessMessage method
MethodInfo minfo = message_handler.GetMethod("ProcessMessage");
try
{
// Invoke it with the message
minfo.Invoke(handler, new object[] { self });
}
catch (TargetException ex)
{
// Ignore if method doesnt exist
}
}
}
消息
public class Message : MessageBase
{
public override void Dispatch(IHandler handler)
{
DynamicDispatch(handler, this);
}
}
IHandler
public interface IHandler
{
}
IMessageHandler
public interface IMessageHandler<MessageType> : IHandler
{
void ProcessMessage(MessageType message);
}
DerivedMessageOne
public class DerivedMessageOne : Message
{
public int MessageOneField;
}
DerivedMessageTwo
public class DerivedMessageTwo : Message
{
public int MessageTwoField;
}
DerivedMessageHandlerOne
public class DerivedMessageHandlerOne : IMessageHandler<DerivedMessageOne>,
IMessageHandler<DerivedMessageTwo>
{
#region IMessageHandler<MessaegType> Members
// ************ handle both messages *************** //
public void ProcessMessage(DerivedMessageOne message)
{
// Received Message one, do soemthing with i
int do_something_with_it = message.MessageOneField;
}
public void ProcessMessage(DerivedMessageTwo message)
{
// Received Message two, do soemthing with i
}
#endregion
}
DerivedMessageHandlerTwo
public class DerivedMessageHandlerTwo : IMessageHandler<DerivedMessageOne>
{
#region IMessageHandler<MessaegType> Members
// ************ handle just MessageOne *************** //
public void ProcessMessage(DerivedMessageOne message)
{
// Received Message one, do soemthing with i
}
#endregion
}
测试用例
IMessage messageOne = new DerivedMessageOne();
IMessage messageTwo = new DerivedMessageTwo();
IHandler handlerOne = new DerivedMessageHandlerOne();
IHandler handlerTwo = new DerivedMessageHandlerTwo();
messageOne.Dispatch(handlerOne);
messageOne.Dispatch(handlerTwo);
messageTwo.Dispatch(handlerOne);
messageTwo.Dispatch(handlerTwo);
答案 0 :(得分:2)
在C#中,您需要as
运算符。
http://msdn.microsoft.com/en-us/library/vstudio/cscsdfbt.aspx
它的行为与C ++ dynamic_cast
完全相同。
这里可以使用类似的东西:
IMessageHandler<MessageType> handlerTarget = handler as IMessageHandler<MessageType>;
handlerTarget.ProcessMessage(message);
如您所述,您必须将消息类型传递到消息库中,例如:
class MessageBase
{
protected void DoDispatch<T>(T m)
{
// ...
}
}
class Message<T> : MessageBase where T : class
{
public void Dispatch()
{
DoDispatch<T>(this as T);
}
}
class MyMessage : Message<MyMessage>
{
}
答案 1 :(得分:0)
我发现这个DoubleDispatch在没有动态的情况下工作正常:
namespace DoubleDispatch
{
public interface IMessage
{
void Dispatch(HandlerBase handler);
}
public interface IHandler
{
void HandleDefault(IMessage message);
}
public interface IHandler<in TMessage> : IHandler
where TMessage : class, IMessage
{
void HandleSpecific(TMessage message);
}
public interface IMessage<TMessage, THandler> : IMessage
where TMessage : class, IMessage<TMessage, THandler>
where THandler : class, IHandler<TMessage>
{
}
public abstract class HandlerBase : IHandler
{
public void HandleDefault(IMessage message)
{
Console.WriteLine("HandlerBase process {0}", message.GetType().Name);
}
}
public abstract class MessageBase<TMessage, THandler>
: IMessage<TMessage, IHandler<TMessage>>
where TMessage : class, IMessage, IMessage<TMessage, IHandler<TMessage>>
where THandler : class, IHandler, IHandler<TMessage>
{
public void Dispatch(HandlerBase handler)
{
var runtimeHandler = handler as THandler;
if (runtimeHandler != null)
{
var runtimeMessage = this as TMessage;
if (runtimeMessage != null)
{
runtimeHandler.HandleSpecific(runtimeMessage);
return;
}
}
handler.HandleDefault(this);
}
}
public class FirstMessage : MessageBase<FirstMessage, IHandler<FirstMessage>>
{
}
public class SecondMessage : MessageBase<SecondMessage, IHandler<SecondMessage>>
{
}
public class FirstHandler : HandlerBase, IHandler<FirstMessage>
{
public void HandleSpecific(FirstMessage message)
{
Console.WriteLine("FirstHandler process {0}", message.GetType().Name);
}
}
public class SecondHandler : HandlerBase, IHandler<SecondMessage>
{
public void HandleSpecific(SecondMessage message)
{
Console.WriteLine("SecondHandler process {0}", message.GetType().Name);
}
}
public class ThirdHandler : HandlerBase, IHandler<FirstMessage>, IHandler<SecondMessage>
{
public void HandleSpecific(FirstMessage message)
{
Console.WriteLine("ThirdHandler process {0}", message.GetType().Name);
}
public void HandleSpecific(SecondMessage message)
{
Console.WriteLine("ThirdHandler process {0}", message.GetType().Name);
}
}
public class EmptyHandler : HandlerBase
{
}
public static class DoubleDispatch
{
public static void Test()
{
var handlers = new HandlerBase[]
{
new FirstHandler(),
new SecondHandler(),
new ThirdHandler(),
new EmptyHandler(),
};
var messages = new IMessage[]
{
new FirstMessage(),
new SecondMessage(),
};
Array.ForEach(messages, m =>
{
Array.ForEach(handlers, m.Dispatch);
Console.WriteLine();
});
}
}
}