Gunner
Gunner

Reputation: 917

How to call a generic with restrictions when type is known only at runtime

I would like to have a class that handles population of lists of data from a drop down that can take any type as I would rather have the external code looking like:

listProvider.For<AnEnumType>().And<AClass>.GetLists();

than

listProvider.ForEnum<AnEnumType>().ForClass<AClass>.GetLists();

Here is the example code

public class Foo
{
    public void DoSomething<T>
    {
        if(typeof(T).IsEnum)
        {
           //Do Something
        } else if (typeof(T).IsClass)
        {
           var bar = new Bar();

           //Problem How to call bar as type T must be a reference type?
           bar.GetData<T>()
        }     
    }
}

public class Bar
{
    public IProvideList<T> GetData() where T : class
    {
        //Do Something
    }
}

public interface IProvideList<T> T : class
{

}

At compile time the complier doesn't know that T is a class, but I know it will at runtime. I can call this with reflection:

bar.GetType().GetMethod("GetData").MakeGenericMethod(typeof(T));

however, I can't cast the result back to (IProvideList) when invoking the method because T must be a referenceType

Is there any way to get around this?

Upvotes: 2

Views: 133

Answers (3)

Gunner
Gunner

Reputation: 917

I eventually managed to get around this by doing reflection:

bar.GetType().GetMethod("GetData").MakeGenericMethod(typeof(T));

Then not attempting to cast the result, but accessing all methods and functions I required for the result via reflection to so:

var listProviderType = typeof (IProvideList<>).MakeGenericType(typeof (T));                    
var result = istProviderImplType.GetMethod("MethodINeedToCall").Invoke(listProviderImpl, null);   

Not exactly the nicest code I know but it achieves the result I want.

Upvotes: 0

&#214;zg&#252;r Kara
&#214;zg&#252;r Kara

Reputation: 1333

do you have to use where T : class in bar? if not try this.

public class Foo
{
    public void DoSomething<T>()
    {
        if(typeof(T).IsEnum)
        {
           //Do Something
        } else if (typeof(T).IsClass)
        {
           var bar = new Bar();

           //Problem How to call bar as type T must be a reference type?
            bar.GetData<T>();
        }     
    }
}

public class Bar
{
    public IProvideList<T> GetData<T>() //where T : class
    {
        //Do Something
    }
}

public interface IProvideList<T> //where T : class
{

}

Upvotes: 1

Alexey Raga
Alexey Raga

Reputation: 7525

Instead of just Bar you can use Bar<T> and it all falls naturally to:

public void DoSomething<T>
{
    if(typeof(T).IsEnum)
    {
       //Do Something
    } 
    else if (typeof(T).IsClass)
    {
       //Here you know T
       var bar = new Bar<T>();
       bar.GetData()
    }     
}

....
public class Bar<T>
{
    public IProvideList<T> GetData<T>() where T : class
    {
        //Do Something
    }
}

Upvotes: 1

Related Questions