`System.Type`如何成为带约束的通用参数?

时间:2014-09-16 22:33:34

标签: c# generics types interface constraints

System.Type如何成为带约束的通用参数?

此处界面I有一个方法M,其中CD类实现。

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中所述。我的接口尝试的任何替代方案也是受欢迎的。

3 个答案:

答案 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子句中多余的whereT是一个类型,因为它是一个通用参数 - 但AB类型的对象不能转换为Type类 - 这是where T : Type意味着什么。

通常,where T: X, Y, Z表示任何T必须(取决于XYZ)实现接口,或者是XYZ的子类。 new()约束略有不同,使编译器意识到您还希望能够在方法中创建类型为T的新对象。 (有关详细信息,请参阅http://msdn.microsoft.com/en-gb/library/bb384067.aspxhttp://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的类型。