質問

Taking the following code in VB2012, I expect foo to be initialized to Nothing:

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

However, it throws an ArgumentException:

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

I don't quite understand this error message, but the situation gets outright scary if I change the type of foo to Func(Of Integer, Integer). In that case the code runs with no errors, but foo gets to be a mysterious lambda expression, which throws a NullReferenceException when called.

If I use the traditional If statement instead of the If function, the code works as expected.

Could someone explain this behaviour to me?

役に立ちましたか?

解決

Looks like IIf works just fine:

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

But I have to say, I have no idea why.

Update

OK, I think I have a reason. Compiler optimizes your code to following:

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

and that's why you get an exception.

Even when you don't use True as condition, and try to use variable

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

it's being transformed into:

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)

which will throw exception anyway.

他のヒント

Looks like a bug in compiler, because this code is equivalent, but it works as expected:

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

I was also able to reproduce your mysterious lambda expression using this code:

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

Which is logically equivalent to your statement (Nothing should get implicitly converted to 0).

This is weird - if compiler wants to optimize something, I would expect it to optimize in the same way as it would do for below statement. However, the below statement behaves as expected:

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

Because True is always True, both this statement and yours should result in the same code.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top