简体   繁体   中英

How can a `System.Type` be a generic parameter with constraints?

How can a System.Type be a generic parameter with constraints?

Here interface I has a single method M which classes C and D implement.

public interface I {
    void M;
}

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

Service instantiates a new T() (which is really C / D implementing I ) and runs I interface methods on it

public class Service {
    public void Fn<T>(T t): where T : Type, I, new() {
        ( new t() ).M();
        // ...
    }
}

This will eventually be the public API for the service so I want it to be as concise as possible:

public class Main {
    public void main() {
        Service.Fn( typeof( C ));
        Service.Fn( typeof( D ));
        // ...
    }
}

This isn't compiling and the error is: '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 ...

The ultimate goal here is to be able to call Service.Fn concisely, as described in Main . Any alternatives to my interfaces attempt are also welcome.

The following code works for me:

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>();
}

The issue was the superfluous Type in the where clause. T is a Type anyway by the fact it is a generic parameter - but an object of type A or B wouldn't be castable to the Type class - this is what where T : Type would mean.

In general, where T: X, Y, Z means that any T must (depending on what X , Y and Z are) either implement the interface, or be a subclass of, X , Y and Z . The new() constraint is slightly different, and makes the compiler aware that you also wish to be able to create a new object of type T in the method. (see http://msdn.microsoft.com/en-gb/library/bb384067.aspx and http://msdn.microsoft.com/en-gb/library/d5x73970.aspx for more details)

Also, I've removed typeOf() from your input, as when you're using a generic the type can be referenced directly in the function (see above). Hope that makes sense. Any questions, just ask!

This example may help you understand what's going on here:

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"
}

Seems like the "proper" implementation would be to get rid of the Type constraint:

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>();
        // ...
    }
}

If you really, really want to pass in a type, then you'll have to use reflection instead of generics:

public class Service {
    public void Fn<T>(Type t) {
        I i = Activator.CreateInstance(t) as I;
        if(i != null)
            i.M();
        // ...
    }
}

The problem is you can't put a compile-time constraint that t is a type that also implements I .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM