Establecer propiedades mediante inicialización de objetos o no: ¿Alguna diferencia?
Aquí hay una pregunta simple: ¿Hay alguna diferencia (de rendimiento) entre esto:
Person person = new Person()
{
Name = "Philippe",
Mail = "[email protected]",
};
Y esto
Person person = new Person();
person.Name = "Philippe";
person.Mail = "[email protected]";
Puede imaginar un objeto más grande con más propiedades.
5 answers
Son casi exactamente equivalentes excepto que el primer método (usando un inicializador de objetos ) solo funciona en C# 3.0 y versiones posteriores. Cualquier diferencia de rendimiento es solo menor y no vale la pena preocuparse.
Producen código IL casi idéntico. La primera da esto:
.method private hidebysig instance void ObjectInitializer() cil managed
{
.maxstack 2
.locals init (
[0] class Person person,
[1] class Person <>g__initLocal0)
L_0000: newobj instance void Person::.ctor()
L_0005: stloc.1
L_0006: ldloc.1
L_0007: ldstr "Philippe"
L_000c: callvirt instance void Person::set_Name(string)
L_0011: ldloc.1
L_0012: ldstr "[email protected]"
L_0017: callvirt instance void Person::set_Mail(string)
L_001c: ldloc.1
L_001d: stloc.0
L_001e: ldloc.0
L_001f: callvirt instance string [mscorlib]System.Object::ToString()
L_0024: pop
L_0025: ret
}
El segundo da esto:
.method private hidebysig instance void SetProperties() cil managed
{
.maxstack 2
.locals init (
[0] class Person person)
L_0000: newobj instance void Person::.ctor()
L_0005: stloc.0
L_0006: ldloc.0
L_0007: ldstr "Philippe"
L_000c: callvirt instance void Person::set_Name(string)
L_0011: ldloc.0
L_0012: ldstr "[email protected]"
L_0017: callvirt instance void Person::set_Mail(string)
L_001c: ldloc.0
L_001d: callvirt instance string [mscorlib]System.Object::ToString()
L_0022: pop
L_0023: ret
}
Como puede ver, se genera un código casi idéntico. Vea a continuación el código exacto de C# que compilé.
Las mediciones de rendimiento muestran muy similares resultados con una mejora de rendimiento muy pequeña para usar la sintaxis del inicializador de objetos:
Method Iterations per second ObjectInitializer 8.8 million SetProperties 8.6 million
Código que utilicé para probar el rendimiento:
using System;
class Person
{
public string Name { get; set; }
public string Mail { get; set; }
}
class Program
{
private void ObjectInitializer()
{
Person person = new Person()
{
Name = "Philippe",
Mail = "[email protected]",
};
person.ToString();
}
private void SetProperties()
{
Person person = new Person();
person.Name = "Philippe";
person.Mail = "[email protected]";
person.ToString();
}
private const int repetitions = 100000000;
private void Time(Action action)
{
DateTime start = DateTime.UtcNow;
for (int i = 0; i < repetitions; ++i)
{
action();
}
DateTime end = DateTime.UtcNow;
Console.WriteLine(repetitions / (end - start).TotalSeconds);
}
private void Run()
{
Time(ObjectInitializer);
Time(SetProperties);
Console.WriteLine("Finished");
Console.ReadLine();
}
private static void Main()
{
new Program().Run();
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-11 20:31:56
Una cosa adicional que vale la pena señalar es esta:
Si no puede manejar una excepción en su constructor, obtendrá una excepción TypeInitializationException. Si bien eso puede no parecer tan malo, la verdad es que oculta la verdadera causa del problema y hace que sea más difícil de rastrear.
Si, por otro lado, usas un inicializador de objeto , estás invocando cada propiedad individualmente fuera del constructor, y cualquier excepción lanzada será muy clara y muy evidente: no serán enmascarados por la excepción TypeInitializationException.
En general, es una mala idea lanzar excepciones en un constructor. Si desea evitar ese escenario, vaya con el inicializador.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-11 21:13:16
Como otros han dicho, no, no hay diferencia. Tenga en cuenta que el primer ejemplo en realidad no está utilizando un constructor para esos argumentos. Está utilizando la función de lenguaje "inicializador de objetos" introducida en C# 3.0. El constructor que se llama es el constructor sin parámetros por defecto al igual que el segundo ejemplo.
Los dos ejemplos compilan el mismo código IL y hacen exactamente lo mismo. El primer ejemplo es solo azúcar sintáctica para llevar a cabo la tarea
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-11 20:11:49
No. La primera forma es nueva en. NET 3.5, pero el segundo ejemplo es para versiones anteriores de C#.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-11 20:04:02
En cuanto al rendimiento, no hay diferencia significativa, como han demostrado otras respuestas.
Sin embargo, crear un objeto usando un inicializador con 2 parámetros me parece como si dijera su intención a cualquiera que lo esté usando, formando un "contrato" diciendo: "estos 2 parámetros son el mínimo para la funcionalidad de la clase" (aunque la forma correcta de expresar esa intención sería usar un constructor).
Tiendo a pensar en la sintaxis del inicializador de esta manera, aunque es más o menos azúcar sintáctica. Uso una mezcla de ambas sintaxis en mi código. Pero de nuevo, ese es mi estilo personal.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-09 10:35:20