2010-04-30 9 views

Respuesta

3

Una forma de lograr esto sería para ir de una construcción 2 de fase y inicializar. Por lo que la construcción de los casos y luego llama a un método initialize la que invoca la clase base de inicialización en el orden apropiado

class MyBase 
{ 
    // Only if need to do some core initialization 
    public MyBase() 
    { 
    } 

    public virtual Initialize() 
    { 
    // do some initialization stuff here 
    } 
} 

class MyDerived : MyBase 
{ 
    // Only if need to do some core initialization 
    public MyDerived() 
    { 
    } 

    public override Initialize() 
    { 
    // do some initialization stuff here 

    // Call the base class initialization function 
    base.Initialize(); 
    } 
} 
+3

Si utiliza la función de crear/inicializar de dos pasos, lo haría aconseje usar un método de fábrica o Asbtract Factory para asegurar que la semántica de inicialización no se extienda por todo el código. – LBushkin

+0

Ok, eso no es exactamente lo que quise decir pero me ayuda a resolver el problema, ty –

0
class A : B 
{ 
    public A() : base() 
    { 
     base.doSomething(); 
    } 
} 

class B : C 
{ 
    public B() : base() 
    { 

    } 

    public void doSomething() { /* ... */ } 
} 

class C 
{ 
    public C() { /* ... */ } 
} 

orden de ejecución debe ser:

  1. C :: ctor()
  2. B :: ctor()
  3. A :: ctor()
  4. B :: doSomething ()
+0

Como dije, el método debe ejecutarse en la superclase, no en la subclase, solo está llamando al método de la superclase en la subclase. –

+0

Sospecho que OP está buscando una solución donde la clase base pueda garantizar que se ejecute cierta inicialización después de que el tipo esté completamente instanciado. De lo contrario, cada autor de clase derivado debe asegurarse de llamar a la lógica de inicialización necesaria. – LBushkin

+0

Eso es exactamente lo que necesito :( –

0

No estoy seguro de lo que quiere decir, ¿no puede simplemente llamar al código en la súper clase al final de nuestra última subclase? ¿estructor? Alternativamente, puede llamarlo directamente después de la creación de instancias.

class Program 
    { 
     static void Main(string[] args) 
     { 
      SubSub obj = new SubSub();     
      //obj.DoStuff(); 
      Console.ReadLine(); 
     } 
    } 

    class Super 
    { 
     public Super() 
     { 
      Console.WriteLine("Constructing Super"); 
     } 
     public void DoStuff() 
     { 
      Console.WriteLine("Doin' stuff"); 
     } 
    } 

    class Sub : Super 
    { 
     public Sub() 
     { 
      Console.WriteLine("Constructing Sub"); 
     } 
    } 

    class SubSub : Sub 
    { 
     public SubSub() 
     { 
      Console.WriteLine("Constructing SubSub"); 
      DoStuff(); 
     } 
    } 

Esta salida voluntad:

Constructing Super 
Constructing Sub 
Constructing SubSub 
Doin' stuff 
+0

Lo que quiero decir es que el código podría ejecutarse después de la construcción completa del objeto en la superclase, la subclase no debería saberlo. –

3

Se podría hacer lo siguiente, pero es arriesgado (ver mi Editar a continuación):

public class Parent 
{ 
    public Parent() 
    { 
     Initialize(); 
    } 

    protected virtual void Initialize() 
    { 
     // do stuff 
    } 
} 

public class Child : Parent 
{ 
    protected override void Initialize() 
    { 
     // do child stuff 
     base.Initialize(); 
    } 
} 

Editar

Como se sugiere en el comentario de Terrence más adelante, este es un enfoque arriesgado porque Initialize() se ejecutará antes de ejecutar Child 's constructor. Si hay campos inicializados en el constructor Child, no estarán listos si son utilizados por Initialize(). Esto podría causar errores confusos.

Una solución simple sería renunciar a la llamada principal Initialize() y en su lugar tener las clases secundarias llamar Initialize(). Como otros han sugerido, otra opción sería usar el patrón abstracto de fábrica.

Aquí es una solución simple que utiliza un método de fábrica estática:

class Program 
{ 
    static void Main() 
    { 
     Child.Create(() => new Child(5)); 
     Console.ReadKey(); 
    } 
} 

public abstract class Parent 
{ 
    protected virtual void Initialize() 
    { 
     Console.Write(" is the number."); 
    } 

    public static TChild Create<TChild>(Func<TChild> childGetter) 
     where TChild : Parent 
    { 
     var child = childGetter(); 
     child.Initialize(); 
     return child; 
    } 
} 

public class Child : Parent 
{ 
    private int _number; 

    public Child(int number) 
    { 
     _number = number; 
    } 

    protected override void Initialize() 
    { 
     Console.Write(_number.ToString()); 
     base.Initialize(); 
    } 
} 
+0

Esto viola la recomendación contra llamadas virtuales métodos de un constructor. Este método puede llevar a rastrear errores. Ver: http://blogs.msdn.com/b/scottwil/archive/2005/01/14/353177.aspx y http : //stackoverflow.com/questions/308061/virtual ization-in-super-class-constructor – Terrence

+0

@Terrence, gracias por su comentario. Actualizado mi respuesta. – devuxer

2

No hay nada integrado en el lenguaje C# que te permite hacer esto. Sin embargo, usar un patrón de creación podría soportarlo. Por ejemplo, el patrón Abstract Factory puede ser útil aquí. La fábrica base se aseguraría de que se invoque un método en la clase base recién creada una vez que se haya instanciado como el tipo de elemento secundario concreto.

+0

¿Sabes si Castle Windsor tiene algo así? –

+0

Esto es realmente más el dominio de una herramienta de AOP como PostSharp (que ahora me has recordado que debería haber sido incluida en mi respuesta), pero es posible que Windsor lo haga. Nunca intenté. – RationalGeek

Cuestiones relacionadas