[Mono-list] Static constructor issue

Jonathan Gilbert 2a5gjx302 at sneakemail.com
Thu Sep 7 15:07:42 EDT 2006


At 02:28 PM 07/09/2006 -0400, Abe Gillespie wrote:
>> No, I wasn't talking of instance constructors. An example:
>>
>> class Parent {
>>         static Parent() {
>>                 // important stuff
>>         }
>>         public Parent(int foo) {
>>         }
>> }
>>
>> class Child : Parent {
>>         static Child() {
>>                 // stuff that relies on "important stuff"
>>         }
>>         public Child(int foo) : base(foo) {
>>         }
>> }
>>
>> Code then does new Child(42);.
>>
>> I would assume that before Child.cctor is called, Parent.cctor would
>> need to be called by the runtime - which apparently is not happening.
>> So I'm wondering whether this is a Mono issue or whether it is
>> intended that way.
>
>static Child.ctor is called first and then static Parent.ctor is
>called ... that's just the way the order of operations go.
>
>The metaphor I was given way back in my student days is this:
>Think of building a watch, you first start with the internals (gears
>and such) and this can be seen as the Child.  Then you put on the
>outer parts (housing, glass, etc.) where this is seen as the Parent.
>
>The reason why it's different for instance ctors is because you call
>the Parent ctor specifically before the code inside the Child ctor
>runs.

I'm not sure that metaphor is really useful :-) If you want to force the
base class' static constructor to run first, then access any member of the
base class from the derived class' static constructor. The reason the base
class' static constructor is not immediately run is that the inheritance
rules involved don't apply to static members. Unlike other languages, .NET
*does* offer inheritance of static members, but the derived class -- in
terms of its static members -- is not really seen as a "kind-of" the base
class.

To put it succinctly: The execution of Child's .cctor does not in and of
itself constitute accessing a member of Parent.

See the attached sample which demonstrates this behaviour.

Jonathan Gilbert
-------------- next part --------------
using System;

class MainClass
{
  static void Main()
  {
    Output.WriteLine("Calling Child..ctor from Main");
    Output.Indent++;
    new Child(42);
    Output.Indent--;
    Output.WriteLine("Leaving Main");
  }
}

class Output
{
  public static int Indent;

  public static void WriteLine(string line)
  {
    WriteIndent();
    Console.WriteLine(line);
  }

  public static void WriteLine(string line, object p0)
  {
    WriteIndent();
    Console.WriteLine(line, p0);
  }

  static void WriteIndent()
  {
    for (int i=0; i < Indent; i++)
      Console.Write("  ");
  }

  public static int WriteLineThroughAndIndent(string line, int through)
  {
    WriteLine(line);
    Indent++;
    return through;
  }
}

class Child : Parent
{
  static Child()
  {
    object value;

    Output.WriteLine("Start of Child..cctor");
    Output.Indent++;

    Output.WriteLine("Outside value (first pass)");
    Output.Indent++;
    Output.WriteLine("getting outside value...");
    value = Outside.Value;
    Output.WriteLine("outside value: {0}", value == null ? "(null)" : value);
    Output.Indent--;

    Output.WriteLine("Parent value");
    Output.Indent++;
    Output.WriteLine("getting parent value...");
    value = Parent.Value;
    Output.WriteLine("parent value: {0}", value == null ? "(null)" : value);
    Output.Indent--;

    Output.WriteLine("Outside value (second pass)");
    Output.Indent++;
    Output.WriteLine("getting outside value...");
    value = Outside.Value;
    Output.WriteLine("outside value: {0}", value == null ? "(null)" : value);
    Output.Indent--;

    Output.Indent--;
    Output.WriteLine("End of Child..cctor");
  }

  public Child(int value)
    : base(Output.WriteLineThroughAndIndent("Start of Child..ctor", value))
  {
    Output.WriteLine("Child..ctor({0})", value);

    Output.Indent--;
    Output.WriteLine("End of Child..ctor");
  }
}

class Parent
{
  static Parent()
  {
    Output.WriteLine("Start of Parent..cctor");
    Output.Indent++;
    Output.WriteLine("setting Parent.Value...");
    Parent.Value = "The parent's static value";
    Output.WriteLine("setting Outside.Value...");
    Outside.Value = "The outside static value, assigned from Parent";
    Output.Indent--;
    Output.WriteLine("End of Parent..ctor");
  }

  public static string Value;

  public Parent(int value)
  {
    Output.WriteLine("Start of Parent..ctor");
    Output.Indent++;

    Output.WriteLine("Parent..ctor({0})", value);

    Output.Indent--;
    Output.WriteLine("End of Parent..ctor");
  }
}

class Outside
{
  public static string Value;
}


More information about the Mono-list mailing list