C# `System.Type`怎么可能是带约束的泛型参数?

C# `System.Type`怎么可能是带约束的泛型参数?,c#,generics,types,interface,constraints,C#,Generics,Types,Interface,Constraints,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(); } 服务实例化一个新的T()(它实际上是C/D实现I)并在其上运行I接口方法 public class Service { public void Fn<

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();
}
服务实例化一个新的T()(它实际上是
C
/
D
实现
I
)并在其上运行
I
接口方法

public class Service {
    public void Fn<T>(T t): where T : Type, I, new() {
        ( new t() ).M();
        // ...
    }
}
这不是编译,错误是:
“System.Type”必须是具有公共无参数构造函数的非抽象类型,才能在泛型类型或方法中将其用作参数“T”…

这里的最终目标是能够简单地调用
Service.Fn
,如
Main
中所述。我的接口尝试的任何替代方案都是受欢迎的。

似乎“正确”的实现应该是摆脱
类型的约束:

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 void Fn():其中T:I,new(){
(新T()).M();
// ...
}
}
公共班机{
公共图书馆{
Service.Fn();
Service.Fn();
// ...
}
}
如果您真的非常想传入一个类型,那么您必须使用反射而不是泛型:

public class Service {
    public void Fn<T>(Type t) {
        I i = Activator.CreateInstance(t) as I;
        if(i != null)
            i.M();
        // ...
    }
}
公共类服务{
公共空间Fn(t型){
I=Activator.CreateInstance(t)作为I;
如果(i!=null)
i、 M();
// ...
}
}

问题是您不能设置编译时约束,即
t
也是实现
I

的类型。以下代码对我有效:

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>();
}
公共类服务{
公共无效Fn(),其中T:I,new(){
(新T()).M();
// ...
}
}
公共接口I
{
无效M();
}
公共C类:I类
{
公共空间M();
}
D班:I
{
公共空间M();
}
静态void Main()
{
var服务=新服务();
service.Fn();
service.Fn();
}
问题是
where
子句中多余的
Type
T
无论如何都是一个类型,因为它是一个泛型参数-但是
a
B
类型的对象不会被强制转换到
Type
类-这就是
中T:Type
的意思

通常,
其中T:X,Y,Z
意味着任何
T
必须(取决于
X
Y
Z
是什么)实现接口,或者是
X
Y
Z
的子类。
new()
约束略有不同,它使编译器知道您还希望能够在方法中创建类型为
T
的新对象。(有关更多详细信息,请参阅和)


此外,我还从您的输入中删除了
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"
}
void PrintTypeName(Type t){Console.WriteLine(t.Name);}
void PrintTypeName(){Console.WriteLine(typeof(T.Name);}
void Main()
{
类型cType=类型(C);
类型dType=类型(D);
C cInstance=新的C();
D dInstance=新的D();
PrintNameOfType(cType.GetType());//打印“RuntimeType”
PrintNameOfType(dType.GetType());//打印“RuntimeType”
PrintNameOfType(cInstance.GetType());//打印“C”
PrintNameOfType(dInstance.GetType());//打印“D”
PrintNameOfType(cType);//打印“C”
PrintNameOfType(dType);//打印“D”
//不编译:
//打印类型名称(cInstance);
//打印类型名称(dInstance);
PrintNameOfType();//打印“类型”
PrintNameOfType();//打印“C”
PrintNameOfType();//打印“D”
}

您是否正在尝试制作
C
/
D
?如果是这样,您应该使用一个泛型参数,例如
Service.Fn()
。C和D是类型,但它们不是从
Type
继承的。此外,除了语法之外,您似乎不了解类型对象(例如,
typeof(C)
)和类型标记(例如,
Service.Fn()
)之间的区别类型对象和类型标记之间的区别是什么?您实际上可以从类型继承,即使这不是人们真正想要做的。我将使用你的第一个版本,因为它更干净/更容易使用!如果可以的话,我只想添加一个有用的概念,帮助我了解其中的区别:
T
可以被认为是取代了任何其他类型,例如
对象
字符串
等,而
类型(T)
是将类型作为变量传递的一种方式。@Davidey感谢您的评论。我更喜欢说“将类型作为对象传递”,但这可能会让人困惑。当然,真正的问题是
Type
是一个描述类型的类,而
Customer
是一个描述客户的类。人们对
Customer
是一种类型这一事实感到困惑,尽管
Customer
“is-a”
type
(正如“is-a”一词在继承教学中使用的那样)不是真的。当然,一个相关的混淆是静态(编译时)和动态(运行时)类型之间的区别。这个例子暗示了这一点,但我不想明确地提到它。真的!(并同意,“将类型作为对象传递”更清晰)。很难解释,你的代码和上面的解释都很棒@Davidey Clear,我不知道,因为“作为一个对象”可能意味着“作为一个
对象”
,也就是说,“作为一个
系统。对象”
,这不是真正的重点。嗯,是真的!我想这只是一个相当令人困惑的问题。。。也许我们可以说“
T
是一个类型,可以用来替换代码中的另一个类型”,而“
typeof(T)
tInstance.getType()
等给出了一个对象,它表示类型
T
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"
}