public class MyClass
{
public object Prop1 { get; set; }
public object Prop2 { get; set; }
public object Prop3 { get; set; }
}
Supongamos que tengo un objeto myObject
de MyClass
y necesito para restablecer sus propiedades, ¿es mejor crear un nuevo objeto o reasignar cada propiedad? Suponga que no tengo ningún uso adicional con la instancia anterior.
myObject = new MyClass();
o
myObject.Prop1 = null;
myObject.Prop2 = null;
myObject.Prop3 = null;
c#
object-oriented
construction
Campanas
fuente
fuente
Suppose I have an object myObject of MyClass and I need to reset its properties
- Si es necesario restablecer las propiedades de su objeto o si es útil modelar el dominio del problema, ¿por qué no crear unreset()
método para MyClass? Vea la respuesta de HarrisonPaine a continuaciónRespuestas:
Instanciar un nuevo objeto siempre es mejor, entonces tiene 1 lugar para inicializar las propiedades (el constructor) y puede actualizarlo fácilmente.
Imagine que agrega una nueva propiedad a la clase, preferiría actualizar el constructor que agregar un nuevo método que también reinicialice todas las propiedades.
Ahora, hay casos en los que es posible que desee reutilizar un objeto, uno en el que una propiedad es muy costosa para reinicializar y desea conservarla. Sin embargo, esto sería más especializado, y tendría métodos especiales para reinicializar todas las demás propiedades. Todavía querrás crear un nuevo objeto a veces incluso para esta situación.
fuente
myObject = new MyClass(oldObject);
. Aunque esto implicaría una copia exacta del objeto original en una nueva instancia.new MyClass(oldObject)
es la mejor solución para los casos en que la inicialización es costosa.Definitivamente debería preferir crear un nuevo objeto en la gran mayoría de los casos. Problemas al reasignar todas las propiedades:
A
y claseB
son instancias pasadas de clase,C
entonces deben saber si alguna vez pasarán la misma instancia, y si es así, si la otra todavía la está usando. Esto une estrechamente las clases que de otra manera no tendrían razón de ser.Fraction
clase con un numerador y un denominador, y quisiste exigir que siempre se redujera (es decir, el mcd del numerador y el denominador era 1). Esto es imposible de hacer bien si desea permitir que las personas establezcan públicamente el numerador y el denominador, ya que pueden pasar de un estado no válido a otro para pasar de un estado válido a otro. Por ejemplo, 1/2 (válido) -> 2/2 (inválido) -> 2/3 (válido).Todos estos son problemas bastante significativos. Y lo que obtienes a cambio del trabajo extra que creas es ... nada. La creación de instancias de objetos es, en general, increíblemente barata, por lo que el beneficio de rendimiento casi siempre será totalmente insignificante.
Como se mencionó en la otra respuesta, el único momento en que el rendimiento podría ser una preocupación relevante es si su clase realiza un trabajo significativamente costoso en la construcción. Pero incluso en ese caso, para que esta técnica funcione, deberá poder separar la parte costosa de las propiedades que está restableciendo, por lo que podrá usar el patrón de peso mosca o similar en su lugar.
Como nota al margen, algunos de los problemas anteriores podrían mitigarse un poco al no usar setters y en su lugar tener un
public Reset
método en su clase que tome los mismos parámetros que el constructor. Si por alguna razón quisieras seguir esta ruta de reinicio, probablemente sería una forma mucho mejor de hacerlo.Aún así, la complejidad y la repetición adicionales que se suman, junto con los puntos anteriores que no aborda, siguen siendo un argumento muy persuasivo en contra de hacerlo, especialmente cuando se comparan con los beneficios inexistentes.
fuente
Dado el ejemplo muy genérico, es difícil saberlo. Si "restablecer las propiedades" tiene sentido semántico en el caso del dominio, tendrá más sentido para el consumidor de su clase llamar
Que
NUNCA requeriría que el consumidor de su clase llame
Si la clase representa algo que se puede restablecer, debería exponer esa funcionalidad a través de un
Reset()
método, en lugar de depender de llamar al constructor o establecer manualmente sus propiedades.fuente
Como sugieren Harrison Paine y Brandin, reutilizaría el mismo objeto y factorizaría la inicialización de las propiedades en un método Reset:
fuente
Si el patrón de uso previsto para una clase es que un solo propietario mantendrá una referencia a cada instancia, ningún otro código conservará copias de las referencias, y será muy común que los propietarios tengan bucles que necesitan, muchas veces , " complete "una instancia en blanco, úsela temporalmente y nunca la vuelva a necesitar (una clase común que cumpla ese criterio sería
StringBuilder
), entonces puede ser útil desde el punto de vista del rendimiento para que la clase incluya un método para restablecer una instancia a like- Nueva condición. Es probable que tal optimización no valga mucho si la alternativa solo requiere la creación de unos cientos de instancias, pero el costo de crear millones o miles de millones de instancias de objetos puede sumar.En una nota relacionada, hay algunos patrones que se pueden usar para los métodos que necesitan devolver datos en un objeto:
El método crea un nuevo objeto; devuelve referencia.
El método acepta una referencia a un objeto mutable y lo completa.
El método acepta una variable de tipo de referencia como
ref
parámetro y utiliza el objeto existente si es adecuado o cambia la variable para identificar un nuevo objeto.El primer enfoque es a menudo el más fácil semánticamente. El segundo es un poco incómodo en el lado de la llamada, pero puede ofrecer un mejor rendimiento si la persona que llama con frecuencia podrá crear un objeto y usarlo miles de veces. El tercer enfoque es un poco semántico incómodo, pero puede ser útil si un método necesita devolver datos en una matriz y la persona que llama no sabrá el tamaño de matriz requerido. Si el código de llamada contiene la única referencia a la matriz, reescribir esa referencia con una referencia a una matriz más grande será semánticamente equivalente a simplemente agrandar la matriz (que es el comportamiento semántico deseado). Si bien el uso
List<T>
puede ser mejor que el uso de una matriz redimensionada manualmente en muchos casos, las matrices de estructuras ofrecen una semántica mejor y un mejor rendimiento que las listas de estructuras.fuente
Creo que a la mayoría de las personas que responden a favor de crear un nuevo objeto les falta un escenario crítico: recolección de basura (GC). GC puede tener un verdadero rendimiento en aplicaciones que crean muchos objetos (juegos de pensamiento o aplicaciones científicas).
Digamos que tengo un árbol de expresión que representa una expresión matemática, donde en los nodos internos hay nodos de función (ADD, SUB, MUL, DIV), y los nodos hoja son nodos terminales (X, e, PI). Si mi clase de nodo tiene un método Evaluate (), es probable que recurra recursivamente a los hijos y recopile datos a través de un nodo de datos. Por lo menos, todos los nodos hoja necesitarán crear un objeto de Datos y luego esos pueden reutilizarse en el camino hacia el árbol hasta que se evalúe el valor final.
Ahora digamos que tengo miles de estos árboles y los evalúo en un bucle. Todos esos objetos de datos activarán un GC y causarán un impacto en el rendimiento, uno grande (hasta un 40% de pérdida de utilización de la CPU para algunas ejecuciones en mi aplicación; ejecuté un generador de perfiles para obtener los datos).
¿Una posible solución? Reutilice esos objetos de datos y solo llame a algunos .Reset () sobre ellos después de que haya terminado de usarlos. Los nodos hoja ya no llamarán 'nuevos datos ()', llamarán a algún método Factory que maneje el ciclo de vida del objeto.
Lo sé porque tengo una aplicación que ha afectado este problema y esto lo resolvió.
fuente