“System.Type”怎么可能是带约束的泛型参数
本文关键字:约束 泛型 参数 System Type 怎么可能 | 更新日期: 2023-09-27 18:22:11
System.Type
如何成为具有约束的泛型参数?
这里接口I
具有类C
和D
实现的单个方法M
。
public interface I {
void M;
}
public class C: I {
public void M();
}
public class D: I {
public void M();
}
服务实例化一个新的T()(实际上是实现I
的C
/D
),并在其上运行I
接口方法
public class Service {
public void Fn<T>(T t): where T : Type, I, new() {
( new t() ).M();
// ...
}
}
这最终将成为服务的公共API,所以我希望它尽可能简洁:
public class Main {
public void main() {
Service.Fn( typeof( C ));
Service.Fn( typeof( D ));
// ...
}
}
这不是在编译,错误为:'System.Type' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method ...
这里的最终目标是能够简洁地调用Service.Fn
,如Main
所述。我的界面尝试的任何替代方案也是受欢迎的。
以下代码适用于我:
public class Service {
public void Fn<T>() where T : I, new() {
(new T()).M();
// ...
}
}
public interface I
{
void M();
}
public class C : I
{
public void M();
}
public class D : I
{
public void M();
}
static void Main()
{
var service = new Service();
service.Fn<C>();
service.Fn<D>();
}
问题是where
子句中多余的Type
。T
无论如何都是一个类型,因为它是一个泛型参数,但类型为A
或B
的对象不能转换为Type
类,这就是where T : Type
的意思。
通常,where T: X, Y, Z
意味着任何T
必须(取决于X
、Y
和Z
是什么)实现接口,或者是X
、Y
和Z
的子类。new()
约束略有不同,它使编译器意识到您还希望能够在方法中创建一个类型为T
的新对象。(参见http://msdn.microsoft.com/en-gb/library/bb384067.aspx和http://msdn.microsoft.com/en-gb/library/d5x73970.aspx了解更多详细信息)
此外,我已经从您的输入中删除了typeOf()
,因为当您使用泛型时,可以在函数中直接引用该类型(见上文)。希望这是有道理的。任何问题,只要问!
这个例子可以帮助您理解这里发生了什么:
void PrintTypeName(Type t) { Console.WriteLine(t.Name); }
void PrintTypeName<T>() { Console.WriteLine(typeof(T).Name); }
void Main()
{
Type cType = typeof(C);
Type dType = typeof(D);
C cInstance = new C();
D dInstance = new D();
PrintNameOfType(cType.GetType()); //prints "RuntimeType"
PrintNameOfType(dType.GetType()); //prints "RuntimeType"
PrintNameOfType(cInstance.GetType()); //prints "C"
PrintNameOfType(dInstance.GetType()); //prints "D"
PrintNameOfType(cType); //prints "C"
PrintNameOfType(dType); //prints "D"
//does not compile:
//PrintNameOfType(cInstance);
//PrintNameOfType(dInstance);
PrintNameOfType<Type>(); //prints "Type"
PrintNameOfType<C>(); //prints "C"
PrintNameOfType<D>(); //prints "D"
}
似乎"正确"的实现应该是摆脱Type
约束:
public class Service {
public void Fn<T>(): where T : I, new() {
( new T() ).M();
// ...
}
}
public class Main {
public void main() {
Service.Fn<C>();
Service.Fn<D>();
// ...
}
}
如果真的,真的想传入一个类型,那么你必须使用反射而不是泛型:
public class Service {
public void Fn<T>(Type t) {
I i = Activator.CreateInstance(t) as I;
if(i != null)
i.M();
// ...
}
}
问题是,不能对t
是一个同时实现I
的类型设置编译时约束。