我正在尝试使用List
个开放泛型类型。有可能有类似的东西:
public class MessageProcessor
{
private IDictionary<Type, IMessageHandler<>> _messageHandlers
= new Dictionary<Type, IMessageHandler<>>();
public void AddHandler<TMessage>(IMessageHandler<TMessage> handler)
{
var messageType = typeof(TMessage);
// Add to dictionary here
}
public void Handle<TMessage>(TMessage message)
{
// Call the correct handler here.
}
}
IMessageHandler
应该有一个强类型的方法:
public void Handle(TMessage message) {}
我的真实例子有点复杂,所以我希望我在这里正确地简化它。
事实是,我对每个处理程序的泛型类型不感兴趣。我只需要在一个地方安装所有这些,我可以很容易地找到正确的处理程序,如果我可以在那个地方找到它们。
私有词典将消息类型(TMessage)作为键。所以我希望能够做到:
// ByteArrayHandler implements IMessageHandler<byte[]>
x.AddHandler(new ByteArrayHandler())
// StringHandler implements IMessageHandler<string>
x.AddHandler(new StringHandler())
x.Handle("Some message");
x.Handle(new byte[] { 1, 2, 3} );
让MessageProcessor
调用正确的MessageHandler
。
答案 0 :(得分:4)
每个人都知道扩展方法。但是&#34;扩展领域&#34 ;?当然,用一些新字段扩展某些对象是不可能的,但是......你见过ConditionalWeakTable类吗?使用它我们可以将一些数据附加/关联到现有对象。很酷的功能是我们不需要显式删除该字典中的项目。对象存储为弱引用,因此当GC收集密钥时,将自动删除键值对。 使用它我们可以发明这个棘手的解决方案:
public class MessageProcessor
{
private static class MessageHandlerHolder<TMessage>
{
public static readonly ConditionalWeakTable<MessageProcessor, IMessageHandler<TMessage>> MessageHandlers =
new ConditionalWeakTable<MessageProcessor, IMessageHandler<TMessage>>();
}
public void AddHandler<TMessage>(IMessageHandler<TMessage> handler)
{
MessageHandlerHolder<TMessage>.MessageHandlers.Add(this, handler);
}
public void Handle<TMessage>(TMessage message)
{
IMessageHandler<TMessage> handler;
if (!MessageHandlerHolder<TMessage>.MessageHandlers.TryGetValue(this, out handler))
throw new InvalidOperationException("...");
handler.Handle(message);
}
}
因此,所有内容都是强大且静态类型的,客户端不需要显式删除处理程序以避免内存泄漏。
答案 1 :(得分:1)
你必须让它实现另一个非通用的接口。
所以:
interface IMessageHandler<T> : IMessageHandler
然后,您的MessageProcessor类将保留对IMessageHandler
的引用。
据我所知,“空”泛型类型仅用于typeof
。
答案 2 :(得分:1)
public class MessageProcessor
{
private readonly IDictionary<Type, Action<object>> _messageHandlers = new Dictionary<Type, Action<object>>();
public void AddHandler<TMessage>(IMessageHandler<TMessage> handler)
{
AddHandler((Action<TMessage>) handler.Handle);
}
public void AddHandler<TMessage>(Action<TMessage> handler)
{
var messageType = typeof (TMessage);
_messageHandlers.Add(messageType, msg => handler((TMessage) msg));//Note: downcast
}
public void Handle<TMessage>(TMessage message)
{
var messageType = typeof (TMessage);
_messageHandlers[messageType](message);
//OR (if runtime type should be used):
_messageHandlers[message.GetType()](message);
}
}
<强>更新强>
当然,您可以将messageHandler的类型更改为Dictionary<Type, object>
并直接存储IMessageHandler<TMessage>
个实例。
更新2: 如果一切都是静态的,那么只能避免向下倾斜:
public static class MessageProcessor
{
private static class MessageHandlerHolder<TMessage>
{
public static IMessageHandler<TMessage> Handler;
}
public static void AddHandler<TMessage>(IMessageHandler<TMessage> handler)
{
MessageHandlerHolder<TMessage>.Handler = handler;
}
public static void Handle<TMessage>(TMessage message)
{
MessageHandlerHolder<TMessage>.Handler.Handle(message);
}
}
答案 3 :(得分:0)
不基于您展示的内容。 IMessageHandler<byte[]>
和IMessageHandler<string>
是不同的类型,并且没有基本类型(object
除外)用于“常见”列表类型。
一些选项:
Dictionary<Type, object>
- 问题是,您必须使用反射或转换值。object
数组 - 您需要进行投射,但即使您可以存储List<IMessageHandler<>>
Dictionary<Type, dynamic>
- 您无需投射,但任何错误都不会在运行时显示。您可能仍需要反射来确定要调用哪个处理程序。如果你只支持一小组处理程序(你只提两个),那么使用泛型方法和if
语句将调用分派给正确的处理程序可能更干净(也更安全):
public void Handle<T>(T input)
{
if (typeof(T) == typeof(string))
{
stringHandler.Handle(input);
}
else if (typeof(T) == typeof(byte[]))
{
byteArrayHandler.Handle(input);
}
else
{
throw new ApplicationException(string.Format("Unsupported type: {0}",typeof(T));
}
}
答案 4 :(得分:0)
根据更全面的要求,另一个选择可能是让您的IMessageHandler
公开Type
作为财产......
public interface IMessageHandler
{
Type Handles {get;}
...
}
然后在派生类中看起来像......
public class StringHandler : IMessageHandler
{
public Type Handles { get { return typeof(string); } }
...
}
然后你的MessageProcessor
看起来像......
public class MessageProcessor
{
private IDictionary<Type, IMessageHandler> _messageHandlers =
new Dictionary<Type, IMessageHandler>();
public void AddHandler<TMessage>(IMessageHandler handler)
{
//omitted error checking etc for brevity
_messageHandlers.Add(handler.Handles, handler);
}
public void Handle<TMessage>(TMessage message)
{
//omitted error checking etc for brevity
var handler = _messageHandlers[typeof(TMessage)];
}
}