2009-04-18 19 views
12

Statische Vererbung funktioniert genau wie Instanzvererbung. Außer Ihnen ist es nicht erlaubt, statische Methoden virtuell oder abstrakt zu machen.C# virtuelle (oder abstrakte) statische Methoden

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

erhalten Sie folgende Ausgabe:

Base class 
Child class 
Base class 
Base class 

Aber ich will:

Base class 
Child class 
Base class 
Child class 

Wenn ich auf statische Methoden könnte, würde ich Targetmethod virtuellen machen und es würde die Arbeit machen. Aber gibt es eine Arbeit um den gleichen Effekt zu erzielen?

Edit: Ja, ich könnte eine Kopie von Operation in der Kind-Klasse, aber das würde kopieren und einfügen ein großes bisschen Code in jedes Kind, was in meinem Fall ist etwa 35 Klassen, eine Wartung Albtraum.

+0

Warum verwenden Sie statische Funktionen? – munificent

+0

Sie verwechseln die Vererbung mit dem Nachschlagen und dem Ausblenden von Namen. –

+0

Mögliches Duplikat von [Warum kann ich keine abstrakten statischen Methoden in C# haben?] (Https://stackoverflow.com/questions/3284/why-cant-i-have-abstract-static-methods-in-c) –

Antwort

12

Nein, Sie können eine statische Methode nicht überschreiben. "Statisch" bedeutet auch, dass es vom Compiler statisch gebunden ist, so dass die tatsächlich aufgerufene Methode zur Laufzeit nicht gefunden wird, sondern zur Kompilierzeit gebunden ist.

Was Sie tun sollten, ist die Klasse nicht statisch zu machen. Machen Sie die Methode virtuell und überschreiben Sie sie und nutzen Sie die echte Vererbung voll aus. Wenn Sie es wirklich benötigen, erstellen Sie einen statischen Einstiegspunkt für eine Referenz Ihrer Klasse. Zum Beispiel eine statische Factory, Singleton (in den meisten Fällen ein Anti-Pattern, aber so gut wie eine statische Klasse) oder nur eine statische Eigenschaft.

8

Sie konnten die Targetmethod als Delegierter speichern, die eine Unterklasse nach Bedarf ändern könnte:

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

statische Instanzen Da diese, obwohl - die _targetMethod über alle Instanzen hinweg gemeinsam genutzt wird - es in TestChild Wechsel ändert sich für TestBase auch. Sie können sich darum kümmern oder nicht. Wenn Sie das tun, könnten Generika oder ein Dictionary<Type, Action> helfen.

Insgesamt hätten Sie jedoch viel leichter, wenn Sie nicht auf Statik oder vielleicht Komposition statt Vererbung bestanden hätten.

2

Wenn Sie abstrakte statische Methoden zu tun suchen, dann funktioniert das, und stellt sich heraus, die einfachste Lösung zu sein für mich anzupassen:

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

Aber ich habe noch Markierung Stafan als die Lösung bin da mit Instanzvererbung ist wahrscheinlich die beste Empfehlung für jeden in einer ähnlichen Situation. Aber ich müsste einfach zu viel Code umschreiben.

2

Ok hier ist das, was ich habe

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

Ich denke, dies ist eine tragfähige Lösung sein für das, was Sie zu viele Puristen OO Prinzipien, ohne brechen zu wollen.

Verwandte Themen