toma sobreescritura sobrecarga programacion para orientada objetos ninguna metodos metodo herencia ejemplo constructores argumentos c# constructor

c# - sobreescritura - ¿Cómo puedo hacer que un constructor sobrecargado llame tanto al constructor predeterminado como a una sobrecarga del constructor base?



sobrecarga de metodos en programacion orientada a objetos (2)

Cree un método privado que asigne los valores predeterminados a todas sus propiedades y llámelos desde cada constructor por separado.

Tal vez la pregunta que he planteado no es la pregunta correcta, porque ya sé que la respuesta corta es "no se puede".

La situación

Tengo una clase base con un constructor sobrecargado que toma dos argumentos.

class Building { public BuildingType BuildingType { get; protected set; } public string Address { get; set; } public decimal Price { get; set; } public Building() { BuildingType = BuildingType.General; Address = "Unknown"; } public Building(string address, decimal price) : this() { Address = address; Price = price; } }

La clase está usando una enumeración

enum BuildingType { None, General, Office, Apartment }

Ahora quiero crear una clase secundaria Office que también tenga un constructor sobrecargado. Esta clase infantil agrega otra propiedad (Compañía). En esta clase, la propiedad BuildingType debería configurarse, por supuesto, en Office. Este es el código.

class Office : Building { public string Company { get; set; } public Office() { BuildingType = BuildingType.Office; } public Office(string address, decimal price, string company) : base(address, price) { Company = company; // BuildingType = BuildingType.Office; // Don''t wanna repeat statement } }

Lo que quiero y por qué

Quiero que el segundo constructor para la clase de Office ejecute tanto el constructor base(address, price) como el constructor predeterminado de la clase de Office. Quiero llamar al constructor base(address, price) para que no tenga que repetir la asignación de todas las propiedades de la clase base. Quiero llamar al constructor predeterminado de la clase de Office porque establece la propiedad BuildingType en BuildingType.Office.

Ahora sé que no puedo usar algo como esto.

public Office(string address, decimal price, string company) : base(address, price) this()

¿Estoy haciendo algo mal?

Me pregunto si hay algún problema con mi diseño que me haga querer llamar tanto a base (dirección, precio) como a esto (). ¿Tal vez no debería estar configurando el BuildingType en el constructor sino en otro lugar? Intenté introducir un campo para esto.

public BuildingType BuildingType = BuildingType.General;

Pero entonces no puedo hacer lo mismo en la clase infantil. Estaría ocultando el campo BuildingType en la clase base, así que tendría que usar el new operador en la clase secundaria. Intenté hacer que BuildingType en la clase base fuera virtual , pero un campo no puede convertirse en virtual.

Creando algo en el constructor base

En este ejemplo simple, los constructores predeterminados solo asignan valores predeterminados a algunas propiedades. Pero el constructor del edificio también podría estar creando una base para el edificio, mientras que el constructor predeterminado de Office podría crear un ... (no se puede pensar en algo, pero se entiende la idea). Por lo tanto, aún desea ejecutar ambos constructores predeterminados.

¿Estoy pensando en la dirección equivocada aquí?

Actualizar

Basado en las respuestas y los comentarios de Jon Skeet, aquí está mi nuevo código. Cambié el encadenamiento de constructores de menos específico a más específico. También agregué el BuildingType al constructor de la clase Building , hice que el constructor estuviera protegido e hice private setter.

enum BuildingType { None, General, Office, Apartment } class Building { private const string DefaultAddress = "Unknown"; public BuildingType BuildingType { get; private set; } public string Address { get; set; } public decimal Price { get; set; } #region Optional public constructors // Only needed if code other than subclass must // be able to create a Building instance. // But in that case, the class itself can be abstract public Building() : this(DefaultAddress, 0m) {} public Building(string address, decimal price) : this(BuildingType.General, address, price) {} #endregion protected Building(BuildingType buildingType) : this(buildingType, DefaultAddress, 0m) {} protected Building(BuildingType buildingType, string address, decimal price) { BuildingType = buildingType; Address = address; Price = price; } } class Office : Building { public string Company { get; set; } public Office() : this("Unknown Office", 0m, null) {} public Office(string address, decimal price, string company) : base(BuildingType.Office, address, price) { Company = company; } }

¿Puede (Jon Skeet u otra persona) comentar esta versión revisada del código?

Un problema (menor) que no se resuelve con esto es que el constructor predeterminado para la clase de Office aún necesita proporcionar una dirección predeterminada ( "Unknown Office" en el código anterior). Todavía preferiría dejar que el constructor de la clase base decida la dirección si no se especifica uno. Entonces este código todavía no hace exactamente lo que quiero.

Probablemente podría resolver eso al no usar el encadenamiento de constructores en la clase derivada, pero en lugar de eso, cada uno de sus constructores llama directamente al constructor base. Eso significaría que cambiaría el constructor predeterminado de la clase de Office a

public Office() : base(BuildingType.Office)

Eso funcionaría para este simple ejemplo, pero si hay algún método que me gustaría ejecutar en cada instanciación de una Office, tendría que llamar a todos los constructores. Es por eso que el encadenamiento de constructores me parece una mejor idea.


Su enfoque no es el convencional, lo que resolvería el problema. En lugar de hacer que el constructor más específico (el que tiene muchos parámetros) llame al sin parámetros, haga las cosas al revés: haga que el uno sin parámetros llame al otro, proporcionando los valores predeterminados. Esto normalmente lleva a que todos los constructores representen una barra en cada clase llamando a una "primaria" (posiblemente indirectamente, a través de otras) y que las llamadas al constructor "principal" hagan la llamada al constructor base.

class Office : Building { public string Company { get; set; } public Office() : this(null, 0m, null) { } public Office(string address, decimal price, string company) : base(address, price) { Company = company; BuildingType = BuildingType.Office; // Don''t wanna repeat statement } }

... y lo mismo en la clase base:

class Building { public BuildingType BuildingType { get; protected set; } public string Address { get; set; } public decimal Price { get; set; } public Building() : this("Unknown", 0m) { } public Building(string address, decimal price) { BuildingType = BuildingType.General; Address = address; Price = price; } }

(Consideraría seriamente hacer que el constructor de Building incluya también un parámetro BuildingType ).