¿Deberíamos siempre incluir un constructor predeterminado en la clase?

Un colega me ha hecho esta pregunta, ¿deberíamos incluir siempre un constructor predeterminado en una clase? Si es así, ¿por qué? Si no, ¿por qué no?

Ejemplo

public class Foo { Foo() { } Foo(int x, int y) { ... } } 

También estoy interesado en obtener algunas luces sobre esto de expertos.

Debe tener en cuenta que si no proporciona un constructor sobrecargado, el comstackdor generará un constructor predeterminado para usted. Eso significa, si solo tienes

 public class Foo { } 

El comstackdor generará esto como:

 public class Foo { public Foo() { } } 

Sin embargo, tan pronto como agregue el otro constructor

 public class Foo { public Foo(int x, int y) { // ... } } 

El comstackdor ya no generará automáticamente el constructor predeterminado para usted. Si la clase ya se estaba utilizando en otro código que dependía de la presencia de un constructor predeterminado, Foo f = new Foo(); , ese código ahora se romperá.

Si no desea que alguien pueda inicializar la clase sin proporcionar datos, debe crear un constructor predeterminado que sea private para que sea explícito sobre el hecho de que está impidiendo que las instancias se construyan sin datos de entrada.

Sin embargo, hay veces en que es necesario proporcionar un constructor predeterminado (ya sea público o privado). Como se mencionó anteriormente, algunos tipos de serialización requieren un constructor predeterminado. También hay momentos en que una clase tiene múltiples constructores parametrizados pero también requiere inicialización de “nivel inferior”, en cuyo caso se puede usar un constructor predeterminado privado que está encadenado desde los constructores parametrizados.

 public class Foo { private Foo() { // do some low level initialization here } public Foo(int x, int y) : this() { // ... } public Foo(int x, int y, int z) : this() { // ... } } 

Algunas cosas (como la serialización) requieren un constructor predeterminado. Fuera de eso, sin embargo, un constructor predeterminado solo debe agregarse si tiene sentido.

Por ejemplo, si las propiedades Foo.X y Foo.Y son inmutables después de la construcción, entonces un constructor predeterminado no tiene sentido. Incluso si se utilizara para un Foo ‘vacío’, un acceso estático Empty sería más reconocible.

Yo diría que no , definitivamente no siempre . Supongamos que tiene una clase con algunos campos de solo lectura que deben inicializarse con algún valor, y no hay valores predeterminados razonables (o no quiere que exista). En este escenario, no creo que un constructor sin parámetros tenga sentido.

Tener un constructor predeterminado es solo una buena idea si tiene sentido tener dicho objeto.

Si produces un objeto que no está en un estado válido de dicho constructor, entonces lo único que puede hacer es introducir un error.

Como nota al margen, al usar struct en lugar de clase, tenga en cuenta que no hay forma de dejar el constructor predeterminado, ni es posible definirlo usted mismo, así que independientemente de los constructores que defina, asegúrese de que el estado predeterminado de la struct (cuando todas las variables se establecen en su estado predeterminado (generalmente 0 para los tipos de valor, y nulo para los tipos de referencia) no romperá su implementación de la estructura.

Sí. Es mejor tener un constructor predeterminado para evitar cualquier confusión. He visto personas que simplemente no hacen nada dentro de un constructor predeterminado (incluso en las propias clases de Microsoft), pero todavía les gusta mantenerlo ya que los objetos obtienen el valor predeterminado (tipo) automáticamente. Las clases que no especifiquen el constructor predeterminado, .NET, las agregarán automáticamente.

La serialización necesita un constructor predeterminado si utiliza los serializadores existentes, ya que tiene sentido para los serializadores de uso general, de lo contrario, debe crear su propia implementación.

En la mayoría de los casos, un constructor predeterminado es una buena idea. Pero ya que usas la palabra “siempre”, todo lo que se necesita es un contraejemplo. Si miras el Marco, encontrarás mucho. Por ejemplo, System.Web.HttpContext.

Un tipo genérico solo se puede instanciar con C # significa (sin reflexión) si tiene un constructor predeterminado. Además, se debe especificar la new() restricción de tipo genérico:

 void Construct() where T : new() { var t = new T(); ... } 

Llamar a este método utilizando un tipo como argumento de tipo genérico que no tiene un constructor predeterminado da como resultado un error de comstackción.