una tipos que programacion objetos llamar ejemplos crear constructores como clases clase c# java

c# - tipos - ¿Inicializar campos de clase en constructor o en declaración?



tipos de clases programacion (14)

He estado programando en C # y en Java recientemente y tengo curiosidad por saber cuál es el mejor lugar para inicializar mis campos de clase.

¿Debo hacerlo en declaración ?:

public class Dice { private int topFace = 1; private Random myRand = new Random(); public void Roll() { // ...... } }

¿O en un constructor ?:

public class Dice { private int topFace; private Random myRand; public Dice() { topFace = 1; myRand = new Random(); } public void Roll() { // ..... } }

Estoy realmente curioso de lo que algunos de ustedes veteranos creen que es la mejor práctica. Quiero ser consistente y apegarme a un enfoque.


¿Y si te lo dijera, depende?

En general lo inicializo todo y lo hago de manera consistente. Sí, es demasiado explícito, pero también es un poco más fácil de mantener.

Si nos preocupa el rendimiento, bueno, entonces inicializo solo lo que se debe hacer y lo coloco en las áreas que más le valen la pena.

En un sistema en tiempo real, me pregunto si incluso necesito la variable o la constante.

Y en C ++ a menudo hago casi sin inicialización en cualquier lugar y lo muevo a una función Init (). ¿Por qué? Bueno, en C ++, si está inicializando algo que puede generar una excepción durante la construcción del objeto, se abre a fugas de memoria.


Considere la situación en la que tiene más de un constructor. ¿Será la inicialización diferente para los diferentes constructores? Si serán iguales, ¿por qué repetir para cada constructor? Esto está en línea con la declaración de kokos, pero puede no estar relacionado con los parámetros. Digamos, por ejemplo, que desea mantener una bandera que muestra cómo se creó el objeto. Luego esa bandera se inicializaría de manera diferente para diferentes constructores, independientemente de los parámetros del constructor. Por otro lado, si repite la misma inicialización para cada constructor, deja la posibilidad de que (involuntariamente) cambie el parámetro de inicialización en algunos de los constructores, pero no en otros. Por lo tanto, el concepto básico aquí es que el código común debe tener una ubicación común y no ser repetido potencialmente en diferentes ubicaciones. Así que diría que siempre póngalo en la declaración hasta que tenga una situación específica en la que eso ya no funcione para usted.


Creo que hay una advertencia. Una vez cometí tal error: dentro de una clase derivada, intenté "inicializar en la declaración" los campos heredados de una clase base abstracta. El resultado fue que existían dos conjuntos de campos, uno es "base" y otro son los recientemente declarados, y me costó bastante tiempo depurarlos.

La lección: para inicializar campos heredados , lo harías dentro del constructor.


El diseño de C # sugiere que se prefiere la inicialización en línea, o no estaría en el idioma. En cualquier momento que pueda evitar una referencia cruzada entre diferentes lugares en el código, generalmente estará mejor.

También existe la cuestión de la coherencia con la inicialización de campo estático, que debe estar en línea para un mejor rendimiento. Las pautas de diseño de marco para el diseño del constructor dicen esto:

✓ CONSIDERE la inicialización de campos estáticos en línea en lugar de usar explícitamente constructores estáticos, porque el tiempo de ejecución puede optimizar el rendimiento de los tipos que no tienen un constructor estático definido explícitamente.

"Considerar" en este contexto significa hacerlo a menos que haya una buena razón para no hacerlo. En el caso de los campos de inicialización estáticos, una buena razón sería si la inicialización es demasiado compleja para ser codificada en línea.


En C # no importa. Los dos ejemplos de código que das son completamente equivalentes. En el primer ejemplo, el compilador de C # (¿o es el CLR?) Construirá un constructor vacío e inicializará las variables como si estuvieran en el constructor. Si ya existe un constructor, cualquier inicialización "arriba" se moverá a la parte superior de este.

En términos de mejores prácticas, el primero es menos propenso a errores que el segundo, ya que alguien podría agregar fácilmente otro constructor y olvidarse de encadenarlo.


En Java, un inicializador con la declaración significa que el campo siempre se inicializa de la misma manera, independientemente del constructor que se use (si tiene más de uno) o los parámetros de sus constructores (si tienen argumentos), aunque un constructor podría posteriormente Cambia el valor (si no es definitivo). Por lo tanto, el uso de un inicializador con una declaración sugiere a un lector que el valor inicializado es el valor que tiene el campo en todos los casos , independientemente de qué constructor se use e independientemente de los parámetros pasados ​​a cualquier constructor. Por lo tanto, use un inicializador con la declaración solo si, y siempre si, el valor para todos los objetos construidos es el mismo.


Hay muchas y diversas situaciones.

Solo necesito una lista vacía

La situación es clara. Solo necesito preparar mi lista y evitar que se lance una excepción cuando alguien agrega un elemento a la lista.

public class CsvFile { private List<CsvRow> lines = new List<CsvRow>(); public CsvFile() { } }

Conozco los valores

Sé exactamente qué valores quiero tener de forma predeterminada o necesito usar alguna otra lógica.

public class AdminTeam { private List<string> usernames; public AdminTeam() { usernames = new List<string>() {"usernameA", "usernameB"}; } }

o

public class AdminTeam { private List<string> usernames; public AdminTeam() { usernames = GetDefaultUsers(2); } }

Lista vacía con posibles valores.

A veces espero una lista vacía por defecto con la posibilidad de agregar valores a través de otro constructor.

public class AdminTeam { private List<string> usernames = new List<string>(); public AdminTeam() { } public AdminTeam(List<string> admins) { admins.ForEach(x => usernames.Add(x)); } }


Hay un ligero beneficio en el rendimiento al establecer el valor en la declaración. Si lo configura en el constructor, en realidad se configura dos veces (primero al valor predeterminado, luego se reinicia en el ctor).


La semántica de C # difiere ligeramente de Java aquí. En C #, la asignación en declaración se realiza antes de llamar al constructor de la superclase. En Java, se realiza inmediatamente después, lo que permite que se use ''esto'' (especialmente útil para clases internas anónimas), y significa que la semántica de las dos formas realmente coincide.

Si puedes, haz los campos finales.


Mis reglas:

  1. No inicialice con los valores predeterminados en la declaración ( null , false , 0 , 0.0 …).
  2. Prefiera la inicialización en la declaración si no tiene un parámetro de constructor que cambie el valor del campo.
  3. Si el valor del campo cambia debido a un parámetro de constructor, ponga la inicialización en los constructores.
  4. Sea consistente en su práctica (la regla más importante).

No es una respuesta directa a su pregunta sobre la mejor práctica, pero un punto de actualización importante y relacionado es que, en el caso de una definición de clase genérica, deje que el compilador se inicie con los valores predeterminados o tenemos que usar un método especial para inicializar los campos a sus valores predeterminados (si eso es absolutamente necesario para la legibilidad del código).

class MyGeneric<T> { T data; //T data = ""; // <-- ERROR //T data = 0; // <-- ERROR //T data = null; // <-- ERROR public MyGeneric() { // All of the above errors would be errors here in constructor as well } }

Y el método especial para inicializar un campo genérico a su valor predeterminado es el siguiente:

class MyGeneric<T> { T data = default(T); public MyGeneric() { // The same method can be used here in constructor } }


Normalmente intento que el constructor haga nada más que obtener las dependencias e inicializar con ellos los miembros de la instancia relacionada. Esto te hará la vida más fácil si quieres poner a prueba tus clases.

Si el valor que va a asignar a una variable de instancia no se ve influenciado por ninguno de los parámetros que va a pasarle al constructor, entonces asigne en el momento de la declaración.


Ser consistente es importante, pero esta es la pregunta que debe hacerse: "¿Tengo un constructor para algo más?"

Por lo general, estoy creando modelos para transferencias de datos que la clase en sí no hace nada, excepto trabajar como alojamiento para variables.

En estos escenarios, generalmente no tengo ningún método o constructor. Me parecería tonto crear un constructor con el único propósito de inicializar mis listas, especialmente porque puedo inicializarlas en línea con la declaración.

Como muchos otros han dicho, depende de su uso. Mantenlo simple, y no hagas nada extra que no tengas que hacer.


Suponiendo que el tipo en su ejemplo, definitivamente prefiere inicializar los campos en el constructor. Los casos excepcionales son:

  • Campos en clases / métodos estáticos
  • Campos tipificados como static / final / et al.

Siempre pienso que el campo que figura en la parte superior de una clase es la tabla de contenido (lo que se incluye en este documento, no cómo se usa) y el constructor como la introducción. Los métodos, por supuesto, son capítulos.