2010-12-14 12 views
5
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; }; 
    } 
} 

Wenn ich versuche, Foo.Calc ("Foo") aufzurufen; Ich habe Ausnahme "Objektreferenz nicht auf eine Instanz eines Objekts festgelegt." weil der statische Konstruktor von Foo nicht aufgerufen wurde und CalcFunction null ist. Ich möchte die Init-Methode für die Foo-Klasse nicht verwenden und sie vor dem Aufruf von Calc() aufrufen.Reihenfolge der Aufrufer

Kann ich die Reihenfolge der aufrufenden Konstruktoren ändern?

+1

Mixing Vererbung und statische Mitglieder scheint ungerade. Wenn 'Calc' und' CalcFunction' nicht statisch wären, hätte 'Foo' einen regulären Instanzkonstruktor und' CalcFunction' würde vor dem Aufruf von 'Calc' initialisiert werden. –

Antwort

6

Nein - Ihr Code hat in

Base.Calc("Foo"); 

... so Foo überhaupt nicht initialisiert zusammengestellt.

Dies ist keine Frage der Ordnung von statischen Konstruktoren laufen zu sein ... es ist, dass der statische Konstruktor für Foo einfach nicht laufen überhaupt sein wird.

Grundsätzlich sollten Sie Ihr Design ändern. Sie könnte erzwingen den statischen Konstruktor von Foo durch die Erstellung einer Instanz von Foo ausgeführt werden, aber das ist ziemlich böse ... Ihr Code wird nicht am Ende klar so sein.

+1

Meinst du nicht "Base.Calc"? –

+0

@Brian: Yup, oops :) –

+0

Könnten Sie erklären, warum Foo.Calc ("Foo"); wird in Base.Calc ("Foo") kompiliert? – ukraine

2

C# garantiert, dass der statische Konstruktor für Base ausgeführt wird, bevor ein Code in Base verwendet wird. Es gibt keine Garantie, dass Code in Foo ausgeführt wird. (Sie haben einen Anruf Foo.Calc geschrieben, aber dies ist wirklich ein Aufruf an Base.Calc.)

Es gibt keine einfache Lösung: Sie eine explizite init-Methode einführen könnte, oder die Klassenhierarchie abzuflachen oder CalcFunction in Foo bewegen.

1

Es scheint, dass Sie die Verwendung von statischen und abstrakten Keywords missverstanden haben. Eine abstrakte Klasse mit nur statischen Elementen zu haben, macht fast keinen Sinn. Sind Sie sicher, dass dies nicht näher an dem ist, was Sie versucht haben:

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; }; 
    } 
} 
+0

Noch besser: mache 'CalcFunction' privat und füge einen Konstruktor hinzu:' protected Base (Func calcFunction) ' –

Verwandte Themen