2012-05-24 12 views
6

Si quiero un constructor al que solo se puede acceder desde clases secundarias, puedo usar la palabra clave protected en el constructor.¿Cómo puedo hacer que un constructor solo sea accesible por clase base?

Ahora quiero lo contrario.

Mi clase niño debe tener un constructor que se puede acceder mediante su clase base, pero no de cualquier otra clase.

¿Esto es posible?

Este es mi código actual. el problema es que las clases secundarias tienen un constructor público.

public abstract class BaseClass 
{ 
    public static BaseClass CreateInstance(DataTable dataTable) 
    { 
     return new Child1(dataTable); 
    } 
    public static BaseClass CreateInstance(DataSet dataSet) 
    { 
     return new Child2(dataSet); 
    } 
} 

public class Child1 : BaseClass 
{ 
    public Child1(DataTable dataTable) 
    { 
    } 
} 

public class Child2 : BaseClass 
{ 
    public Child2(DataSet dataSet) 
    { 
    } 
} 
+4

No estoy seguro de que esto sea posible, una clase base que conozca clases de niños va en contra de mi comprensión de la herencia –

+1

@DanF Tienes razón, pero una clase 'BaseClassFactory' que sabe acerca de' Child1' y ' Child2' sería normal y tendría el mismo problema. – hvd

Respuesta

3

respuesta a la pregunta es "NO"

Existe tal cosa no existe en la programación orientada a objetos que permite al constructor de la clase infantil visible sólo a la base de la Clase de ella ...

+0

@Jon - su opción pero no la solución en la herencia multinivel ... considere ese caso también ... –

12

I cree que tiene dos opciones:

  1. Haga que el constructor hijo internal. Esto significa que será accesible desde todos los tipos en el mismo ensamblaje, pero eso debería ser suficiente en la mayoría de los casos.
  2. Hacer las clases hijo anidados en la clase base:

    public abstract class BaseClass 
    { 
        public static BaseClass CreateInstance(DataTable dataTable) 
        { 
         return new Child1(dataTable); 
        } 
    
        private Child1 : BaseClass 
        { 
         public Child1(DataTable dataTable) 
         { 
         } 
        } 
    } 
    

    De esta manera, BaseClass puede utilizar el constructor, pero ningún otro tipo de fuera puede hacer eso (o incluso ver la clase hija).

+3

+1 Para las clases anidadas –

+2

las clases anidadas solo serían visibles dentro de la BaseClass, ¿verdad? No estoy seguro de que esto sea lo que se pretende. –

+0

@lcfseth, sí, si los marca 'privados'. Y creo que esto es exactamente lo que se pretendía (tenga en cuenta que los métodos de fábrica devuelven 'BaseClass'). – svick

-1

Como dijo Pranay Rana, esto es imposible. Si puede explicar claramente por qué quiere esto, y por qué no es posible otra técnica, entonces tal vez el Microsoft C# designteam esté dispuesto a agregar esto en una versión futura de C#.

Sin embargo, el lenguaje C# (y muchos otros lenguajes orientados a objetos han existido desde hace muchos años sin que esta posibilidad.

+0

No veo cómo se puede hablar aquí de una posible versión futura de C#. – svick

3

Creo que acabo de resolver por mí mismo. Después de leer solución svicks con clases anidadas, pensé why not use an protected nested class as an argument?

nadie desde fuera es capaz de crear una instancia de Arg y los contructors públicos de mis clases niño sólo puede ser utilizado por BaseClass que puede crear Arg<T> casos.

public abstract class BaseClass 
{ 
    protected class Arg<T> 
    { 
     public T Value { get; set; } 
     public Arg(T value) { this.Value = value; } 
    } 

    public static BaseClass CreateInstance(DataTable dataTable) 
    { 
     return new Child1(new Arg<DataTable>(dataTable)); 
    } 

    public static BaseClass CreateInstance(DataSet dataSet) 
    { 
     return new Child2(new Arg<DataSet>(dataSet)); 
    } 
} 


public class Child1 : BaseClass 
{ 
    public Child1(Arg<DataTable> arg) : this(arg.Value) { } 
    private Child1(DataTable dataTable) 
    { 
    } 
} 

public class Child2 : BaseClass 
{ 
    public Child2(Arg<DataSet> arg) : this(arg.Value) { } 
    public Child2(DataSet dataSet) 
    { 
    } 
} 
+1

¿Cómo se protege esto contra 'Child2' al crear un 'Child1'? Pensé que querías protegerte incluso contra instancias erróneas en tu propia asamblea. (De lo contrario, la solución de un constructor interno es mucho más simple). – hvd

+0

En realidad, ¿C# incluso permite un tipo inaccesible en un constructor público? – hvd

+0

Tienes razón. Esto me da un error de tiempo de compilación. –

0

Se podría hacer cumplir el comportamiento deseado en tiempo de ejecución haciendo que el constructor base acepta un parámetro ref, y hacer algo similar (no-hilo):

private int myMagicCounter; 

public DerivedClass makeDerived(whatever) // A factory method 
{ 
    DerivedClass newThing; 
    try 
    { 
    ... do whatever preparation 
    newThing = new DerivedClass(ref myMagicCounter, whatever); 
    } 
    finally 
    { 
    ... do whatever cleanup 
    } 
    return newThing; 
} 

BaseClass(ref int magicCounter, whatever...) 
{ 
    if (magicCounter != myMagicCounter) 
    throw new InvalidOperationException(); 
    myMagicCounter++; 
    if (magicCounter != myMagicCounter) 
    throw new InvalidOperationException(); 
} 

Tenga en cuenta que no será posible para una llamada de constructor de la clase derivada de obtenga el control sin haber realizado la preparación del método de fábrica o para devolver el control a la persona que llama sin realizar la limpieza del método de fábrica. Sin embargo, no habrá nada para evitar que el constructor de la clase derivada pase su instancia parcialmente construida a un código externo que puede hacer lo que quiera con él durante un período de tiempo arbitrario antes de devolver el control al método de fábrica.

Cuestiones relacionadas