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

當我嘗試調用Foo.Calc(「Foo」);我有例外「對象引用未設置爲對象的實例」。因爲Foo的靜態構造函數未被調用,並且CalcFunction爲null。我不想爲Foo類使用Init方法,並在調用Calc()之前調用它。調用構造函數的順序

我可以改變調用構造函數的順序嗎?

+1

混合繼承和靜態成員似乎很奇怪。如果'Calc'和'CalcFunction'不是靜態的,那麼'Foo'將會有一個常規的實例構造函數,'CalcFunction'會在調用'Calc'之前被初始化。 – 2010-12-14 10:06:07

回答

6

否 - 你的代碼已經被編譯成

Base.Calc("Foo"); 

...所以Foo完全不被初始化。

這不是秩序正在運行靜態構造函數的的事......它是爲Foo靜態構造函數根本沒有運行在所有。

基本上,你應該改變你的設計。你可能強制Foo的靜態構造函數通過創建一個Foo的實例來運行,但是這非常討厭......你的代碼最終不會以明確那樣。

+1

難道你不是指'Base.Calc'? – 2010-12-14 10:08:50

+0

@Brian:是的,哎呀:) – 2010-12-14 10:15:25

+0

你能解釋爲什麼Foo.Calc(「Foo」);將被編譯成Base.Calc(「Foo」)? – ukraine 2010-12-14 10:34:10

2

C#保證在使用Base中的任何代碼之前,運行Base的靜態構造函數。沒有什麼可以保證Foo中的任何代碼都可以運行。 (您已寫入Foo.Calc一個電話,但是這是真的Base.Calc打電話。)

有沒有簡單的解決辦法:你可以引入一個明確的init方法,或壓平類層次結構,或移動CalcFunctionFoo

1

看起來你錯誤地理解了靜態和抽象關鍵字的使用。只有靜態成員的抽象類幾乎沒有意義。你確定這不是更接近你試圖:

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

更好:使'CalcFunction'專用並添加一個構造函數:'protected Base(Func calcFunction)'' – 2010-12-14 10:13:35