是否可以将一个开放的泛型类型的列表保存在一个地方?

Pet*_*ter 4 c# generics open-generics

我试图有一个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.
    }
}
Run Code Online (Sandbox Code Playgroud)

IMessageHandler 应该有一个强类型方法:

public void Handle(TMessage message) {}
Run Code Online (Sandbox Code Playgroud)

我的实际示例有些复杂,所以我希望在这里正确地简化了它。

事实是,我对每个处理程序的泛型类型不感兴趣。我只需要他们都在一个地方,我可以很容易地找到正确的处理程序,如果我可以在一个地方得到他们。

专用词典将以消息的类型(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} );
Run Code Online (Sandbox Code Playgroud)

并有MessageProcessor正确的电话MessageHandler

小智 6

每个人都知道扩展方法。但是“扩展字段”呢?当然,不可能用一些新字段来扩展某些对象,但是...您看到过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);
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,所有内容都是强类型和静态类型的,客户端无需显式删除处理程序即可避免内存泄漏。