Domanda

Ecco una semplice domanda: c'è una differenza (performance) tra questa:

Person person = new Person()
{
  Name = "Philippe",
  Mail = "phil@phil.com",
};

e questo

Person person = new Person();
person.Name = "Philippe";
person.Mail = "phil@phil.com";

Puoi immaginare un oggetto più grande con più proprietà.

È stato utile?

Soluzione

Sono quasi esattamente equivalenti tranne che il primo metodo (usando un Inizializzatore dell'oggetto) funziona solo in C# 3.0 e più recenti. Qualsiasi differenza di prestazione è solo minore e non vale la pena preoccuparsi.

Producono un codice IL quasi identico. Il primo dà questo:

.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 "phil@phil.com"
    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 
}

Il secondo dà questo:

.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 "phil@phil.com"
    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 
}

Come puoi vedere, viene generato un codice quasi identico. Vedi sotto per il codice C# esatto che ho compilato.

Le misurazioni delle prestazioni mostrano risultati molto simili con un miglioramento delle prestazioni molto piccolo per l'utilizzo della sintassi dell'inizializzatore dell'oggetto:

Method               Iterations per second
ObjectInitializer    8.8 million
SetProperties        8.6 million

Codice che ho usato per testare le prestazioni:

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 = "phil@phil.com",
        };
        person.ToString();
    }

    private void SetProperties()
    {
        Person person = new Person();
        person.Name = "Philippe";
        person.Mail = "phil@phil.com";
        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();
    }
}

Altri suggerimenti

Un'ulteriore cosa che vale la pena notare è questa:

Se non riesci a gestire un'eccezione nel tuo costruttore, otterrai una TypeInitializationException. Anche se ciò potrebbe non sembrare così male, la verità è che nasconde la vera causa del problema e rende più difficile rintracciare.

Se, d'altra parte, usi un oggetto inizializzatore, stai invocando ogni proprietà individualmente fuori del costruttore e qualsiasi eccezione lanciata sarà molto chiara e molto evidente: non saranno mascherati dalla TypeInitializationException.

In generale, è una cattiva idea gettare eccezioni in un costruttore. Se vuoi evitare quello scenario, vai con l'inizializzatore.

Come altri hanno detto, no, non c'è differenza. Si noti che il primo esempio non è effettivamente usando un costruttore per tali argomenti. Sta usando la funzione di lingua "Initializer Object" introdotta in C# 3.0. Il costruttore chiamato è il costruttore senza parametri predefinito proprio come il secondo esempio.

I due esempi effettivamente si compilano allo stesso codice IL e lo fanno Esattamente la stessa cosa. Il primo esempio è solo zucchero sintattico per svolgere il compitou003Copinion> in modo più facile e più espressivou003C/opinion> .

No. Il primo modo è nuovo in .NET 3.5 ma il secondo esempio è per le versioni precedenti di C#.

Per quanto riguarda le prestazioni non vi è alcuna differenza significativa, come hanno mostrato altre risposte.

Tuttavia, la creazione di un oggetto usando un inizializzatore con 2 parametri mi sembra come te Indica il tuo intento A chiunque lo usi, formando un "contratto" che dice: "Questi 2 parametri sono il minimo per la funzionalità della classe" (sebbene il modo corretto per esprimere tale intento sarebbe quello di usare un costruttore).

Tendo a pensare alla sintassi iniziale in questo modo, sebbene sia più o meno solo zucchero sintattico. Uso un mix di entrambi i sintassi nel mio codice. Ma poi di nuovo, questo è il mio stile personale.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top