2010-06-18 1 views
5

No estoy seguro de por qué el operador new no está funcionando como esperaba.El nuevo operador en C# no está anulando el miembro de la clase base

Nota: Todas las clases siguientes están definidas en el mismo espacio de nombres y en el mismo archivo.

Esta clase le permite añadir un prefijo a cualquier contenido escrito en la consola con el texto provisto.

public class ConsoleWriter 
{ 
    private string prefix; 

    public ConsoleWriter(string prefix) 
    { 
     this.prefix = prefix; 
    } 

    public void Write(string text) 
    { 
     Console.WriteLine(String.Concat(prefix,text)); 
    } 
} 

Aquí es una clase base:

public class BaseClass 
{ 
    protected static ConsoleWriter consoleWriter = new ConsoleWriter(""); 

    public static void Write(string text) 
    { 
     consoleWriter.Write(text); 
    } 
} 

Aquí es una clase práctica:

public class NewClass : BaseClass 
{ 
    protected new static ConsoleWriter consoleWriter = new ConsoleWriter("> "); 
} 

Ahora aquí está el código para ejecutar este:

class Program 
{ 
    static void Main(string[] args) 
    { 
     BaseClass.Write("Hello World!"); 
     NewClass.Write("Hello World!"); 

     Console.Read(); 
    } 
} 
Así

I esperaría que la salida fuera

Hello World! 
> Hello World! 

Pero la salida es

Hello World! 
Hello World! 

No entiendo por qué ocurre esto. Aquí está mi proceso de pensamiento en cuanto a lo que está sucediendo:

  1. El CLR llama al método BaseClass.Write()
  2. El CLR inicializa el miembro de BaseClass.consoleWriter.
  3. El método se llama y ejecutados con el BaseClass.consoleWriter variable de

Entonces

  1. El CLR llama a la NewClass.Write()
  2. El CLR inicializa el objeto NewClass.consoleWriter.
  3. El CLR ve que la aplicación reside en BaseClass, pero el método se hereda a través
  4. El CLR ejecuta el método localmente (en NewClass) utilizando la variable

pensé que esta es la forma en la estructura NewClass.consoleWriter herencia ¿trabajos?

¿Alguien puede ayudarme a entender por qué esto no funciona?

-

Actualización:

Este escenario tendría las características siguientes (la forma en vez implementado)

public class LogBase 
{ 
    protected static TraceSource logger = new TraceSource(""); 

    public static void Error (string text) { logger.WriteError(text); } 
    public static void Info (string text) { logger.WriteInformation(text); } 
    public static void Warning (string text) { logger.WriteWarning(text); } 
    public static void Verbose (string text) { logger.WriteVerbose(text); } 
} 

// DataAccess logging 
public class DALog : LogBase 
{ 
    protected new static TraceSource logger = new TraceSource("DataAccess"); 
} 

// BusinessObjects logging 
public class BOLog : LogBase 
{ 
    protected new static TraceSource logger = new TraceSource("Objects"); 
} 

// BusinessLogic logging 
public class BLLog : LogBase 
{ 
    protected new static TraceSource logger = new TraceSource("Logic"); 
} 

// WebUI logging 
public class WebUILog : LogBase 
{ 
    protected new static TraceSource logger = new TraceSource("WebUI"); 
} 

La razón es que no tengo que duplicar el código de cada clase individual

-

Update (después de la solución elegida):

Así que con el fin de solucionar este problema, en lugar de utilizar clases de base, que define la funcionalidad de uno. Entonces creado nuevas clases, que llevan a cabo casos Singleton para cada capa:

public sealed class LogBase 
{ 
    private TraceSource logger = null; 

    public static LogBase GetLogger(string loggerName) 
    { 
     return new LogBase(loggerName); 
    } 

    private LogBase(string loggerName) { logger = new TraceSource(loggerName); } 

    public void Error (string text) { logger.WriteError(text); } 
    public void Info (string text) { logger.WriteInformation(text); } 
    public void Warning (string text) { logger.WriteWarning(text); } 
    public void Verbose (string text) { logger.WriteVerbose(text); } 
} 

// DataAccess logging - no base class 
public class DALog 
{ 
    private static LogBase logger; 

    public static LogBase Instance 
    { 
     get 
     { 
       if (logger==null) { logger = new TraceSource("DataAccess"); } 
       return logger; 
     } 
    } 
} 

... 

Respuesta

8

El operador new en realidad no anular en el sentido de polimorfismo. Simplemente agrega otro método que "pasa" a tener la misma firma y, sin embargo, se trata como un método separado. Solo si ejecuta ese método explícitamente en la subclase, se usará la implementación "nueva".

En su caso, ha implementado Write solo en la clase base. Allí, tienes la línea que llama al consoleWriter. Esa línea se refiere a la clase base y por lo tanto utiliza la implementación original. Ni siquiera sabe acerca de la implementación adicional en la subclase.

revisión de su código y lo consideran como sería:

public class BaseClass 
{ 
    protected static ConsoleWriter consoleWriter = new ConsoleWriter(""); 

    public static void Write(string text) 
    { 
     consoleWriter.Write(text); 
    } 
} 


public class NewClass : BaseClass 
{ 
    protected static ConsoleWriter anotherConsoleWriter = new ConsoleWriter(">"); 
} 

Su BaseClass.Write no alguna vez la posibilidad de llamar anotherConsoleWriter en lugar de consoleWriter.

si desea que su ejemplo funcione, ya sea necesario añadir una nueva aplicación para Write:

public class NewClass : BaseClass 
{ 
    protected new static ConsoleWriter consoleWriter = new ConsoleWriter(">"); 

    public static new void Write(string text) 
    { 
     consoleWriter.Write(text); 
    } 
} 

... o, lo que lo más probable es originalmente quería, en lugar introducir verdadera imperiosa de sentido del polimorfismo usando override en lugar de new. Sin embargo, su clase base debe admitir eso al declarar consoleWriter como virtual. Además (como mencionaste en tu comentario) esto solo funciona si no conviertes estos métodos en estáticos.

En su lugar, puede aplicar el Singleton pattern si aún desea tener acceso estático a sus registradores, o eche un vistazo al log4net que ya resolvió todos estos problemas por usted.

+0

No puedo declarar los métodos estáticos como virtuales. Tal vez debería devolver una instancia de la clase y luego llamar a métodos no estáticos para evitar este problema. –

+0

Sí, haz eso. Puede convertirlo en un singleton y seguir proporcionando una forma estática de acceder a él como: LogBase.GetLogger ("DataAccess"). Y luego casi está en la forma en que se ve en log4net, que es posible que desee echarle un vistazo. – chiccodoro

2

Le faltan algunos puntos cruciales ... Static lo convierte en un campo de nivel de clase. Protegido significa que está disponible a partir de clases derivadas. Nuevo significa que está ocultando el miembro base.

¿Necesita que estas clases sean estáticas? Si no, puede hacer que el método Write sea virtual y anularlo en la clase derivada; base.Write (">" + texto);

+0

Quiero que sea estático porque puedo definir todos mis métodos en una clase base, que a su vez llama a un miembro estático (en la implementación real es un TraceSource). Por lo tanto, lo único que tengo que cambiar con respecto a mis clases base heredadas es la implementación anulada. Actualizaré la pregunta. –

1

Usted sabe que la herencia y la anulación funciona para métodos de instancia (virtuales), no estáticos, ¿no?

Su sustitución es protected y por lo tanto no visible fuera de su NewClass y descendientes. Por lo tanto, el comportamiento es por especificación. new solo le permite crear una nueva función a la que se puede hacer referencia mediante el mismo identificador en su contexto: su método NewClass.Write realmente no tiene nada que ver con su BaseClass.Write.

+0

Gracias Pontus. Todas las palabras clave fueron elegidas para un propósito específico, sin embargo, ahora entiendo que fueron incorrectas. He aquí por qué: 'protected' fue porque solo quería subclases para ver al miembro, para anularlo. 'nuevo' porque quería que el método utilizara la versión anulada. Y 'estático' ya que el miembro iba a ser usado junto con métodos estáticos (por conveniencia realmente, en vez de tener que 'actualizarlo' cada vez). Pero como hemos visto aquí, los miembros estáticos y los métodos NO se heredan. –

Cuestiones relacionadas