2010-09-11 17 views
54

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

Ejemplo

public class Foo { 

    Foo() { } 

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

} 

También estoy interesado en obtener algunas luces en esta parte de expertos.

+16

Como de costumbre, solo cuando es necesario. –

+0

Sí, también tengo curiosidad. Mi manager siempre me dice que es necesario para Reflection, pero no pude buscar nada al respecto, así que estoy un poco confundido. –

Respuesta

83

Debe tener en cuenta que si no proporciona un constructor sobrecargado, el compilador generará un constructor predeterminado para usted. Eso significa que, si sólo tiene

public class Foo 
{ 
} 

El compilador generará esto como:

public class Foo 
{ 
    public Foo() { } 
} 

Sin embargo, tan pronto como se agrega otro constructor

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

El compilador ya lo hará sin genere 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ía.

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

Hay veces, sin embargo, cuando 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() 
    { 
     // ... 
    } 
} 
+0

Creo que te faltan algunos modificadores 'públicos' (los miembros de la clase son 'privados' por defecto) ... –

+0

@Dan Tao: Sí, lo era. Gracias @Anthony Pegram por agregarlos para mí. –

+0

También no debería tener() después del nombre de la clase. Quítelos y tiene suficiente código que puede intentar compilar y ver que esta respuesta es incorrecta, e intentar usar el constructor predeterminado dará como resultado "'Foo' no contiene un constructor que tome '0' argumentos" . –

20

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 accesorio estático Empty sería más reconocible.

+1

La serialización no requiere un constructor predeterminado. Si tiene una clase que desea serializar, para la cual un constructor predeterminado no tiene sentido, implemente 'ISerializable' y agregue un constructor (' private' si está sellado, 'protected' en caso contrario) con la firma' ClassName (SerializationInfo info, contexto de StreamingContext) 'que refleja la implementación de' ISerializable.GetObjectData'. –

12

Yo diría 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.

+4

Totalmente de acuerdo. Las clases siempre se deben instanciar en un estado válido. Si tiene un ctor predeterminado y establece las propiedades después de la construcción, ¿cuándo es válida la instancia? Después de configurar algunas propiedades? Después de configurar todo? Quién sabe. – Cumbayah

0

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.

2

Sí, en general, en la mayoría de los casos, es mejor escribir el constructor predeterminado.

Generalmente, si no especifica ningún constructor,.NET crea automáticamente un constructor predeterminado para usted.

Necesidades de serialización Constructor predeterminado.

+0

La serialización no requiere un constructor predeterminado.Si tiene una clase que desea serializar, para la cual un constructor predeterminado no tiene sentido, implemente 'ISerializable' y agregue un constructor (' private' si está sellado, 'protected' en caso contrario) con la firma' ClassName (SerializationInfo info, contexto de StreamingContext) 'que refleja la implementación de' ISerializable.GetObjectData'. –

+0

Punto contado. En realidad, lo sé, pero en general la gente quiere ser simple. Pero agregaste un punto a la respuesta. Gracias. – abhishek

+0

Simplemente curioso, tengo una lista dentro de mi clase serializable. No agregué el constructor y obtuve una excepción nula. Cuando agregué el constructor e hice una instancia de mi lista dentro del constructor, funcionó bien. Solo curiosidad, ¿por qué la serialización necesitaría un constructor predeterminado en mi caso? –

4

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

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

1

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 que el estado predeterminado de la estructura (cuando todas las variables se establecen en su estado predeterminado (normalmente 0 para tipos de valor y nulo para tipos de referencia) no interrumpirá su implementación de la estructura.

0

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

void Construct<T>() 
    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 genera un error de compilación.

Cuestiones relacionadas