2009-04-18 124 views
12

靜態繼承與實例繼承一樣工作。除非您不允許使靜態方法變爲虛擬或抽象。C#虛擬(或抽象)靜態方法

class Program { 
    static void Main(string[] args) { 
     TestBase.TargetMethod(); 
     TestChild.TargetMethod(); 
     TestBase.Operation(); 
     TestChild.Operation(); 
    } 
} 

class TestBase { 
    public static void TargetMethod() { 
     Console.WriteLine("Base class"); 
    } 

    public static void Operation() { 
     TargetMethod(); 
    } 
} 

class TestChild : TestBase { 
    public static new void TargetMethod() { 
     Console.WriteLine("Child class"); 
    } 
} 

這將輸出:

Base class 
Child class 
Base class 
Base class 

但我想:

Base class 
Child class 
Base class 
Child class 

如果我能在靜態方法,我會做TargetMethod虛擬,它會做的工作。但是有沒有一種解決方法來獲得相同的效果?

編輯:是的,我可以在子類中放置一個操作副本,但是這需要將大量代碼複製並粘貼到每個孩子身上,在我的情況下,這是大約35個班級的維護噩夢。

+0

爲什麼使用靜態函數? – munificent 2009-04-18 12:41:23

回答

12

不,您不能覆蓋靜態方法。 「靜態」也意味着它由編譯器靜態綁定,所以實際要調用的方法在運行時找不到,但在編譯時綁定。

你應該做的是使類非靜態。使方法變爲虛擬並覆蓋它,並充分利用真正的繼承。然後,如果您確實需要它,請爲您的課程參考創建一個靜態入口點。例如一個靜態工廠,單例(在大多數情況下它是反模式,但和靜態類一樣好),或者只是一個靜態屬性。

8

您可以在TargetMethod存儲爲代表,它需要一個子類可以改變:

class TestBase { 
    protected static Action _targetMethod; 

    static new() { 
     _targetMethod = new Action(() => { 
      Console.WriteLine("Base class"); 
     }); 
    } 

    public static void TargetMethod() { 
     _targetMethod(); 
    } 

    public static void Operation() { 
     TargetMethod(); 
    } 
} 

class TestChild : TestBase { 
    static new() { 
     _targetMethod = new Action(() => { 
      Console.WriteLine("Child class"); 
     }); 
    } 
} 

因爲這些都是靜態的情況下,雖然 - _targetMethod在所有實例共享的 - 改變其在TestChild改變它對於TestBase也是如此。你可能會也可能不會在意這一點。如果你這樣做,泛型或Dictionary<Type, Action>可能會有所幫助。但是,總的來說,如果你不堅持靜力學,或者可能使用了組合而不是繼承,那麼你會有更容易的時間。

2

如果你正在尋找做抽象靜態方法,那麼這個工作的,原來是最簡單的解決方案,我適應:

class TestBase<ChildType> where ChildType : TestBase<ChildType> { 
    //public static abstract void TargetMethod(); 

    public static void Operation() { 
     typeof(ChildType).GetMethod("TargetMethod").Invoke(null, null); 
    } 
} 

class TestChild : TestBase<TestChild> { 
    public static void TargetMethod() { 
     Console.WriteLine("Child class"); 
    } 
} 

但我還在原地Stafan作爲解決方案,因爲使用實例繼承對於類似情況下的任何人來說可能都是最好的建議。但我只是不得不爲它重寫太多的代碼。

2

確定這裏是我做了什麼

public abstract class Base<T> 
    where T : Base<T>, new() 
{ 
    #region Singleton Instance 
    //This is to mimic static implementation of non instance specific methods 
    private static object lockobj = new Object(); 
    private static T _Instance; 
    public static T Instance 
    { 
     get 
     { 
      if (_Instance == null) 
      { 
       lock (lockobj) 
       { 
        if (_Instance == null) 
        { 
         _Instance = new T(); 
        } 

       } 
      } 
      return _Instance; 
     } 
    } 

    #endregion //Singleton Instance 

    #region Abstract Definitions 

    public abstract T GetByID(long id); 
    public abstract T Fill(SqlDataReader sr); 

    #endregion //Abstract Definitions 
} 

public class InstanceClass : Base<InstanceClass> 
{ 
    //empty constructor to ensure you just get the method definitions without any 
    //additional code executing 
    public InstanceClass() { } 


    #region Base Methods 

    public override InstanceClass GetByID(long id) 
    { 
     SqlDataReader sr = DA.GetData("select * from table"); 
     return InstanceClass.Instance.Fill(sr); 
    } 

    internal override InstanceClass Fill(SqlDataReader sr) 
    { 
     InstanceClass returnVal = new InstanceClass(); 
     returnVal.property = sr["column1"]; 
     return returnVal; 
    } 
} 

我認爲這將是您要在不破壞太多純粹的面向對象的原則,做一個可行的解決方案。