views:

354

answers:

2

Hi,

the following code used to work fine under vs2008:

namespace N2.Engine.Globalization
{
    public class DictionaryScope : Scope
    {
                object previousValue;
     public DictionaryScope(IDictionary dictionary, object key, object value)
      : base(delegate
      {

       if (dictionary.Contains(key))
        previousValue = dictionary[key];
       dictionary[key] = value;
      }, delegate
      {
       if (previousValue == null)
        dictionary.Remove(key);
       else
        dictionary[key] = previousValue;
      })
     {

     }
    }
}

but now it reports An object reference is required for the non-static field, method, or property 'N2.Engine.Globalization.DictionaryScope.previousValue'

It seems something changed in the compiler? Any workarounds?

update:

regarding the suggestion to use a virtual method. This probably wouldn work either, as the virtual method would get called from the base constructor, which I believe is also not possible?

Here is the implementation of the Scope (base class):

public class Scope: IDisposable
    {
     Action end;

     public Scope(Action begin, Action end)
     {
      begin();
      this.end = end;
     }

     public void End()
     {
      end();
     }

     #region IDisposable Members

     void IDisposable.Dispose()
     {
      End();
     }

     #endregion
+9  A: 

Update:

§ 7.5.7 This access

A this-access consists of the reserved word this.

this-access:

this

A this-access is permitted only in the block of an instance constructor, an instance method, or an instance accessor.

This is none of these. The 4.0 compiler looks to be correct. Presumably it isn't happy because this in essence provides access to this at a point when the type isn't initialized. Maybe ;-p

Note that I expect that it isn't really the this.someField that causes this - more that the use of a field causes this to be captured, meaning it wants to hoist the this instance onto a compiler-generated class - as though you had written:

public MyCtor() : base( new SomeType(this).SomeMethod ) {...}

The C# 3.0 compiler spots the above abuse of this.


Reproduced. Investigating. It looks like an issue resolving the implicit this in the constructor chaining.

The most likely workaround would be to use a virtual method instead of a delegate, and simply override it in the derived class.

One workaround would be to pas the instance in as an argument, so the delegate becomes "obj => obj.whatever...", and use theDelegate(this);.

Simpler repro:

public class MyBase {
    public MyBase(Action a) { }
}
public class MySub : MyBase {
    private string foo;
    // with "this.", says invalid use of "this"
    // without "this.", says instance required
    public MySub() : base(delegate { this.foo = "abc"; }) { }
}

I would need to check the spec, but I'm not sure whether this is valid in this context... so the 4.0 compiler could be correct.

Marc Gravell
Your analysis is correct. We discovered this bug late in the C# 3 cycle and postponed fixing it until C# 4. As you correctly note, allowing an anonymous function in this context provides numerous opportunities for accessing "this" before the object has gotten through enough of its initialization sequence to be safe. And as SLaks notes in another posting, we didn't get the codegen "correct" for some of these cases anyway. (I say "correct" in quotes because of course there is no correct codegen defined for an erroneous program.)
Eric Lippert
@Eric - cheers for the info.
Marc Gravell
thank you for a very thorough answer! I'll have to go through the code and see where this is used and how I can fix it. Might be in many places (this is from N2 open source CMS)
Robert Ivanc
see the updated question regarding workaround
Robert Ivanc
A: 

Add: static object previousValue;

Andrey