如果仅在运行时知道类型,如何调用具有限制的泛型

时间:2012-02-10 10:54:03

标签: c# generics casting

我想有一个类来处理来自下拉列表的数据列表,该类可以采用任何类型,因为我希望外部代码看起来像:

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

大于

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

以下是示例代码

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
{

}

在编译时,编译器不知道T是一个类,但我知道它会在运行时。我可以用反思来称呼它:

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

但是,我无法在调用方法时将结果强制转换回(IProvideList),因为T必须是referenceType

有没有办法解决这个问题?

3 个答案:

答案 0 :(得分:1)

您可以使用Bar代替Bar<T>,而这一切都自然而然地落在:

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
    }
}

答案 1 :(得分:1)

你必须在栏中使用where T : class吗?如果不试试这个。

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
{

}

答案 2 :(得分:0)

我最终设法通过反思来解决这个问题:

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

然后不尝试转换结果,而是通过反射访问结果所需的所有方法和函数:

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

不完全是我所知道的最好的代码,但它实现了我想要的结果。