2011-09-20 31 views
5

Lamentablemente, no puedo encontrar el proyecto original que me llevó a esta pregunta. Eso quizás le hubiera dado a esta pregunta un poco más de contexto.Clase abstracta que hereda el tipo más derivado

EDIT: me encontré con el proyecto original que he visto esto en: http://mews.codeplex.com/SourceControl/changeset/view/63120#1054567 con una aplicación concreta en: http://mews.codeplex.com/SourceControl/changeset/view/63120#1054606

Digamos que tengo una clase abstracta con una aplicación concreta que hace algo útil como:

abstract class AbstractClass 
{ 
    public virtual int ConvertNumber(string number) 
    { 
     string preparedNumber = Prepare(number); 
     int result = StringToInt32(number); 
     return result; 
    } 

    protected abstract string Prepare(string number); 

    protected virtual int StringToInt32(string number) 
    { 
     return Convert.ToInt32(number); 
    } 
} 

sealed class ConcreteClass : AbstractClass 
{ 
    protected override string Prepare(string number) 
    { 
     return number.Trim(); 
    } 

    public override int ConvertNumber(string number) 
    { 
     return base.ConvertNumber(number); 
    } 
} 

Esto es tan básico como se puede. Ahora en el código que he visto en la web del autor implementado inheritence heredando la clase abstracta de la forma más derivada, por ejemplo:

abstract class AbstractGenericClass<TGenericClass> 
    where TGenericClass : AbstractGenericClass<TGenericClass> 
{ 
    public virtual int ConvertNumber(string number) 
    { 
     string preparedNumber = Prepare(number); 
     int result = StringToInt32(number); 
     return result; 
    } 

    protected abstract string Prepare(string number); 

    protected int StringToInt32(string number) 
    { 
     return Convert.ToInt32(number); 
    } 
} 

sealed class ConcreteGenericClass : AbstractGenericClass<ConcreteGenericClass> 
{ 
    protected override string Prepare(string number) 
    { 
     return number.Trim(); 
    } 

    public override int ConvertNumber(string number) 
    { 
     return base.ConvertNumber(number); 
    } 
} 

Ahora ¿por qué uno hacer tal cosa? Recuerdo muy vagamente que esta era una técnica muy usada en ATL por razones de rendimiento (¿alguna forma de llamar implementaciones concretas de miembros sin trabajar con un vtable?). No estoy muy seguro de esta parte.

He comprobado el IL generado para ambos casos y son exactamente iguales.

¿Quién me puede explicar esto?

+0

no creo que su primera sección del código se compila. 'public override int ConvertNumber (número de serie)' pero no hay ningún método para anular en el tipo base. –

+0

Supongo que no se hará así? http://pastebin.com/BgpuKYb7 – Zenwalker

+1

@DannyChen: su derecha, he cambiado el código un poco para el marcado, lo he arreglado ahora. La pregunta sigue en pie – Polity

Respuesta

4

Esa es una versión C# de lo que se llama el Patrón de Plantilla Curiosamente Recurrente en C++. Es un poco extraño, y personalmente, trato de evitarlo. Es útil, pero me resulta más confuso que útil.

Véase mi artículo para más detalles:

http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx

+0

Gracias Eric! Esto realmente estaba jugando con mi cerebro. Afortunadamente, su artículo lo explicó fuerte y claro. – Polity

+1

@Eric Lippert: me gusta este patrón para permitir que la clase antecesora tenga miembros que puedan usar/devolver instancias de clases descendientes. Esperaba que el código de ejemplo del OP tuviera dicho método o propiedad. Sin embargo, el único inconveniente es que puede romper el patrón si, por ejemplo, 'clase X: AbstractGenericClass ' y tiene 'clase Y: AbstractGenericClass '. Me encantaría que C# tuviera una restricción "this" para evitar esto, es decir, 'clase abstracta A donde T: this, A ' - tan pronto como declare una clase concreta, el parámetro genérico debe ser él mismo. ** empujar suavemente ** Eric. – Enigmativity

+0

@Enigmativity: De hecho, analizo la deficiencia que identifica en el artículo al que me he vinculado. Realmente necesitas una construcción de "este tipo" para que el patrón funcione. Puedes hacer ese tipo de cosas en Haskell pero no en C#; Hacerlo requeriría un trabajo bastante importante para el sistema de tipo CLR, por lo que es poco probable que suceda pronto. –

Cuestiones relacionadas