{ p...">

Why is the "this" pointer null in the delegate?

I have the following code (details removed for clarity):

private abstract class Base<TResult> { private readonly System.Func<TResult> func = null; protected Base(System.Func<TResult> func) { this.func = func; } public TResult Execute() { return this.func(); } } private class Derived : Base<bool> { public Derived(bool myValue) : base(delegate() { return this.MyValue(); }) { this.myValue = myValue; } private bool myValue = false; private bool MyValue() { return this.myValue; // The "this" pointer is null here... } } Derived d = new Derived(true); bool result = d.Execute(); // This results in a null reference pointer (commented above) 

Any ideas?

Thanks Dave

+7
c #
source share
4 answers

Is it even legal? this at this point is not defined. IIRC, this is a compiler error - already fixed in 4.0.

Here it is in compiler 4.0:

Error 1 The keyword 'this' is not available in the current context C: \ Users \ Marc \ AppData \ Local \ Temporary Projects \ ConsoleApplication1 \ Program.cs 22 40 ConsoleApplication1

For citation 7.5.7:

This access is only allowed in the instance constructor, instance method, or instance instance block . It has one of the following meanings:

(emph mine)

...

Using this in a primary expression in a context other than those listed above is a compile-time error. In particular, you cannot reference this in a static method, a static property accessory, or in the initializer of a field declaration variable.

In the above example, this is simply not true.

+6
source share

Using this in a constructor is always dangerous (except in the special case when you call the sibling constructor). Your Derived constructor captures this during its invocation, which is null since the instance has not yet been created.

+5
source share

This is a compiler error and very strange. Let me explain the details. I would be very happy if some experts clarified this.

Yes, it is incorrect to write this to ctor, but the situation becomes hot because this used inside an anonymous delegate. Usually, if the anonymous delegate does not have a closure (does not capture external variables), it is implemented by the compiler as a static method of the same class. It happened here. But let's take a look at the IL code generated by this static method:

 .method private hidebysig static bool <.ctor>b__0() cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() .maxstack 1 .locals init ( [0] bool CS$1$0000) L_0000: nop L_0001: ldloc.0 L_0002: call instance bool ConsoleApplication15.Derived::MyValue() L_0007: stloc.0 L_0008: br.s L_000a L_000a: ldloc.0 L_000b: ret } 
Did you see that? take a closer look at line L_0002 and line L_0001 . There are two extremely strange things:
  • We tried to call the MyValue method against bool !
  • The method was called as call , but it is not static, the C # compiler usually calls instance methods using callvirt ! If callvirt was used, this call would fail because callvirt checks this == null .

Now let me break it. Let the closure and change code be introduced:

 public Derived(bool myValue) : base(delegate() { return myValue ^ this.MyValue(); }) { this.myValue = myValue; } 

And now everything is in order! No NRE! An anonymous class has been generated and it marks closure. In this case, the correct IL is generated:

 .method public hidebysig instance bool <.ctor>b__0() cil managed { .maxstack 2 .locals init ( [0] bool CS$1$0000) L_0000: nop L_0001: ldarg.0 L_0002: ldfld bool ConsoleApplication15.Derived/<>c__DisplayClass1::myValue L_0007: ldarg.0 L_0008: ldfld class ConsoleApplication15.Derived ConsoleApplication15.Derived/<>c__DisplayClass1::<>4__this L_000d: call instance bool ConsoleApplication15.Derived::MyValue() L_0012: xor L_0013: stloc.0 L_0014: br.s L_0016 L_0016: ldloc.0 L_0017: ret } 

The method is called against closing it. (but still with call instance , hmm)

+1
source share

Looking at my code, I would say this is a design problem ...

Why don't you make an abstract function of the Execute function and let the derived classes provide any implementation they need?

For example:

 private abstract class Base<TResult> { public abstract TResult Execute(); } private class Derived : Base<bool> { //... public override bool Execute(){ return this.myValue; } //.... } Derived d = new Derived(true); bool result = d.Execute(); //This should work now 
0
source share

All Articles