C#4.0中的命名参数和泛型类型推断

Bir*_*erH 57 c# generics type-inference compiler-errors c#-4.0

我一直在编程,假设在C#4.0中调用方法时,为参数提供名称不会影响结果,除非这样做是"跳过"一个或多个可选参数.

所以我发现以下行为有点惊讶:

给定一个获取a的方法Func<T>,执行它并返回结果:

public static T F<T>(Func<T> f)
{
    return f();
}
Run Code Online (Sandbox Code Playgroud)

以及上述方法可见的另一种方法:

static void Main()
{
    string s;
Run Code Online (Sandbox Code Playgroud)

调用F(没有命名参数)编译没有任何问题:

    s = F<string>(() => "hello world"); // with explicit type argument <string>
    s = F(() => "hello world"); // with type inference
Run Code Online (Sandbox Code Playgroud)

当使用命名参数时......

    s = F<string>(f: () => "hello world");
Run Code Online (Sandbox Code Playgroud)

...使用显式类型参数的上述代码行仍然可以编译而没有问题.也许并不太令人惊讶,如果安装了ReSharper,它将表明"类型参数规范是多余的".

但是,删除类型参数时...

    s = F(f: () => "hello world");
Run Code Online (Sandbox Code Playgroud)

C#编译器将报告此错误:

无法从用法推断出方法'Program.F(System.Func)'的类型参数.尝试显式指定类型参数.

对于命名参数和类型推断之间的这种交互,是否有逻辑解释?

这种行为是否记录在语言规范的某处?

我明白,根本没有必要为这个论点命名.但是,我在一个更复杂的场景中发现了这种行为,我认为在我的方法调用中为参数命名以用于内部文档目的可能是有意义的.我不是问如何解决这个问题.我试图理解一些语言的细节.

为了使事情更有趣,我发现以下所有编译都没有问题:

    Func<string> func = () => "hello world";
    s = F<string>(func);
    s = F(func);
    s = F<string>(f: func);
    s = F(f: func);
}
Run Code Online (Sandbox Code Playgroud)

顺便说一下,我用非静态方法观察到了相同的行为.我只是选择使用静态方法使这里的示例更短一些.

Aka*_*ava 16

推理不是可以在编译中的许多嵌套级别工作的东西.这是基于所提供的参数的猜测.我觉得编译器编写者没有考虑推断逻辑和命名参数.如果考虑抽象语法树,即使逻辑相同,但F(()=>"xyz")和F(f :()=>"xyz")都是编译器角度不同的抽象语法树.

我觉得这只是编译器设计者忽略的规则,即使编译器本身也是一个包含大量规则的程序.一条规则匹配第一个案例但没有规则匹配第二个案例.它可能在概念上是正确的,但编译器只是一个程序,所有规则都是人为编码的.

好吧,我猜其他人已经确定,它是一个错误,应该报告给微软!

  • OP应该被视为一个错误:冗余的命名参数不应该破坏代码. (2认同)

Mar*_*urd 6

只是想让你知道这一个特定于C#的错误(和@leppie我已经确认它确实失败了标准的csc.exe,甚至在Visual Studio中都没有).冗余地指定命名参数不应该导致行为的改变.

Microsoft Connect已报告该错误.

等效的VB工作正常(因为它编译我添加了一点点来确认运行时行为符合预期):

Imports System

Module Test
  Function F(Of T)(ByVal fn As Func(Of T)) As T
    Return fn()
  End Function

  Function Inc(ByRef i as Integer) As String
    i += 1
    Return i.ToString
  End Function

  Sub Main()
    Dim s As String
    s = F(Of String)(Function()"Hello World.")
console.writeline(s)
    s = F(Function()"Hello, World!")
console.writeline(s)
    s = F(Of String)(fn:=Function()"hello world.")
console.writeline(s)
    s = F(fn:=Function()"hello world")
console.writeline(s)
    Dim i As Integer
    Dim func As Func(Of String) = Function()"hello world " & Inc(i)
    s = F(Of string)(func)
console.writeline(s)
    s = F(func)
console.writeline(s)
    s = F(Of string)(fn:=func)
console.writeline(s)
    s = F(fn:=func)
console.writeline(s)
  End Sub
End Module
Run Code Online (Sandbox Code Playgroud)

输出:

Hello World.
Hello, World!
hello world.
hello world
hello world 1
hello world 2
hello world 3
hello world 4
Run Code Online (Sandbox Code Playgroud)