Suppose I have a POCO and a List class for them:
class MyClass
{...}
class MyClasses : List<MyClass>
{...}
And the following method to map an IEnumerable<MyClass>
to a MyClasses
list:
public static TListType ToListOfType<TListType, TItemType>(this IEnumerable<TItemType> list) where TListType : IList<TItemType>, new()
{
var ret = new TListType();
foreach (var item in list)
{
ret.Add(item);
}
return ret;
}
I would expect this code to compile, but it doesn't:
var list = someListOfMyClass.ToListOfType<MyClasses>();
but instead I get
Error CS1061 'IEnumerable' does not contain a definition for 'ToListOfType' and no accessible extension method 'ToListOfType' accepting a first argument of type 'IEnumerable' could be found (are you missing a using directive or an assembly reference?)
However, this does work:
var list = someListOfMyClass.ToListOfType<MyClasses, MyClass>();
I don't understand why type inference isn't sufficient for the compiler to know what the item type is, since the this
variable is a list of a known type.
Type inference doesn't infer the missing arguments from a generic method call. Instead it either infers all or none of the arguments. So you can't call the method with one type argument and expect the compiler to come up with the rest.
In this case, it is possible to infer TItemType
, since it is in one of the arguments. TListType
can't be inferred though since it is the return type. So in the end, the method signature can't be inferred, and you have to specify all the type arguments.
As other have said, partial generic type argument inference is not supported by c#.
About why one of the types can't be inferred, maybe a more obvious example makes it clearer:
TPeeledFruit peeled = Peel<TPeeledFruit, TFruit)(
this TFruit fruit) where TPeeledFruit: TFruit
Ok, now you say:
var myPeeledBanana = Peel(myBanana)
The compiler infers easily enough that TFruit
must be Banana
.
But how is it going to ever infer what TPeeledFruit
is? It has no information whatsoever of that type; you might see it as obvious because you understand the relation but the compiler has no such knowledge. The only thing it knows is that TPeeledFruit
must be a type that inherits from TFruit
but that can be infinite amount of types: it can be Banana
again, it can be PeeledBanana
, it can be PeeledRipeBanana
, PeeledGreenBanana
, etc.
Also consider the fact that explicitly typing the assignment helps in no way whatsoever:
PeeledBanana myPeeledBanana = Peel(myBanana)
This wont work either, c# reasons types on the right hand side of an assignment first and then works out if the assignment is in fact legal. If its an implicitly typed variable then the assignment is always valid.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With