2009-04-18 14 views
12

Dziedziczenie statyczne działa tak samo jak dziedziczenie instancji. Tyle tylko, że nie wolno ci uczynić metod statycznych wirtualnymi lub abstrakcyjnymi.C# wirtualne (lub abstrakcyjne) metody statyczne

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"); 
    } 
} 

Wyjście to będzie:

Base class 
Child class 
Base class 
Base class 

Ale chcę:

Base class 
Child class 
Base class 
Child class 

Jeśli mogę na metodach statycznych, chciałbym zrobić TargetMethod wirtualny i byłoby wykonać zadanie. Ale czy jest jakieś obejście, aby uzyskać ten sam efekt?

Edycja: Tak, mógłbym umieścić kopię Operacji w klasie dziecka, ale wymagałoby to skopiowania i wklejenia dużego kodu do każdego dziecka, co w moim przypadku dotyczy około 35 klas, koszmar utrzymania.

+0

Dlaczego używasz funkcji statycznych? – munificent

+0

Jesteś mylące dziedziczenia z wyszukiwaniem i ukrywanie nazwy. –

+0

Możliwy duplikat [Dlaczego nie mogę mieć abstrakcyjnych metod statycznych w języku C#?] (Https://stackoverflow.com/questions/3284/why-cant-i-have-abstract-static-methods-in-c) –

Odpowiedz

12

Nie, nie można zastąpić metody statycznej. "static" oznacza również, że jest on statycznie związany przez kompilator, więc właściwa metoda, która ma zostać wywołana, nie jest znaleziona w czasie wykonywania, ale związana podczas kompilacji.

Co należy zrobić, aby klasa stała się niestatyczna. Zmień metodę na wirtualną i nadpisaj ją, aby w pełni korzystać z prawdziwego dziedziczenia. Następnie, jeśli naprawdę tego potrzebujesz, ustaw statyczny punkt wejścia na odniesienie do klasy. Na przykład statyczna fabryka, singleton (w większości przypadków jest to anty-wzór, ale jest tak dobra, jak klasa statyczna) lub po prostu nieruchomość statyczna.

8

Można przechowywać TargetMethod jako delegat, który mógłby zmienić podklasą ile potrzeba:

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"); 
     }); 
    } 
} 

Ponieważ są to przypadki statyczne, choć - w _targetMethod jest wspólne we wszystkich przypadkach - zmieniając go w TestChild zmienia go także dla TestBase. Możesz o to nie dbać lub nie. Jeśli to zrobisz, generics lub Dictionary<Type, Action> może pomóc.

Ogólnie rzecz biorąc, miałbyś znacznie łatwiejszy czas, jeśli nie nalegałeś na statykę, a może użyłeś kompozycji zamiast dziedziczenia.

2

Jeśli szukasz zrobić abstrakcyjne metody statyczne, to działa, i okazuje się być najprostszym rozwiązaniem dla mnie, aby dostosować się do:

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"); 
    } 
} 

Ale ja wciąż znakowania Stafan jako rozwiązanie, ponieważ za pomocą Dziedziczenie dziedzin jest prawdopodobnie najlepszą rekomendacją dla każdego, kto znajduje się w podobnej sytuacji. Ale po prostu musiałbym przepisać za dużo kodu.

2

Ok oto co mam zrobić

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

myślę, że będzie to opłacalne rozwiązanie dla tego, co chcesz zrobić, nie łamiąc zbyt wielu zasad purist oo.

Powiązane problemy