简体   繁体   中英

Constraint return type of static method to current class type

I have a class hierarchy and a static method in the base class, so subclasses have this static method too. I would love to define a static method like

public static IEnumerable<T> GetList<T>()
    where T : BaseClass, new()
{
    return new List<T>() { ... };
}

so I would be able to call

var list = ChildClass.GetList();

and list would be IEnumerable<ChildClass> . But: I don't know how to tell the compiler to infer generic type to be type of the class I call from, so this usage yields an error and I have to correct it to somehow redundant

var list = ChildClass.GetList<ChildClass>();

I could use extension methods (they have this argument that allows compiler to catch on), but I want do this without instantiation of ChildClass .

Is there a way to accomplish this without repetition?

You can't make the compiler infer the class you call from because technically you always call from the class the method is defined in.

The compiler allowing you to use a derived class name instead is simply a convenience.

If you can live with an ugly hack, you can make BaseClass itself generic, and pass the child class' type as argument to the generic parameter, like:

class BaseClass<T> where T : BaseClass<T>, new()
{
    public static IEnumerable<T> GetList()
    {
        return new List<T>() { new T() }; // whatever
    }
}

class Child : BaseClass<Child>
{

}

class Child2 : BaseClass<Child2>
{

}

Now Child.GetList() returns an IEnumerable<Child> and Child2.GetList() returns an IEnumerable<Child2> .

If you want to know why the compiler cannot resolve the type, read on:

Firstly static methods are bound to types not objects. So there can not be any polymorphic behaviour here. So the fact that you have a child, baseclass hierarchy is not really important here as the methods are bound to two completely different entities.

The real issue is in the type inference capabilities of the C# compiler. You have to give the compiler some information on what the type T is. Otherwise it cannot infer it.

You cannot give this information on the left hand side either as the C# type inference works from right to left. In other words:

var ints = new {};

Is perfectly fine. Because the type on the right is an anonymous method and ints is resolved to one. But:

int[] ints = new [] {};

Wouldn't work. The compiler complains that "no best type was found for the implicitly-typed array". In other words the compiler cannot use the information on the left hand side to figure out what the type should be on the right hand side.

In you question

var list = ChildClass.GetList();

Does not give the compiler any information on what T is ! Even if you had the type instead of var that would have not made a difference.

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