Given the following class:
public static class EnumHelper
{
//Overload 1
public static List<string> GetStrings<TEnum>(TEnum value)
{
return EnumHelper<TEnum>.GetStrings(value);
}
//Overload 2
public static List<string> GetStrings<TEnum>(IEnumerable<TEnum> value)
{
return EnumHelper<TEnum>.GetStrings(value);
}
}
What rules are applied to select one of its two generic methods? For example, in the following code:
List<MyEnum> list;
EnumHelper.GetStrings(list);
it ends up calling EnumHelper.GetStrings<List<MyEnum>>(List<MyEnum>)
(i.e. Overload 1), even though it seems just as valid to call EnumHelper.GetStrings<MyEnum>(IEnumerable<MyEnum>)
(i.e. Overload 2).
For example, if I remove overload 1 entirely, then the call still compiles fine, instead choosing the method marked as overload 2. This seems to make generic type inference kind of dangerous, as it was calling a method which intuitively seems like a worse match. I'm passing a List/Enumerable as the type, which seems very specific and seems like it should match a method with a similar parameter (IEnumerable<TEnum>)
, but it's choosing the method with the more generic, generic parameter (TEnum value)
.
Overload 2
be valid for your example?TEnum
would beList<MyEnum>
so the argument isIEnumerable<List<MyEnum>> value
- isnt it ovious that he would prefer the method withList<MyEnum> value
as argument? – DrydenTEnum
would be inferred asMyEnum
for the second overload. Why would it be inferred asList<MyEnum>
? – HinmanList<Foo<string>> list; EnumHelper.GetStrings(list);
would you know expect that c# will call the method withIEnumerable<string> value
just becauseFoo
is declared asFoo<string>
? - no it will beIEnumerable<List<Foo<string>> value
– DrydenTEnum
inferred to beMyEnum
, becauseList<MyEnum>
implementsIEnumerable<MyEnum>
. That's just type inference, and can be shown by the call working if you remove overload 1. – HinmanGetStrings<TEnum>
-<TEnum>
will be the type you are calling the method - what you are saying is true if you remove the generic declaration and just havepublic static List<string> GetStrings(IEnumerable value)
than justList<MyEnum>
inheritsIEnumerable
and it will be called – DrydenTEnum
really is inferred asMyEnum
in a call to the second method with an argument of typeList<MyEnum>
. If you don't believe the second method is applicable at all, please try it. Just take the code in the question, remove the first overload, and try calling it with aList<Foo>
whereFoo
is an enum. AddConsole.WriteLine(typeof(TEnum));
into the body of the method - you'll see it printFoo
. – HinmanEnumHelper.GetStrings<MyEnum>(list);
instead ofEnumHelper.GetStrings(list);
. – IndeterminateTEnum
is inferred asList<MyEnum>
for the first method, but it's inferred asMyEnum
for the second method. After type inference, overload resolution is used to pick which method is actually called. But that doesn't change the fact that while it's considering the second method, it infersTEnum
to beMyEnum
. It's worth separating out the two phases in your mind. (I've edited my answer to make that slightly clearer.) – HinmanGetStrings(TEnum)
will break apart the individual flags composing the enum and return their string equivalents fromEnumMember
attributes. So it really should be called something likeGetStringsForFlagsEnum
. Meanwhile,GetStrings(IEnumerable<TEnum>>)
will just return the one-to-one mappings for each enum, and will actually throw an error if a flags value is passed, because there's no mapping for composite values. – Trefoil