2009-04-18 22 views
12

L'ereditarietà statica funziona come l'ereditarietà di istanza. Tranne che non ti è permesso di rendere i metodi statici virtuali o astratti.Metodi statici C# virtuali (o astratti)

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

Questo stamperà:

Base class 
Child class 
Base class 
Base class 

Ma voglio:

Base class 
Child class 
Base class 
Child class 

Se ho potuto sui metodi statici, mi farebbe TargetMethod virtuale e sarebbe fare il lavoro. Ma c'è un lavoro in giro per ottenere lo stesso effetto?

Modifica: Sì, potrei inserire una copia di Operazione nella classe figlio, ma ciò richiederebbe copia e incolla di un gran numero di codice in ogni bambino, che nel mio caso è di circa 35 classi, un incubo di manutenzione.

+0

Perché stai utilizzando funzioni statiche? – munificent

+0

Si sta confondendo l'ereditarietà con la ricerca e il nome nascosto. –

+0

Possibile duplicato di [Perché non posso avere metodi statici astratti in C#?] (Https://stackoverflow.com/questions/3284/why-cant-i-have-abstract-static-methods-in-c) –

risposta

12

No, non è possibile sovrascrivere un metodo statico. "statico" significa anche che è vincolato staticamente dal compilatore, quindi il metodo effettivo da chiamare non viene trovato in fase di runtime, ma vincolato al momento della compilazione.

Quello che dovresti fare è rendere la classe non statica. Rendi virtuale il metodo, esegui l'override e sfrutta appieno l'ereditarietà reale. Quindi, se davvero ne hai bisogno, crea un punto di accesso statico a un riferimento della tua classe. Ad esempio una fabbrica statica, singleton (è un anti-pattern nella maggior parte dei casi ma è valida come una classe statica) o solo una proprietà statica.

8

Si potrebbe archiviare il TargetMethod come un delegato, che una sottoclasse potrebbe cambiare se necessario:

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

Dato che questi sono casi statiche, anche se - il _targetMethod è condiviso tra tutte le istanze - trasformandolo in TestChild lo cambia per TestBase pure. Potresti o non potresti preoccupartene. Se lo fai, generici o un Dictionary<Type, Action> potrebbe aiutare.

Nel complesso, tuttavia, avresti un tempo molto più semplice se non insistessi sulla statica, o forse usassi la composizione invece dell'ereditarietà.

2

Se stai cercando di fare metodi statici astratti, allora questo funziona, e risulta essere la soluzione più facile per me adattarmi a:

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

ma sono ancora marcando Stafan come la soluzione perché usando l'ereditarietà dell'istanza è probabilmente la migliore raccomandazione per chiunque si trovi in ​​una situazione simile. Ma dovrei semplicemente riscrivere troppi codici per questo.

2

approvazione qui è quello che ho fatto

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

Penso che questa sarà una soluzione praticabile per quello che si vuole fare senza rompere troppi principi puristi OO.

Problemi correlati