我有Class1和通用T1,Class2有通用T2。通用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 {
}
编辑:不幸的是,由于开销,反射不是一个好的解决方案,因此会被调用很多。
答案 0 :(得分:4)
正如@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
方法创建100万个GetObj()
个实例需要多长时间:
Class1
,只需返回new Class2<T1>()
): 4毫秒 正如您所看到的,新解决方案明显快于前一个解决方案。但是,如果您为T1
使用了许多不同的类型,则性能提升会更小甚至不存在。
答案 1 :(得分:0)
如果我理解正确,T1和T2都继承自SomeBaseClass? 如果是,则应将Class1声明为
public class Class1<T1> where T1: SomeBaseClass
答案 2 :(得分:0)
根据要求,您可以使用两种不同的通用方法,其中一种约束:
public static object GetObj<T>() where T : SomeBaseClass => new Class2<T>();
public static object GetObjOther<T>() => <whatever you want as else>;
没有静态类型的方法来实现它,方法与类型系统在编译时需要知道的方法相同;如果您必须按照描述使用if语句,则唯一的另一种方式是fknx
的答案中建议的反映。
如果您添加特定类型的参数,则越接近您的要求:
public static object GetObj<T>(T obj) where T : SomeBaseClass => new Class2<T>();
public static object GetObj<T>(Class2<T> objc) where T : SomeBaseClass => <whatever you want as else>;
当然,如果不了解背景,这确实令人困惑,可能是错误的。