简体   繁体   中英

Extension methods on enumerable-derived classes cannot infer type arguments

We are currently working with generics on extensions for enumerable-derived classes. Apparently, the compiler produces an error CS0411 with extension methods if they are called on a class derived from IEnumerable<T> and return values that are of the enclosed T type.

The following example reproduces the error:

public class Item { }

public class CollectionType : IEnumerable<Item>
{
    public IEnumerator<Item> GetEnumerator()
    {
        throw new NotImplementedException();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }
}

public static class CollectionExtension
{
    public static T[] DoSomething<T, TCollection>(this TCollection source)
        where TCollection : IEnumerable<T>
    {
        throw new NotImplementedException();
    }
}

public class Test
{
    public void TestMethod()
    {
        var collection = new CollectionType();

        collection.DoSomething();

        collection.DoSomething<Item, CollectionType>(); // This works fine
    }
}

Calling DoSomething() will produce the following error:

The type arguments for method 'T[] [...].CollectionExtension.DoSomething<T,TCollection>(this TCollection)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

How can this happen if TCollection is bound to be of type IEnumerable<T> and T is also defined as a generic type parameter of DoSomething() ?

Calling the extension method on the CollectionType should provide DoSomething() with both generic types.

It would not be possible to use the DoSomething() method as-is without specifying the generic types explicitly. The class IEnumerable<T> from which it seemingly would be possible to infer the type of T is located in the type constraint declaration, unfortunately C# "...cannot infer the type parameters only from a constraint or return value" . See the details here:

[https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/generic-methods]

This is issue can be solved in a different ways, you could explicitly specify the type as you have done in the example code - collection.DoSomething<Item, CollectionType>() , or add to DoSomething() an argument of type T , in that case C# will be able to infer the type, or get rid of the generic type TCollection, replacing it with IEnumerable<T> in the following way:

public static T[] DoSomething<T>(this IEnumerable<T> source)
{
    throw new NotImplementedException();
}

The last one I think would be a cleaner way.

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