2010-01-08 9 views
64

Tengo una clase abstracta que define un get, pero no set, porque en lo que respecta a esa clase abstracta, solo necesita un get.Anular Obtener, pero no establecer

public abstract BaseClass 
{ 
    public abstract double MyPop 
    {get;} 
} 

Sin embargo, en algunos de la clase derivan, necesito una propiedad set, por lo que estoy buscando en esta implementación

public class DClass: BaseClass 
{ 
    public override double MyPop 
    {get;set;} 
} 

El problema es que tengo un error de compilación, diciendo que

* .set: no se puede anular porque *. no tiene un acceso de conjunto invalidable.

Aunque creo que la sintaxis anterior es perfectamente legítima.

¿Alguna idea de esto? ¿Solución temporal, o por qué es así?

Editar: El único enfoque que se me ocurre es poner tanto get y set como en la clase abstracta, y dejar que la subclase lanza una NotImplementedException si set se llama y no es necesario. Eso es algo que no me gusta, junto con un special setter method.

+0

Vamos a romper esto un poco. Necesita crear un conjunto de clases que exponga un método para leer un valor 'doble' que se implementará específicamente en cada clase. A veces, este valor tendrá que establecerse, por lo que algunas de estas clases deberían exponer una forma de establecer esto. ¿Es esto correcto? ¿Cuántos niveles de herencia necesita usar? – Codesleuth

+0

@Codesleuth: sí. En cuanto a cuántos niveles de herencia, no estoy seguro de cómo esto es relevante para la pregunta? – Graviton

+0

@David, irónicamente esto parece una pregunta para la que no quiero aceptar una respuesta. – Graviton

Respuesta

5

Nueva en C# 6.0:

Si sólo está llamando la incubadora dentro de su constructor, puede resolver este problema mediante las propiedades de sólo lectura.

void Main() 
{ 
    BaseClass demo = new DClass(3.6); 
} 

public abstract class BaseClass 
{ 
    public abstract double MyPop{ get; } 
} 

public class DClass : BaseClass 
{ 
    public override double MyPop { get; } 
    public DClass(double myPop) { MyPop = myPop;} 
} 
-2

¿Por qué no tener simplemente una propiedad en la clase base que tiene un colocador privado, luego en su subclase que necesita el colocador, anularlo y hacerlo público.

+5

descriptor de acceso abstracto * no puede * ser privado – Graviton

+0

el atributo 'privado' del' del 'del' del 'de la propiedad de' abstract' es 'protected'. Entonces, en la clase base, usted quiere: 'public abstract MyProp {get; conjunto protegido; } ' – JoeBrockhaus

-2

No puede anular el acceso del conjunto ya que la clase base no tiene un acceso de acceso definido.

Lo que puede hacer es utilizar la palabra clave new para ocultar la implementación de las clases base, pero eso puede no ser lo que desea.

+1

La clase base es abstracta y * no tiene implementación *, por lo tanto,' new' no puede funcionar. – Joey

+0

Para aclarar: Esto no funciona debido a que la clase derivada no implementa la propiedad abstracta. El comentario anterior puede haber sido ligeramente inexacto. – Joey

+0

Mi comentario también fue engañoso (sugirió que "nuevo" podría funcionar) así que lo eliminé. Aún así gracias por la actualización. –

-2

EDIT:

Aceptar que puede haber sido precipitada con esta respuesta, pero me he dado un poco más pensaba ahora.

¿Tienes que usar una clase base abstracta? Si no se requiere, intente esto:

public interface ISomeRelevantName 
{ 
    double MyPop { get; } 
} 

public class DClass : ISomeRelevantName 
{ 
    public double MyPop { get; set; } 
} 
+2

Se quejará de que la propiedad abstracta 'MyPop' de' BaseClass' no se implementa en la clase derivada. – Joey

+1

usando 'new' wont 'work, el código no puede compilar – Graviton

+0

Hmm, mi respuesta me avergüenza :(Estoy tratando de rectificar esto con una edición tho. – Codesleuth

23

Una respuesta posible sería la de sustituir el captador, y luego poner en práctica un método de selección por separado. Si no desea que el establecimiento de propiedades se defina en la base, no tiene muchas otras opciones.

public override double MyPop 
{ 
    get { return _myPop; } 
} 

public void SetMyPop(double value) 
{ 
    _myPop = value; 
} 
17

No es posible hacer lo que quiera. Debe definir el colocador en la propiedad abstracta; de lo contrario, no podrá sobrescribirlo correctamente.

El único caso que conozco en el que se define un captador y un captador/definidor se implementan es mediante el uso de una interfaz:

public interface IBaseInterface 
{ 
    double MyPop { get; } 
} 

public class DClass : IBaseInterface 
{ 
    public double MyPop { get; set; } 
} 
+8

No es un mal enfoque, pero a veces solo necesitas usar clase abstracta, no interfaz. – Graviton

0
public abstract class BaseClass 
{ 
    public abstract double MyPop { get; } 
} 

public class DClass: BaseClass 
{ 
    private double _myPop = 0; 
    public override double MyPop 
    { 
     get { return _myPop; } 
    } 

    // some other methods here that use the _myPop field 
} 

Si necesita establecer la propiedad desde fuera DClass entonces tal vez sería mejor poner al colocador en la clase base.

5

¿Estás seguro de que hacer lo que estás tratando de hacer sería un buen diseño si encuentras una forma de hacerlo?

Permitiría a los objetos de la subclase realizar cambios de estado que los objetos de la clase primaria no pueden realizar. ¿No violaría eso el Principio de Sustitución de Liskov?

2

se podría hacer algo como esto:

abstract class TestBase { public abstract int Int { get; } }

class TestDerivedHelper : TestBase 
{ 
    private int _Int; 
    public override int Int 
    { 
     get 
     { 
      return _Int; 
     } 
    } 

    protected void SetInt(int value) 
    { 
     this._Int = value; 
    } 
} 

class TestDerived : TestDerivedHelper 
{ 
    public new int Int 
    { 
     get { return base.Int; } 
     set { base.SetInt(value); } 
    } 
} 

Usando TestDerived tendrá la funcionalidad que está buscando. El único inconveniente que puedo ver de este método es que debe implementar todos los métodos abstractos en TestDerivedHelper, pero le da más control más adelante.

Espero que esto ayude. ;)

9

Si BaseClass es en su propia base de código, entonces usted puede hacer:

abstract public class BaseClass 
{ 
    abstract public double MyPop { get; protected set; } 
} 

public class DClass : BaseClass 
{ 
    private double _myProp; 
    public override double MyProp 
    { 
     get { return _myProp; } 
     protected set { _myProp = value; } 
    } 
} 

EDIT: A continuación, puede ir a hacer un método público en DCLASS SetMyProp(double myProp) o similares. El diseño de clase para su modelo de dominio debe ser claro o hablar por sí mismo por qué no puede establecer la propiedad directamente en la clase base y por qué puede hacerlo en la derivada.

+0

OK, pero ¿qué pasa con las subclases que no necesitan configurar el 'MyPop'? – Graviton

+0

Tal vez solo puedan derivarse de BaseClass y no de DClass? – herzmeister

+0

No creo que sea una buena idea para mis aplicaciones, la herencia debe reservarse para la relación 'is a', no para evitar una limitación de idioma, además de usar la herencia para otro propósito más realista en la aplicación aquí. – Graviton

1

asedio

abstract class TestBase 
{ 
    public abstract int Int { get; } 
} 

class TestDerivedHelper : TestBase 
{ 
    private int _Int; 
    public override int Int 
    { 
     get 
     { 
      return _Int; 
     } 
    } 

    protected void SetInt(int value) 
    { 
     this._Int = value; 
    } 
} 

class TestDerived : TestDerivedHelper 
{ 
    public new int Int 
    { 
     get { return base.Int; } 
     set { base.SetInt(value); } 
    } 
} 

Usando TestDerived tendrá la funcionalidad que está buscando. El único inconveniente que puedo ver en este método es que debe implementar cada método abstracto en TestDerivedHelper, pero le da más control más tarde.

Uso este enfoque y funciona muy bien para mí. Además, también hice mi resumen de clase "TestDerivedHelper", luego todos los métodos deben implementarse en la clase "TestDerived".

2

La razón por la que esto no es posible se debe a la forma en que los parámetros están "Magicked" a la existencia por C#. Cuando define un parámetro, C# crea un campo privado que manipulan el eliminador y el colocador implícitos. Si no hay un setter en la clase base, es imposible cambiar esta variable desde un método escrito en una subclase (ya que la bandera privada prohíbe que incluso las subclases accedan a ella). Lo que generalmente sucede es que usa el setter implícito de la clase base en su lugar.

No aconsejaría poner el conjunto en la clase base si no todas las subclases pueden hacerlo, porque esto va en contra de todo el principio de la programación polimórfica (cualquier método abstracto definido en la clase abstracta debe ser implementado por una subclase) Crear un método setter especial, como se describe en otras respuestas es probablemente la mejor manera de ir.

1

Aunque este hilo es viejo, estoy planteando mi solución, en caso de que ayude a alguien. No es mío, pero se basa en respuestas en otros temas SO.

public abstract BaseClass 
{ 
    public double MyPoP { get { return GetMyPoP; } } 

    protected abstract double GetMyPoP { get; } 
} 

public class DClass: BaseClass 
{ 
    public new double MyPoP { get; set; } 

    protected override double GetMyPop { get { return MyPoP; } } 
} 

Esta solución agrega una línea adicional de código para cada propiedad que necesita acceso modificado. Sin embargo, no hay cambios en la visibilidad externa y proporciona la funcionalidad necesaria.

Cuestiones relacionadas