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

时间:2011-07-20 15:50:52

标签: c# generics

我需要存储一系列类型。

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

我对此解决方案或多或少感到满意。

1 个答案:

答案 0 :(得分: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);
  }
}