Подтвердить что ты не робот

Это ошибка в компиляторе VB.NET или по дизайну?

Я нашел разницу в разрешении перегрузки между С# и 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 сообщит об ошибке:

Ошибка перегрузки невозможна, поскольку для этих аргументов наиболее специфичным для FW не является:

'Public Sub Foo (Of String) (выражение As System.Linq.Expressions.Expression(Of System.Func(Of String))): Не наиболее конкретный.

'Public Sub Foo (Of) (значение As)': не самый конкретный.


Добавление кода С#, который работает для сравнения:

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)
    {

    }
}
4b9b3361

Ответ 1

Я уверен, что нашел причину этого, и это не короткое пришествие VB-компилятора, но это короткое начало компилятора С#.

Рассмотрим следующее, что является законным в VB:

Dim foo = Function() String.Empty

Эквивалент не будет законным в С#:

var foo = () => string.Empty;

Итак, вывод типа немного сильнее в VB, из-за этого аргумент в примере Function() String.Empty может быть выведен на Function(Of String), который применим к перегрузке Foo(Of T)(ByVal value As T).

В С# это не может произойти, так как () => string.Empty никогда не может быть выведено без контекста, это может быть выведено в перегрузке выражения, но не в T-перегрузке.

Ответ 2

Игнорируя на данный момент предположение, что "если компилятор С# делает это, он должен быть прав, поэтому он является ошибкой в ​​компиляторе VB". Я сразу вижу двусмысленность:

Foo(Function() String.Empty)

Может вызывать версию T, заменяя Func(Of String) на T. Или он может реклассифицировать одиночную строку lambda в дерево выражений и вызвать метод Expression(Of Func(Of String)). Нет причин, по которым нужно быть предпочтительнее другого, и на самом деле VB останавливает вас от продолжения, не заставляя вас указывать, какой из них вы хотите.