2009-04-18 14 views
12

La herencia estática funciona igual que la herencia de instancias. Excepto que no está permitido hacer métodos estáticos virtuales o abstractos.C# métodos estáticos virtuales (o abstractos)

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

Esta es la salida:

Base class 
Child class 
Base class 
Base class 

Pero quiero:

Base class 
Child class 
Base class 
Child class 

Si pude sobre los métodos estáticos, lo haría TargetMethod virtual y que haría el trabajo. ¿Pero hay una solución alternativa para obtener el mismo efecto?

Editar: Sí, podría poner una copia de Operación en la clase secundaria, pero esto requeriría copiar y pegar una gran cantidad de código en cada niño, que en mi caso son alrededor de 35 clases, una pesadilla de mantenimiento.

+0

¿Por qué está utilizando funciones estáticas? – munificent

+0

Está confundiendo la herencia con búsqueda y ocultación de nombres. –

+0

Posible duplicado de [¿Por qué no puedo tener métodos estáticos abstractos en C#?] (Https://stackoverflow.com/questions/3284/why-cant-i-have-abstract-static-methods-in-c) –

Respuesta

12

No, no puede anular un método estático. "estático" también significa que está estáticamente enlazado por el compilador, por lo que el método real para llamar no se encuentra en el tiempo de ejecución, sino que está enlazado en tiempo de compilación.

Lo que debe hacer es hacer que la clase no sea estática. Haga que el método sea virtual y anule y aproveche al máximo la herencia real. Luego, si realmente lo necesita, cree un punto de entrada estático a una referencia de su clase. Por ejemplo, una fábrica estática, singleton (es un antipatrón en la mayoría de los casos pero es tan buena como una clase estática) o simplemente una propiedad estática.

8

Se puede almacenar el TargetMethod como delegado, lo que podría cambiar una subclase según sea necesario:

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

ya que estos son casos estáticos, sin embargo - la _targetMethod es compartida por todas las instancias - cambiándolo en TestChild lo cambia para TestBase también. Puede o no preocuparse por eso. Si lo hace, los genéricos o un Dictionary<Type, Action> podrían ayudar.

En general, sin embargo, tendrías un tiempo mucho más fácil si no insistieras en la estática, o quizás usaras la composición en lugar de la herencia.

2

Si usted está buscando para hacer los métodos estáticos abstractos, entonces esto funciona, y resulta ser la solución más fácil para mí para adaptarse 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"); 
    } 
} 

pero todavía estoy marcando Stafan como la solución porque el uso la herencia de instancias es probablemente la mejor recomendación para cualquier persona en una situación similar. Pero simplemente tendría que volver a escribir demasiado código para ello.

2

autorización aquí es lo que he hecho

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

Creo que esto será una solución viable para lo que quieres hacer sin romper demasiados principios puristas OO.

Cuestiones relacionadas