Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mapping between T --> IHandler<T>

I have the following interface

public interface IHandler<T>
{
    void Handle(T myObject);
}

I'd like to have a HandlersManager class with holds a mapping between object types to their corresponding handler, but I'm not sure how I'm supposed to define the object that hold this mapping.

For example, what I'd like to have is this:

typeof(string)  --> instance of IHandler<string>
typeof(MyClass) --> instance of IHandler<MyClass>

The best thing I got so far was to define Dictionary<Type, object> for the mapping, but in this case I would have to cast the value to IHandler<T> every time I get it.

Is there a better solution or something that I have completely missed?

like image 395
Adi Lester Avatar asked Apr 03 '12 11:04

Adi Lester


2 Answers

I suspect you're using this to resolve dependencies. Instead, use a dedicated container that will handle these issues for you.

If you don't want to do that, you want something like this:

Dictionary<Type, object> dictionary;

IHandler<T> Resolve<T>() {
    return (IHandler<T>)dictionary[typeof(T)];
}

There isn't any other way with generics.

Is there a better solution or something that I have completely missed?

No, but manager classes are generally code smells. Be careful.

like image 87
jason Avatar answered Oct 16 '22 01:10

jason


That's as good as it can get with only a generic IHandler<T> interface.

In order to explore more options, we could define a non-generic version of the interface:

public interface IHandler
{
    void Handler(object myObject);
}

Then you could also define a generic abstract base class that implements both IHandler<T> and IHandler:

public abstract class BaseHandler<T> : IHandler, IHandler<T>
{
    public abstract void Handle(T myObject);

    void IHandler.Handle(object myObject)
    {
        ((IHandler<T>)this).Handle((T) myObject);
    }
}

At this point you can have an IDictionary<Type, IHandler> and you can directly call IHandler.Handle on the values you pull out of it:

var obj = /* whatever */
dictionary[obj.GetType()].Handle(obj);

On the other hand we now have an additional interface and an abstract base class just to hide a cast from "user" code, which doesn't sound very impressive.

like image 39
Jon Avatar answered Oct 16 '22 03:10

Jon