转换泛型类型

时间:2018-05-19 09:31:05

标签: c# generics casting type-conversion

我有两个实现一个接口的泛型类。

public interface Interface1
{
    //implementation
}
public interface Interface2<T>
{
    //implementation
}
class Class1<T>: Interface2<T> where T : Interface1
{
    //implementation
}
class Class2<T>: Interface2<T>
{
    //implementation
}

我想编写一个返回其中一个类的对象的方法,具体取决于类型T.

 Interface2<T> GetObject<T>()
{
    if (typeof(Interface1).IsAssignableFrom(typeof(T)))
    {
        //error
        return new Class1<T>();
    }
    return new Class2<T>();
}

Class1的实现必须限于实现接口的类型。有没有办法将类型T转换为Interface1?现在我收到了错误:类型&#39; T&#39;不能用作类型参数&#39; T&#39;通用类型或方法&#39; Class1&#39;。没有拳击转换或类型参数转换来自&#39; T&#39;到&#39; Test.Interface1&#39;。

1 个答案:

答案 0 :(得分:1)

完全反思是:

return (Interface2<T>)Activator.CreateInstance(typeof(Class1<>).MakeGenericType(typeof(T)));

但它很慢(与执行new Foo()相比较慢)...我找不到任何其他方式。请注意,您已经部分处于反射方向(IsAssignableFrom

嗯使用静态类的“缓存”,我们可以作弊......我们可以在运行时生成创建new Class1<T>并缓存它所需的确切代码。

第一版

static class Maker<T>
{
    public static Func<Interface2<T>> Func { get; private set; }

    public static Interface2<T> New()
    {
        if (Func == null)
        {
            Func = Expression.Lambda<Func<Interface2<T>>>(Expression.New(typeof(Class1<>).MakeGenericType(typeof(T)))).Compile();
        }

        return Func();
    }
}

我使用表达式new Class1<T>的表达式树。然后:

static Interface2<T> GetObject<T>()
{
    if (typeof(Interface1).IsAssignableFrom(typeof(T)))
    {
        return Maker<T>.New();
    }
    return new Class2<T>();
}

但我们仍然可以做更多事情。给定T类型,可以预先计算和缓存ifGetObject()的结果。我们在表达式树中移动整个GetObject()

static class Maker2<T>
{
    public static Func<Interface2<T>> Func { get; private set; }

    public static Interface2<T> New()
    {
        if (Func == null)
        {
            if (typeof(Interface1).IsAssignableFrom(typeof(T)))
            {
                Func = Expression.Lambda<Func<Interface2<T>>>(Expression.New(typeof(Class1<>).MakeGenericType(typeof(T)))).Compile();
            }
            else
            {
                Func = Expression.Lambda<Func<Interface2<T>>>(Expression.New(typeof(Class2<>).MakeGenericType(typeof(T)))).Compile();
            }
        }

        return Func();
    }
}

然后

static Interface2<T> GetObject2<T>()
{
    return Maker2<T>.New();
}

使用表达式树的解决方案在第一次用于每个类型T时非常慢,因为它必须生成表达式树并对其进行编译,但随后它变得非常快。这与使用每次缓慢的Activator.CreateInstance的版本相比: - )