System.Type
如何成为带约束的通用参数?
此处界面I
有一个方法M
,其中C
和D
类实现。
public interface I {
void M;
}
public class C: I {
public void M();
}
public class D: I {
public void M();
}
Service实例化一个新的T()(真正C
/ D
实现I
)并在其上运行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
中所述。我的接口尝试的任何替代方案也是受欢迎的。
答案 0 :(得分:3)
以下代码适用于我:
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>();
}
问题是Type
子句中多余的where
。 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()
,因为当您使用泛型时,该类型可以直接在函数中引用(参见上文)。希望有道理。有问题,请问!
答案 1 :(得分:2)
此示例可帮助您了解此处发生的事情:
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"
}
答案 2 :(得分:1)
似乎&#34;正确&#34;实现将是摆脱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
的类型。