Reputation: 1387
I have trivial generic enum
parse method:
public static T Parse<T>(string value) => (T)Parse(typeof(T), value, false);
and usage is:
public IEnumerable<DocumentTypesEnum> FileTypeEnums =>
FileTypes.Split(',').Select(Extensions.StringEnumerator.Parse<DocumentTypesEnum>);
Above compiles fine.
Adding optional parameter to Parse<T>
:
public static T Parse<T>(string value, bool ignoreCase = false) =>
(T)Parse(typeof(T), value, ignoreCase);
Now compiler is not happy!
It works just fine, supplying argument/type explicitly (that's what error message saying anyway :) ):
public IEnumerable<DocumentTypesEnum> FileTypeEnums =>
FileTypes.Split(',').Select(f => Extensions.StringEnumerator.Parse<DocumentTypesEnum>(f));
But I am curious why compiler is complaining just by adding optional parameter to func selector?
Note: Closest discussion I can find is Unable to infer generic type with optional parameters, But its more of named arguments issue than optional arguments as John Skeet stated.
Upvotes: 3
Views: 291
Reputation: 2453
This is because even though you have the optional parameter, compiler resolution doesn't care - parameter signature has to match on the invocation of your Select()
.
Select's input parameter is more or less Func<TInput, TOutput>
with TInput
being string
and TOutput
being DocumentTypesEnum
. In this case, there's no room for another parameter.
When you do your explicit call, you actually create a new delegate
with an acceptable signature, which then calls your "non acceptable" signature with the hidden/optional parameter.
Upvotes: 4
Reputation: 101700
Malachi's answer explains why this is happening.
If you want a way to address it cleanly, the answer is to just have two Parse
methods - one with two parameters, and one with one, and have the latter call the former.
public static T Parse<T>(string value, bool ignoreCase)
=> (T)Parse(typeof(T), value, ignoreCase);
public static T Parse<T>(string value) => Parse<T>(value, false);
Upvotes: 4
Reputation: 1500903
Let's simplify this to remove type inference and overload resolution from the picture. What you want is a method group conversion that takes optional parameters into account - and that just isn't part of the C# language rules.
Here's a simpler concrete example:
using System;
class Program
{
static void Foo(int x = 1)
{
Console.WriteLine(x);
}
static void Main()
{
Action action = Foo; // Error
action();
}
}
That fails to compile, because there's no parameterless Foo
method (with a void
return type).
The language spec could have been written so that the compiler would generate a method that just called Foo
with the optional parameter, and then create a delegate referring to that new method, but it isn't written that way. I believe that at the moment, when you create a delegate from a method group conversion, the invocation list of that delegate is always the corresponding method itself, never a sort of "proxy" method.
The relevant part of the C# 5 ECMA standard is section 11.8, which contains:
The candidate methods considered are only those methods that are applicable in their normal form and do not omit any optional parameters (§12.6.4.2). Thus, candidate methods are ignored if they are applicable only in their expanded form, or if one or more of their optional parameters do not have a corresponding parameter in D.
Upvotes: 2