Reputation: 17151
I've found a difference in overload resolution between the C# and the VB-compiler. I'm not sure if it's an error or by design:
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
Note that it doesn't matter if the overloaded Foo-methods are defined in VB or not. The only thing that matters is that the call site is in VB.
The VB-compiler will report an error:
Overload resolution failed because no accessible 'Foo' is most specific for these arguments:
'Public Sub Foo(Of String)(expression As System.Linq.Expressions.Expression(Of System.Func(Of String)))': Not most specific.
'Public Sub Foo(Of )(value As )': Not most specific.
Adding the C# code which works for comparison:
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)
{
}
}
Upvotes: 17
Views: 683
Reputation: 17151
I'm pretty sure I've found the reason for this and it is not a short coming of the VB-compiler but it is a short coming of the C# compiler.
Consider the following which is legal in VB:
Dim foo = Function() String.Empty
The equivalent would not be legal in c#:
var foo = () => string.Empty;
So, type inference is a bit stronger in VB, because of this the argument in the example Function() String.Empty
can be inferred to Function(Of String)
which would be applicable to the Foo(Of T)(ByVal value As T)
overload.
In C# this can not happen since the () => string.Empty
can never be inferred without context, it can be inferred in the expression overload but not in the T-overload.
Upvotes: 2
Reputation: 239664
Ignoring for the moment the assumption that "if the C# compiler does it, it must be right, therefore it's a bug in the VB compiler". I can immediately see the ambiguity:
Foo(Function() String.Empty)
Could invoke the T
version, substituting Func(Of String)
for T. Or it could reclassify the single line lambda into an expression tree, and invoke the Expression(Of Func(Of String))
method. There's no reason one should be preferred over the other, and in fact VB is stopping you from proceeding without forcing you to specify which one you want.
Upvotes: 5