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

Kiedy próbuję wywołać Foo.Calc ("Foo"); Mam wyjątek "Odwołanie do obiektu nie jest ustawione na instancję obiektu". , ponieważ konstruktor statyczny Foo nie został wywołany, a funkcja calcFunction ma wartość null. Nie chcę używać metody Init dla klasy Foo i wywołuj ją przed wywołaniem Calc().Zamówienie wywołań konstruktorów

Czy mogę zmienić kolejność wywoływania konstruktorów?

+1

Mieszanie dziedziczenia i elementów statycznych wydaje się dziwne. Jeśli 'Calc' i' CalcFunction' nie były statyczne, to 'Foo' miałby zwykły konstruktor instancji, a' CalcFunction' byłby inicjalizowany przed wywołaniem 'Calc'. –

Odpowiedz

6

Nie - kod został skompilowany do

Base.Calc("Foo"); 

... więc Foo nie jest inicjowana w ogóle.

To nie jest sprawa zlecenia uruchamianych konstruktorów statycznych ... to, że konstruktor statyczny dla Foo po prostu nie jest w ogóle uruchamiany.

Zasadniczo powinieneś zmienić swój projekt. Ty mógł wymusić uruchomienie konstruktora statycznego Foo przez utworzenie instancji Foo, ale to dość nieprzyjemne ... Twój kod nie zostanie w ten sposób wyczyszczony wyczyszczony.

+1

Nie masz na myśli 'Base.Calc'? –

+0

@Brian: Tak, oops :) –

+0

Czy możesz wyjaśnić, dlaczego Foo.Calc ("Foo"); zostanie skompilowany do Base.Calc ("Foo")? – ukraine

2

C# gwarantuje, że przed użyciem dowolnego kodu w Base zostanie uruchomiony konstruktor statyczny dla Base. Nie ma nic, co zagwarantowałoby uruchomienie dowolnego kodu w wersji Foo. (Pisałeś wezwanie do Foo.Calc, ale to jest naprawdę wezwanie do Base.Calc.)

Nie ma prosty fix: można wprowadzić wyraźne metodę init lub spłaszczyć hierarchię klas, lub przenieść CalcFunction do Foo.

1

Wygląda na to, że źle zrozumiałeś użycie statycznych i abstrakcyjnych słów kluczowych. Posiadanie klasy abstrakcyjnej z tylko statycznymi członkami nie ma prawie żadnego sensu. Czy na pewno nie jest to bliższe temu, co próbujesz:

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

Jeszcze lepiej: ustaw '' CalcFunction' private i dodaj konstruktor: 'protected Base (Func calcFunction)' –