“System.Type”怎么可能是带约束的泛型参数

本文关键字:约束 泛型 参数 System Type 怎么可能 | 更新日期: 2023-09-27 18:22:11

System.Type如何成为具有约束的泛型参数?

这里接口I具有类CD实现的单个方法M

public interface I {
    void M;
}
public class C: I {
    public void M();
}
public class D: I {
    public void M();
}

服务实例化一个新的T()(实际上是实现IC/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所述。我的界面尝试的任何替代方案也是受欢迎的。

“System.Type”怎么可能是带约束的泛型参数

以下代码适用于我:

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子句中多余的TypeT无论如何都是一个类型,因为它是一个泛型参数,但类型为AB的对象不能转换为Type类,这就是where T : Type的意思。

通常,where T: X, Y, Z意味着任何T必须(取决于XYZ是什么)实现接口,或者是XYZ的子类。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的类型设置编译时约束。