我有简单的通用enum
解析方法:
public static T Parse<T>(string value) => (T)Parse(typeof(T), value, false);
用法是:
public IEnumerable<DocumentTypesEnum> FileTypeEnums =>
FileTypes.Split(',').Select(Extensions.StringEnumerator.Parse<DocumentTypesEnum>);
以上编译正常。
将可选参数添加到Parse<T>
:
public static T Parse<T>(string value, bool ignoreCase = false) =>
(T)Parse(typeof(T), value, ignoreCase);
现在编译器不开心!
它工作得很好,明确地提供参数/类型(这是错误消息说的:)但是:
public IEnumerable<DocumentTypesEnum> FileTypeEnums =>
FileTypes.Split(',').Select(f => Extensions.StringEnumerator.Parse<DocumentTypesEnum>(f));
但我很好奇为什么编译器只是通过向func选择器添加可选参数来抱怨?
注意:我能找到的最近的讨论是Unable to infer generic type with optional parameters,但它的命名参数问题比 John Skeet 的可选参数更多>陈述。
答案 0 :(得分:4)
这是因为即使您有可选参数,编译器解析也不关心 - 参数签名必须与Select()
的调用匹配。
选择的输入参数或多或少Func<TInput, TOutput>
,TInput
为string
,TOutput
为DocumentTypesEnum
。在这种情况下,没有其他参数的空间。
当您进行显式调用时,实际上是创建了一个具有可接受签名的新delegate
,然后使用hidden / optional参数调用“不可接受”签名。
答案 1 :(得分:4)
玛拉基的答案解释了为什么会这样。
如果你想要一种方法来干净地解决它,答案是只有两个Parse
方法 - 一个有两个参数,一个有一个,后者叫前者。
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);
答案 2 :(得分:2)
让我们简化一下,从图片中删除类型推断和重载决策。你想要的是一个方法组转换,它将可选参数考虑在内 - 而且它不是C#语言规则的一部分。
这是一个更简单的具体例子:
using System;
class Program
{
static void Foo(int x = 1)
{
Console.WriteLine(x);
}
static void Main()
{
Action action = Foo; // Error
action();
}
}
无法编译,因为没有无参数Foo
方法(void
返回类型)。
语言规范可以编写,以便编译器生成一个只用可选参数调用Foo
的方法,然后创建一个引用该新方法的委托,但是它不是那样写的。我相信,目前,当您从方法组转换创建委托时,该委托的调用列表始终是相应的方法本身,而不是一种“代理”方法。
C#5 ECMA标准的相关部分是第11.8节,其中包含:
所考虑的候选方法只是那些适用于其正常形式的方法,并且不会省略任何可选参数(第12.6.4.2节)。因此,如果候选方法仅适用于其扩展形式,或者如果其中一个或多个可选参数在D 中没有相应参数,则会忽略候选方法。