2009-05-14 20 views
27

Me preguntaba, ¿cuál es la forma preferida de construir un nuevo objeto en C#?¿Cuál es la forma preferida de construir objetos en C#? ¿Parámetros o propiedades del constructor?

Tome una clase Persona:

public class Person 
{ 
    private string name; 
    private int age; 

    //Omitted.. 
} 

debo crear a utilizar:

New Person("name", 24); 

o

New Person() { Name = "name", Age = 24 }; 

¿Es sólo una cuestión de gusto o hay un buen razón para usar uno sobre el otro?

Puedo imaginar que uno solo debe usar los campos requeridos en el constructor y los campos opcionales no como parámetros de constructor, sino mediante el uso de propiedades.

¿Estoy en lo cierto?

+2

Esta es efectivamente la versión de C# de http://stackoverflow.com/questions/830657 –

Respuesta

39

La forma preferida depende de su diseño.

Las propiedades del constructor son para los elementos que su objeto necesita para ser construidos correctamente. Es decir, las propiedades que debe tener el objeto para inicializarse deben estar en el constructor (normalmente no desea un objeto parcialmente inicializado después de llamar al constructor a menos que esté creando un patrón de fábrica o de constructor y el constructor está oculto de todos menos de la fábrica/constructor).

Los intializadores de propiedad son los mejores para configuración adicional después de un constructor que es requerido por su caso de uso particular pero no es necesario para que el objeto se considere inicializado.

Por ejemplo, podría tener un objeto que represente a una persona. Una persona necesita un nombre y una edad para inicializarse, pero la dirección en la que vive es una configuración opcional.Entonces, el nombre y la edad son parámetros de constructor, y la dirección es una propiedad de lectura/escritura.

Person johnDoe = new Person("John Doe", 24) { Address = "42 Adams Street" }; 
+0

es una muy buena justificación que ayuda a discernir cuándo aplicar qué. ¡Gracias! – Peterdk

+0

También recomiendo leer la respuesta de Marc Gravell (http://stackoverflow.com/a/863064/23234), que proporciona algunos escenarios alternativos que miran los usos reales donde el punto de vista más ideal que presenté no es relevante debido a otras limitaciones. –

2

La segunda forma es simplemente azúcar sintáctico para establecer las propiedades de forma manual:

Person p = new Person(); 
p.Name = "name"; 
p.Age = 24; 

También no está en función de la constructora que puede no inicializar todas las propiedades que desea establecer.

Si su clase tiene un constructor que requiere estos dos parámetros, no moverse a llamar explícitamente a ese constructor.

12

Realmente depende del escenario. El enfoque de propiedad tiene mucha conveniencia, ya que no es necesario duplicar las asignaciones en el constructor. Además, a la mayoría de los escenarios vinculantes de datos les gusta poder crear objetos nuevos, para lo cual generalmente usan el constructor sin parámetros, por lo que es una gran ventaja.

Sin embargo, para los tipos inmutables, el enfoque de constructor es la única opción sensata. Curiosamente (tal vez) los parámetros nombrados/opcionales en C# 4.0 permiten algo similar a los initabilizadores de objetos para tipos inmutables: see here.

El enfoque de constructor también es muy popular para los marcos de Inversión de control, ya que anuncia claramente qué necesita esa clase para funcionar.

Es posible que necesite mezclar y combinar, pero generalmente tiene más estilo de propiedad que el estilo de constructor.

+2

Sí, los campos de solo lectura solo se pueden establecer mediante código de constructor. – Dario

5

Configuración de los valores en el constructor, hace que esas propiedades obligatorio, así que esto significa que no puede crear una nueva instancia, sin ajustes de esas propiedades. En algunas situaciones esto es preferible, en otras situaciones esto no es preferible.

+0

Esto es cierto, aunque para las estructuras no puede, por supuesto, hacer que la configuración sea obligatoria. – Noldorin

+0

De hecho, pero eso se debe a que una estructura es un tipo de valor y siempre tiene un valor (predeterminado), incluso si no se inicializa. –

0

Mis principales consideraciones sobre esta cuestión son: 1) qué cantidad de datos que la entidad creación de instancias tener cuando se crea una instancia del objeto y 2) ¿Cómo encapsulado que hace la clase tiene que ser? Si, una vez configuradas, las propiedades no pueden cambiar (al menos, debido a entidades externas) entonces usaría el constructor, ya que el constructor puede establecer cualquier propiedad de solo lectura así como cualquier propiedad de lectura/escritura.

Asimismo, recuerda que, al igual que cualquier otro método, el constructor puede sobrecargarse, por lo que puede crear cualquier número de formas de inicializar esas propiedades.

En general, uso constructores, pero a veces establezco las propiedades manualmente. Use la herramienta correcta para el problema correcto.

7

Siempre trabajo sobre la base de que debe pasar valores a un constructor que son obligatorios para que ese objeto exista en un estado válido.

En su ejemplo, podría decir que una persona nueva no puede existir sin una edad, por lo que debe pasarse al contructor.

Si trabaja sobre la base de que un objeto debe modelar una entidad de trabajo real, entonces eso determina el mínimo necesario para hacer que un objeto sea válido, ya sea que los establezca como valores predeterminados o ingrese valores mediante el constructor.

+1

+1: Los objetos siempre deben dejarse en un estado válido después de la construcción y después de cada llamada al método, de modo que los métodos no tengan que validar el estado de su propio objeto antes de ejecutar, solo sus argumentos. – palm3D

2

En mi opinión, primero debe decidir qué hace a una persona una persona. ¿Cuáles son las propiedades de la persona para que una persona se convierta en una instancia correcta? ¿Cuáles son los requisitos mínimos para una persona?

Siempre debe haber un constructor con los requisitos mínimos.

Solo utilizaría los inicializadores de objetos para los tipos que no requieren ninguna propiedad para crear una instancia. De ahí el constructor predeterminado.

Sé que los inicializadores de objetos son muy convenientes. Otros mecanismos también pueden requerir un constructor vacío en el objeto.

Pero no creo que tenga mucho sentido que pueda crear una Persona sin nombre.

4

Unos pocos pensamientos:

  1. Se necesitan propiedades públicas a utilizar inicializadores de objeto. Entonces, si hay algo que no quieres exponer, debes inicializarlos por parámetro de constructor.

  2. Si marca IL, verá que Object Initializer no es "atómico". Si se escribe código como este (no es que yo recomiendo, sólo un ejemplo):

    using (p = New Person() {Name = GetName(), Age = GetAge()}) 
    { 
        //blah, blah 
    } 
    

    Si hay una excepción en GetAge(), va a crear una instancia de Person en un estado corrupto. Peor aún, nunca puede ingresar el ámbito de uso y esa instancia no se eliminará como se imaginaría.

+0

Me gusta que hayas señalado que no es atómico. Obvio cuando lo veas, y no creo que escriba el código como lo has dicho, pero si estuviera leyendo el código de otra persona, no creo que lo haya captado. –

0

Para configurar las propiedades manualmente, tendrían que declararse públicas, y es posible que desee que los miembros de la clase sean privados. En cuyo caso, el constructor es el camino a seguir, o escribe métodos para obtenerlos/establecerlos o usar un descriptor de acceso.

0

Tiendo a preferir un constructor muy simple con intializadores de propiedades. Encuentro que conduce a un código más explícito. La única información que pasaría al constructor es información que no quiero que el usuario de mi clase modifique una vez que se crea la clase.

0

El verdadero problema surge cuando pasas el objeto por niveles/capas. Por ejemplo, usted crea un objeto personal y pasa a través de un servicio web. ¡El servicio web en algún punto intenta deserializar e intenta crear instancias y luego puede obtener un error si se requiere un parámetro para los constructores! ya que los servicios web primero crean un objeto y luego asignan valores.

Así que preferiría un contructor sin parámetros si se trata de un modelo de datos (tipo POCO) que debe pasar por niveles.

Por otras razones, el parámetro contructor es la mejor manera (para campos obligatorios). Especialmente cuando se proporciona la clase como una interfaz para objetos o conjuntos externos.

Cuestiones relacionadas