这是VB.NET编译器中的错误还是设计错误?
我发现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
请注意,重载的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.Empty); Foo(string.Empty); Foo(() => string.Empty); } public void Foo(T value) { } public void Foo(Expression<Func> expression) { } }
暂时忽略“如果C#编译器执行它,它必须是正确的,因此它是VB编译器中的错误”的假设。 我可以立即看到模棱两可:
Foo(Function() String.Empty)
可以调用T
版本,用Func(Of String)
代替T.或者它可以将单行lambda重新分类为表达式树,并调用Expression(Of Func(Of String))
方法。 没有理由一个人应该优先于另一个,事实上VB阻止你继续进行而不强迫你指定你想要的那个。
我很确定我已经找到了这个的原因,它不是VB编译器的短暂出现,但它是C#编译器的简称。
考虑以下在VB中合法的内容:
Dim foo = Function() String.Empty
等效在c#中不合法:
var foo = () => string.Empty;
因此,类型推断在VB中要强一些,因此可以将示例Function() String.Empty
的参数推断为Function(Of String)
,它将适用于Foo(Of T)(ByVal value As T)
超载。
在C#中,这不可能发生,因为() => string.Empty
永远不能在没有上下文的情况下推断,它可以在表达式重载中推断,但不能在T重载中推断。