func上的C#可选参数丢失泛型类型推断

时间:2018-06-01 05:47:26

标签: c# .net generics ienumerable func

我有简单的通用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);

现在编译器不开心!

enter image description here

它工作得很好,明确地提供参数/类型(这是错误消息说的:)但是:

public IEnumerable<DocumentTypesEnum> FileTypeEnums => 
            FileTypes.Split(',').Select(f => Extensions.StringEnumerator.Parse<DocumentTypesEnum>(f));

但我很好奇为什么编译器只是通过向func选择器添加可选参数来抱怨?

注意:我能找到的最近的讨论是Unable to infer generic type with optional parameters,但它的命名参数问题比 John Skeet 的可选参数更多>陈述。

3 个答案:

答案 0 :(得分:4)

这是因为即使您有可选参数,编译器解析也不关心 - 参数签名必须与Select()的调用匹配。

选择的输入参数或多或少Func<TInput, TOutput>TInputstringTOutputDocumentTypesEnum。在这种情况下,没有其他参数的空间。

当您进行显式调用时,实际上是创建了一个具有可接受签名的新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 中没有相应参数,则会忽略候选方法。