Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are anonymous backing fields still created for virtual auto-implemented properties when they are overridden?

Morbid curiosity. Say I have this hierarchy:

class Base {
  public virtual int Field { get; set; }
}

class Derived : Base {
  int _field;
  public override int Field { get { return _field; } set { _field = value; } }
}

If I instantiate Base, the compiler will magically create a backing field for the Field property.

So, given that Derived does not reference the base implementation, does the backing field get created when Derived is instantiated? Is this dictated in the C# spec, or left to compiler implementations?

Update

Turns out that the specification does indeed specifically state that automatically-implemented properties are implemented with a "hidden backing field". (Sec 10.7.3) Nothing is said of my specific question. Assuming the word "hidden" there refers to the same member-hiding functionality provided by the new keyword, I must conclude that the backing field is always created regardless of use.

I guess a related question might be "Is a backing field created for a auto-implemented property that is never accessed?" Same underlying argument, same conclusion.

like image 880
G-Wiz Avatar asked Jun 20 '11 21:06

G-Wiz


2 Answers

So, given that Derived does not reference the base implementation, does the backing field get created when Derived is instantiated?

Absolutely the backing field is created. Just because Derived doesn't use the backing field provided by Base, for an instance of Derived to be a Base, the field must exist. Imagine if we added the following method to Derived:

public int GetBaseField()
{
    return base.Field; // calls Base.get_Field(), which uses the base
                       // class's auto-generated backing property
}

This example needs to be valid; there's never a good reason to try to optimize away base class values that are unused in a derived class.

like image 177
Adam Maras Avatar answered Sep 29 '22 08:09

Adam Maras


This sample program demonstrates that the backing field is created. The call to GetFields returns a backing field of Int32 <Field>k__BackingField in the example below. You can set and get the value of this field via reflection, but not through the derived instance. You can also see that the setter declared on the Derived class is not called when you update the field via reflection.

void Main()
{
    var derived = new Derived();
    derived.Field = 10;
    var fieldInfo = typeof(Base).GetFields(
                        BindingFlags.NonPublic | BindingFlags.Instance)[0];
    fieldInfo.SetValue(derived, 20);
    Console.WriteLine(derived.Field);
    Console.WriteLine(fieldInfo.GetValue(derived));
}

public class Base {
  public virtual int Field { get; set; }
}

public class Derived : Base {
  int _field;
  public override int Field 
  { 
      get { return _field; } 
      set { Console.WriteLine("Setter called."); _field = value; } 
  }
}

The output of this program is:

Setter called.
10
20

The 20 value that is written out along with the FieldInfo instance that is returned from the call to GetFields demonstrates that the backing field is created.

like image 28
rsbarro Avatar answered Sep 29 '22 08:09

rsbarro