开发者

Strongly typed way of storing type references

I need to store a collection of types.

All types implement the same interface IHandler<T>, where T is a parameter of the parent class.

At runtime, I enumerate the list of handlers and process a message. Each handler is created by a builder (just uses StructureMap internally). The builder exposes a method like:

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

}

Of course, I only have a Type so can't use the above.

I've got round this by also passing the underlying interface as the generic parameter and the concrete type as a parameter:

DoSomething<IHandler<T>>(handlerType, h =>
                            {
                                h.Handle(message);
                            });

Then inside DoSomething I can get an instance of handlerType but cast it as IHandler<T>.

Just wondered if there was a better/cleaner way.

Update

In response to some of the comments.

The collection is an ICollection<Type>, not instances. The message handlers are created on demand, on different threads, for each batch of messages, so creating the handlers in advance, or using Lazy<T>, was not an option.

Essentially I am trying to abstract away some direct references to StructureMap. Specifically, DoSomething<T> actually creates the handler using a nested container, before executing the action (it's Handle method).

Update 2 (solution)

I realized that I could handle (no pun intended) this better by storing a collection of Action<T> and creating the handlers using a factory. Here's a simple example:

public class SimpleProcessor<T> where T : IMessage
{
    ICollection<Action<T>> ha开发者_运维知识库ndlers;
    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);
        }
    }
}

Usage:

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

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

simpleProcessor.Process();

I'm more or less happy with this solution.


If you're willing to change Action<T> into Action<dynamic>, then you can do something like this:

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);
  }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜