Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning generic without knowing type

I have a situation where I have a class that accepts an instance of a certain object type in its generic type parameter. The layout is something like this:

public abstract BaseClass { ... }
public DiamondClass : BaseClass { ... }
public SilverClass : BaseClass { ... }

public Handler<T> where T : BaseClass { ... }

I want to be able to create a method to return an instance of Handler<DiamondClass> or Handler<BaseClass> without defining the type upon input. I've tried something along these lines:

public Handler<BaseClass> GetHandler(HandlerType type)
{
    switch(type)
    {
        case HandlerType.Diamond: return new Handler<DiamondClass>();
        case HandlerType.Silver: return new Handler<SilverClass>();
        default: throw new InvalidOperationException("...");
    }
}

But this won't work, because apparently Handler<DiamondClass> won't cast implicitly to Handler<BaseClass>. I can specify it like this:

public Handler<T> GetHandler<T>(HandlerType type) where T : BaseClass
{
    switch(type)
    {
        case HandlerType.Diamond: return (Handler<T>)new Handler<DiamondClass>();
        case HandlerType.Silver: return (Handler<T>)new Handler<SilverClass>();
        default: throw new InvalidOperationException("...");
    }
}

But now I need to call GetHandler<DiamondClass> or GetHandler<BaseClass>. And that defeats the purpose of having a method that returns the proper handler based on an enum, without knowing the type. I hoped that I could define a Type object and pass it, as such:

 Type objType = typeof(DiamondClass);
 var handler = Handler<objType>();

But apparently C# won't allow that kind of foolishness. I've gone about this several different ways, and I'd like to think there's a way to do it, but I'm stumped.


(I actually did get this working by returning a dynamic object, but I'd like to avoid it if at all possible, as it loses any type safety and Intellisense support.)

like image 364
KChaloux Avatar asked Sep 27 '12 15:09

KChaloux


People also ask

How do you identify a generic type?

To examine a generic type and its type parametersGet an instance of Type that represents the generic type. In the following code, the type is obtained using the C# typeof operator ( GetType in Visual Basic, typeid in Visual C++). See the Type class topic for other ways to get a Type object.

Is it possible to inherit from a generic type?

An attribute cannot inherit from a generic class, nor can a generic class inherit from an attribute.

Can a non-generic class have a generic method?

Yes, you can define a generic method in a non-generic class in Java.

How do I return a generic null?

So, to return a null or default value from a generic method we can make use default(). default(T) will return the default object of the type which is provided.


1 Answers

This is where co-variance comes into play, covariance and contra-variance just work only on interface and delegate, so, to solve your problem, just define a new interface IHandler as co-variant with out which specifies that the type parameter is co-variant:

public interface IHandler<out T> where T : BaseClass 
{
}

An interface that has a covariant type parameter enables its methods to return more derived types than those specified by the type parameter

It will work. More information is here

like image 51
cuongle Avatar answered Nov 15 '22 22:11

cuongle