2014-02-01 1 views
4

Принимая следующий код в VB2012, я ожидаю Foo быть инициализированы в настоящее время:Если() функции и делегаты в VB

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, код работает должным образом.

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

+1

Ошибка компилятора. Представленный в VS2013, вы можете подать его на сайте connect.microsoft.com –

+0

@ ХансПасант: Также 2010 и 2012. – Neolisk

ответ

1

Похоже IIf работает просто отлично:

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

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

Update

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

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) 

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

+0

Интересно, я подозревал, что ошибка будет «нет никакого неявного преобразования между Nothing и лямбдой». –

+0

Так это ошибка в компиляторе VB? Потому что я все еще не понимаю, почему мой код будет неправильным. – Dave

+1

Проблема возникает из-за того, что компилятор пути преобразует команду 'if()'. Я не уверен, что это ошибка, или она где-то задокументирована, но я думаю, что это не очень интуитивно, и я ожидаю, что она сработает, – MarcinJuraszek

1

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

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, как это утверждение и ваши должны привести к тому же коду.