我有带有通用T1的Class1和带有通用T2的Class2。通用T2有约束,而T1没有约束。

现在在Class1中,我想检查T1是否与T2的约束匹配,以及是否与Class2一起使用。

这可能吗?怎么样?

public class Class1<T1> {
    public static object GetObj() {
        if (typeof(SomeBaseClass).IsAssignableFrom(typeof(T1))) {
            // I know that T1 is a subclass of SomeBaseClass, and want to create a Class2 object using it
            return new Class2<T1>();  // this doesn't work. How can I "force" the compiler to treat T1 as a T2, like casting?
        }
    }
}

public class Class2<T2> where T2 : SomeBaseClass {
}


编辑:不幸的是,由于开销,反射不是一个好的解决方案,这被称为很多。

最佳答案

正如@AakashM所说,我想使用反射是唯一的方法:

public class Class1<T1>
{
    public static object GetObj()
    {
        if (typeof(SomeBaseClass).IsAssignableFrom(typeof(T1)))
        {
            var genericType = typeof(Class2<>).MakeGenericType(typeof(T1));
            return Activator.CreateInstance(genericType);
        }

        // throw Exception or return null
    }
}


更新资料

发表您的评论后,如果反射太慢,则可以使用编译表达式:

public class Class1<T1>
{
    private static readonly Func<T1> _factory;

    static Class1()
    {
        if (!typeof(SomeBaseClass).IsAssignableFrom(typeof(T1)))
        {
            _factory = () => default(T1);
            return;
        }

        var ctor = typeof(T1).GetConstructor(Array.Empty<Type>());
        var newExpression = Expression.New(ctor);

        _factory = Expression.Lambda<Func<T1>>(newExpression).Compile();
    }

    public static object GetObj()
    {
        return _factory();
    }
}


此解决方案为Class1的每个变体(例如Class1<SomeSubClass>Class1<SomeOtherSubClass>等)创建一个工厂。构建表达式需要一些时间,但是之后确实非常快。

我已经进行了一些测试,以查看使用Class2方法创建一百万个GetObj()实例需要花费多长时间:


最佳情况(将约束添加到Class1,只需返回new Class2<T1>()):4毫秒
反射(如原始解决方案所示):991毫秒
使用已编译的表达式(如上所示):26 ms


如您所见,新解决方案比以前的解决方案快得多。但是,如果您为T1使用许多不同类型,则性能提升将变小甚至不存在。

关于c# - 泛型用作更具体的泛型,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40108632/

10-11 22:37
查看更多