Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Order of calling constructors

Tags:

c#

class Program
{
    static void Main(string[] args)
    {
        Foo.Calc("Foo");
    }   
}

public abstract class Base
{
    protected static Func<string, int> CalcFunction;

    public static void Calc(string str)
    {
        Console.WriteLine(CalcFunction(str));
    }
}

public class Foo : Base
{
    static Foo() 
    {
        CalcFunction = s => { return s.Length; };
    }
}

When I try to call Foo.Calc("Foo"); I have exception "Object reference not set to an instance of an object." because static constructor of Foo was not called and CalcFunction is null. I don't want to use Init method for Foo class and call it before calling Calc().

Can I change order of calling constructors?

like image 625
ukraine Avatar asked Dec 14 '10 09:12

ukraine


3 Answers

No - your code has been compiled into

Base.Calc("Foo");

... so Foo isn't being initialized at all.

This isn't a matter of the order of static constructors being run... it's that the static constructor for Foo simply isn't being run at all.

Basically, you should change your design. You could force the static constructor of Foo to be run by creating an instance of Foo, but that's pretty nasty... your code won't end up being clear that way.

like image 52
Jon Skeet Avatar answered Oct 05 '22 11:10

Jon Skeet


C# guarantees that, before any code in Base is used, the static constructor for Base is run. There's nothing to guarantee that any code in Foo will run. (You've written a call to Foo.Calc, but this is really a call to Base.Calc.)

There's no simple fix: you could introduce an explicit init method, or flatten the class hierarchy, or move CalcFunction into Foo.

like image 22
Tim Robinson Avatar answered Oct 05 '22 09:10

Tim Robinson


It seems you've misunderstood the use of static and abstract keywords. Having an abstract class with only static members makes almost no sense. Are you sure this isn't closer to what you were trying:

class Program
{
    static void Main(string[] args)
    {
        var foo = new Foo()
        foo.Calc("Foo");
    }   
}

public abstract class Base
{
    protected Func<string, int> CalcFunction;

    public void Calc(string str)
    {
        Console.WriteLine(CalcFunction(str));
    }
}

public class Foo : Base
{
    public Foo() 
    {
        this.CalcFunction = s => { return s.Length; };
    }
}
like image 41
Jamiec Avatar answered Oct 05 '22 10:10

Jamiec