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.

Author: Snæbjørn, 2011-02-11

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();
    }
}
 43
Author: Mark Byers,
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.

 9
Author: Mike Hofer,
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 de una manera más fácil y expresiva.

 2
Author: David,
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#.

 0
Author: Mohammad M. Ramezanpour,
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.

 0
Author: Theodore Zographos,
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