强类型方式存储类型引用

3

我需要存储一组类型。

所有的类型都实现了相同的接口IHandler<T>,其中T是父类的一个参数。

在运行时,我会枚举处理程序列表并处理消息。每个处理程序都是由一个构建器创建的(仅在内部使用StructureMap)。该构建器公开了一个类似于以下方法的方法:

static void DoSomething<T>(Action<T> action)
{

}

当然,我只有一个Type,所以不能使用上述方法。
我通过将底层接口作为泛型参数和具体类型作为参数来解决这个问题:
DoSomething<IHandler<T>>(handlerType, h =>
                            {
                                h.Handle(message);
                            });

DoSomething方法内,我可以获取一个handlerType的实例,但需要将其强制转换为IHandler<T>

不知道是否有更好/更简洁的方法。

更新

回应一些评论。

该集合是ICollection<Type>,而不是实例。消息处理程序是按需创建的,在不同的线程上,对于每批消息都是如此,因此预先创建处理程序或使用Lazy<T>不是一个选项。

本质上,我正在尝试抽象掉一些直接引用StructureMap的部分。具体来说,DoSomething<T>实际上是在执行操作之前(它的Handle方法)使用嵌套容器创建处理程序。

更新2(解决方案)

我意识到可以通过存储Action<T>的集合并使用工厂创建处理程序来更好地处理这个问题。以下是一个简单的示例:

public class SimpleProcessor<T> where T : IMessage
{
    ICollection<Action<T>> handlers;
    T message;

    public SimpleProcessor(T message)
    {
        this.handlers = new List<Action<T>>();
        this.message = message;
    }

    public void AddHandler(Action<T> handler)
    {
        handlers.Add(handler);
    }

    public void Process()
    {           
        foreach (var handler in handlers)
        {
            handler(message);
        }
    }
}

使用方法:

var testMessage = new TestMessage { Message = "Foo" };

var simpleProcessor = new SimpleProcessor<TestMessage>(testMessage);
simpleProcessor.AddHandler(m => DoSomething<TestMessageHandler>(h => h.Handle(m)));

simpleProcessor.Process();

我对这个解决方案比较满意。


我不确定我完全理解了。所以集合包含Type对象?还是只包含实现IHandler<T>的类型的实例? - James Michael Hare
你尝试过使用两个类型参数,一个用于处理程序,另一个用于底层参数类型吗?例如DoSomething<TMessage, THandler>(),其中THandler:IHandler<TMessage>。 - sll
1
你说:“当然,我只有一个类型,所以不能使用上面的方法” - 但我根本没有看到“当然”。为什么你只有一个类型?什么情况下你只有一个类型?你并没有清楚地说明你想要实现什么。 - Jon Skeet
我已更新我的问题以提供更多信息。 - Ben Foster
1个回答

0
如果你愿意将 Action<T> 改为 Action<dynamic>,那么你可以像这样做:
class Program
{
  static void Main(string[] args)
  {
    try
    {
      var myMessage = new object();
      Action<dynamic> action = (dynamic h) => { h.Handle(myMessage); };

      Type myType = typeof(int);
      var method = typeof(Program).GetMethod("DoSomething");
      var concreteMethod = method.MakeGenericMethod(myType);
      concreteMethod.Invoke(null, new [] { action });

      Console.ReadKey();
    }
    catch (Exception ex)
    {
      Console.Error.WriteLine(ex);
      Console.ReadKey();
    }
  }

  static public void DoSomething<T>(Action<dynamic> action)
  {
    Console.WriteLine("DoSomething invoked with T = " + typeof(T).FullName);
  }
}

这是基于我对原始问题的理解;他希望DoSomething是强类型的,但使用Type调用,因此需要反射。 - Stephen Cleary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接