存储类型引用的强类型方式

本文关键字:强类型 方式 引用 类型 存储 | 更新日期: 2023-09-27 18:02:48

我需要存储一个类型集合。

所有类型实现相同的接口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();

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

存储类型引用的强类型方式

如果您愿意将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);
  }
}