Функция If() и делегаты в VB

Взяв следующий код в VB2012, я ожидаю, что foo будет инициализирован в Nothing:

 Dim foo As Func(Of Integer) = If(True, Nothing, Function() 0)

Однако он выдает исключение ArgumentException:

Delegate to an instance method cannot have null 'this'.

Я не совсем понимаю это сообщение об ошибке, но ситуация становится откровенно пугающей, если я изменяю тип foo на Func(Of Integer, Integer). В этом случае код выполняется без ошибок, но foo становится загадочным лямбда-выражением, которое при вызове генерирует исключение NullReferenceException.

Если я использую традиционный оператор If вместо функции If, код работает так, как ожидалось.

Может ли кто-нибудь объяснить мне такое поведение?


person Dave    schedule 01.02.2014    source источник
comment
Ошибка компилятора. Присутствует в VS2013, вы можете загрузить его на connect.microsoft.com   -  person Hans Passant    schedule 02.02.2014
comment
@HansPassant: также 2010 и 2012 годы.   -  person Neolisk    schedule 03.02.2014


Ответы (2)


Похоже, IIf работает нормально:

Dim foo As Func(Of Integer) = IIf(True, Nothing, Function() 0)

Но я должен сказать, я понятия не имею, почему.

Обновить

Ладно, думаю, у меня есть причина. Компилятор оптимизирует ваш код следующим образом:

Dim foo As Func(Of Integer) = New Func(Of Integer)(Nothing.Invoke)

и поэтому вы получаете исключение.

Даже если вы не используете True в качестве условия и пытаетесь использовать переменную

Dim t = Integer.Parse(Console.ReadLine()) < 10
Dim foo As Func(Of Integer) = If(t, Nothing, Function() 0)

он трансформируется в:

Dim foo As Func(Of Integer) = New Func(Of Integer)((If((Integer.Parse(Console.ReadLine()) < 10), Nothing, New VB$AnonymousDelegate_0(Of Integer)(Nothing, ldftn(_Lambda$__1)))).Invoke)

который все равно вызовет исключение.

person MarcinJuraszek    schedule 01.02.2014
comment
Интересно, я подозревал, что ошибка будет there is no implicit conversion between Nothing and lambda. - person Hamlet Hakobyan; 02.02.2014
comment
Так это ошибка в компиляторе VB? Потому что я до сих пор не понимаю, почему мой код будет неправильным. - person Dave; 02.02.2014
comment
Проблема возникает из-за того, что компилятор преобразует оператор If(). Я не уверен, что это ошибка или это где-то задокументировано, но я думаю, что это не совсем интуитивно понятно, и я ожидаю, что это сработает, - person MarcinJuraszek; 02.02.2014

Похоже на ошибку в компиляторе, потому что этот код эквивалентен, но работает как положено:

Dim f As Func(Of Integer) = Function() 0
Dim foo As Func(Of Integer) = If(True, Nothing, f)

Я также смог воспроизвести ваше загадочное лямбда-выражение, используя этот код:

Dim foo As Func(Of Integer) = If(True, Nothing, Function() Nothing)

Что логически эквивалентно вашему утверждению (Nothing должно быть неявно преобразовано в 0).

Это странно - если компилятор хочет что-то оптимизировать, я ожидаю, что он оптимизируется так же, как и для приведенного ниже утверждения. Однако приведенный ниже оператор ведет себя так, как ожидалось:

Dim foo As Func(Of Integer) = If(True, Nothing, Nothing)

Поскольку True всегда равно True, и это выражение, и ваше должны привести к одному и тому же коду.

person Neolisk    schedule 02.02.2014