2010-02-11 11 views
5

Lo que quiero lograr es lo siguiente: Tengo una propiedad declarada en la BaseClass. Si se accede a esta propiedad mediante el puntero de la clase base, solo el getter debe estar disponible, pero si se utiliza el puntero de clase derivado, quiero poder obtener y establecer la propiedad. Entonces el intellisense ni siquiera debería mostrar un setter para el puntero base.Hacer una propiedad de solo lectura que se pueda escribir en la clase derivada

public class BaseClass 
{ 
    public virtual int MyProperty 
    { 
     get { return 1; } 
     set {;}//This would show the setter in Intellisense 
    } 
} 

public class DerivedClass : BaseClass 
{ 
    int intValue; 

    public override int MyProperty 
    { 
     set { intValue = value;} 
    } 
} 

Un ejemplo realista:
Considérese una situación en la que usted tiene una clase de padres e hijos derivada de la clase Persona. Imagine una propiedad -RestrictionLevel, donde ambos pueden leerla, pero solo el padre puede establecer el valor. ¿Hay una mejor manera de diseñar esta situación?

+0

Enlace cruzado: http://stackoverflow.com/questions/1489361/override-abstract-readonly-property-to-read-write-property – Mikhail

+0

Just needed to this para detener una referencia readlyly a un objeto que se actualiza indirectamente . Gracias por preguntar las preguntas antes de necesitar la respuesta. –

Respuesta

0

No es posible (AFAIK). Sería confuso de todos modos. ¿Alguna razón en particular por la que quieres hacer esto?

+0

@silky Bueno, quiero evitar que el código del cliente lo establezca en un puntero base, pero solo en el puntero derivado. Proporcionar un setter vacío conseguiría el propósito, pero preferiría proporcionar un error de tiempo de compilación si se intenta establecerlo en el puntero base – alwayslearning

+0

@alwayslearning: Me pregunto qué tipo de estructura sugeriría tal requisito. No parece natural; pero podría estar equivocado. ¿Puede explicar el caso exacto del que está hablando? –

+0

actualizó la pregunta con un caso de uso – alwayslearning

9

La única manera en que podía pensar es que la sombra de la propiedad con una nueva:

public class DerivedClass : BaseClass 
{ 
    int intValue; 

    public new int MyProperty 
    { 
     get { return intValue; } 
     set { intValue = value; } 
    } 
} 

Aviso cómo la propiedad se declara new en lugar de override. Esto significa, por supuesto, que MyProperty del tipo DerivedClass no tiene nada que ver con MyProperty del tipo , es una propiedad completamente nueva que tiene el mismo nombre (por lo tanto, oculta la de la clase base).

El resultado es este:

DerivedClass d = new DerivedClass(); 
d.MyProperty = 42; 

BaseClass b = new DerivedClass(); 
b.MyProperty = 42; /* compilation error: Property or indexer 
              'TheNamespace.BaseClass.MyProperty' 
              cannot be assigned to -- it is 
              read only */ 

También, como estados @silky en el comentario:

(aunque yo sugiero que lo hace, y el padre , se refieren a la misma variable a evite una situación muy confusa) pero Realmente no creo que esto sea sea apropiado.

... es posible que desee que la nueva propiedad acceda a la de la clase base (a través de base.MyProperty, completada con un setter protegido). Considere lo siguiente, por ejemplo:

DerivedClass d = new DerivedClass(); 
d.MyProperty = 42; 

BaseClass b = d; 
Console.WriteLine(b.MyProperty); // prints 1 

Dicho esto, siempre me siento un poco sucio cuando se utiliza new (que, cuando pienso en ello, no estoy seguro de que realmente he hecho en código de producción).

actualización
Dado el escenario de ejemplo que das (que interpreto de una manera que un Parent es ser capaz de establecer el RestrictionLevel de un Child), que podría resolverse de esta manera:

public enum RestrictionLevel 
{ 
    Low, 
    Medium, 
    Grounded 
} 

public class Person 
{ 
    public RestrictionLevel RestrictionLevel { get; private set; } 
    protected static void SetRestrictionLevelInternal(Person person, RestrictionLevel restrictionLevel) 
    { 
     person.RestrictionLevel = restrictionLevel; 
    } 
} 

public class Child : Person { } 

public class Parent : Person 
{ 
    public void SetRestrictionLevel(Child child, RestrictionLevel restrictionLevel) 
    { 
     SetRestrictionLevelInternal(child, restrictionLevel); 
    } 
} 

Esto significa que el código siguiente es válido:

Child c = new Child(); 
Parent p = new Parent(); 
p.SetRestrictionLevel(c, RestrictionLevel.Grounded); 

...pero éste no es:

Child c = new Child(); 
c.SetRestrictionLevel(c, RestrictionLevel.Low); 

El método SetRestrictionLevelInternal se puede llamar desde dentro cualquier tipo descendiente (incluyendo Child), pero no se puede invocar desde fuera del tipo en sí. Por lo tanto, no puede invocar SetRestrictionLevelInternal en una instancia Parent. En el ejemplo anterior, elegimos exponer un método public, que a su vez invoca el método protected.

+0

Voy a recomendar esto como una 'solución' (aunque sugiero que lo haga, y el padre, consulte la misma variable para evitar una situación muy confusa) pero realmente no lo hago Creo que esto sería apropiado. –

+0

@silky: buenos puntos; los incluyó en la respuesta. –

+0

Una buena respuesta, no es algo que haya encontrado –

4

programa a una interfaz, no una implementación:

public interface IFoo 
{ 
    int MyProp { get; } 
} 

public interface IFooWithSetter 
{ 
    int MyProp { get; set; } 
} 

public class FooImplementation : IFoo, IFooWithSetter 
{ 
    public int MyProp 
    { 
     get { return 100; } 
     set { } 
    } 
} 

Ejemplo de uso:

IFoo var1 = new FooImplementation(); // only getter is available in var1 
IFooWithSetter var2 = (IFooWithSetter) var1; // setter and getter is available in var2 

puede utilizar simplemente algunos modificadores privados para las interfaces con diferentes contratos. Esta solución es simple y la OMI es ideal para su tarea.
Y si crees que será fácil hacer algunas acciones que intentas ocultar/restringir, tienes razón. Y lo mismo es con cualquier forma posible.

Cuestiones relacionadas