这是VB.NET编译器中的错误还是设计错误?

Pat*_*gne 17 .net c# vb.net compiler-construction

我发现C#和VB编译器之间的重载决策有所不同.我不确定这是错误还是设计错误:

Public Class Class1
    Public Sub ThisBreaks()

        ' These work '
        Foo(Of String)(Function() String.Empty) 'Expression overload '
        Foo(String.Empty) 'T overload '

        ' This breaks '
        Foo(Function() String.Empty)
    End Sub

    Public Sub Foo(Of T)(ByVal value As T)

    End Sub

    Public Sub Foo(Of T)(ByVal expression As Expression(Of Func(Of T)))

    End Sub
End Class
Run Code Online (Sandbox Code Playgroud)

请注意,重载的Foo方法是否在VB中定义并不重要.唯一重要的是呼叫站点在VB中.

VB编译器将报告错误:

重载决策失败,因为没有可访问的'Foo'对这些参数最具体:

'Public Sub Foo(Of String)(表达式为System.Linq.Expressions.Expression(Of System.Func(Of String)))':不是最具体的.

'Public Sub Foo(Of)(价值为)':不是最具体的.


添加用于比较的C#代码:

class Class1
{
    public void ThisDoesntBreakInCSharp()
    {
        Foo<string>(() => string.Empty);
        Foo(string.Empty);
        Foo(() => string.Empty);
    }

    public void Foo<T>(T value)
    {

    }

    public void Foo<T>(Expression<Func<T>> expression)
    {

    }
}
Run Code Online (Sandbox Code Playgroud)

Dam*_*ver 5

暂时忽略"如果C#编译器执行它,它必须是正确的,因此它是VB编译器中的错误"的假设.我可以立即看到歧义:

Foo(Function() String.Empty)
Run Code Online (Sandbox Code Playgroud)

可以调用T版本,替换Func(Of String)T.或者它可以将单行lambda重新分类为表达式树,并调用该Expression(Of Func(Of String))方法.没有理由一个人应该优先于另一个,事实上VB阻止你继续进行而不强迫你指定你想要的那个.


Pat*_*gne 2

我很确定我已经找到了原因,这不是 VB 编译器的缺点,而是 C# 编译器的缺点。

考虑以下在 VB 中合法的情况:

Dim foo = Function() String.Empty
Run Code Online (Sandbox Code Playgroud)

等价物在 c# 中是不合法的:

var foo = () => string.Empty;
Run Code Online (Sandbox Code Playgroud)

因此,VB 中的类型推断要强一些,因此Function() String.Empty可以推断出示例中的参数Function(Of String)适用于重载Foo(Of T)(ByVal value As T)

在 C# 中,这种情况不会发生,因为() => string.Empty在没有上下文的情况下永远无法推断出,它可以在表达式重载中推断,但不能在 T 重载中推断。