38 votes

Définir les propriétés via l'initialisation de l'objet ou non : quelle différence ?

Voici une question simple : y a-t-il une différence (en termes de performances) entre ce :

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

et ceci

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

Vous pouvez imaginer un objet plus grand avec plus de propriétés.

0 votes

A vérifier également cette réponse à une question similaire.

44voto

Mark Byers Points 318575

Elles sont presque exactement équivalentes, sauf que la première méthode (utilisant un initialisateur d'objet ) ne fonctionne qu'en C# 3.0 et plus récent. Toute différence de performance n'est que mineure et ne mérite pas qu'on s'en préoccupe.

Ils produisent un code IL presque identique. Le premier donne ceci :

.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 
}

La seconde donne ceci :

.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 
}

Comme vous pouvez le constater, un code presque identique est généré. Voir ci-dessous pour le code C# exact que j'ai compilé.

Les mesures de performances montrent des résultats très similaires avec une très faible amélioration des performances pour l'utilisation de la syntaxe de l'initialisateur d'objet :

Method               Iterations per second
ObjectInitializer    8.8 million
SetProperties        8.6 million

Code que j'ai utilisé pour tester les performances :

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();
    }
}

0 votes

Eh bien, tant que vous avez le compilateur 3.0, vous pouvez l'utiliser dans du code écrit pour .net 2.0.

0 votes

Il est donc plus lourd de le faire avec l'initialisateur d'objet. Y a-t-il une méthode préférée ?

8 votes

Opinion personnelle : Pour les objets simples ou initialisés avec juste des valeurs statiques, comme cet exemple, le bloc initialisateur est ok - propre à lire. Si je dois assigner beaucoup de propriétés ou utiliser des variables, j'ai tendance à utiliser l'option d'assignation standard. Tout simplement parce que si elle échoue pour une raison quelconque (objet nul, etc.) à l'intérieur du bloc OI, il est plus difficile de comprendre où elle échoue. Alors qu'avec l'affectation standard, vous saurez exactement où se situe le problème.

10voto

Mike Hofer Points 6559

Une autre chose qui mérite d'être notée est la suivante :

Si vous ne parvenez pas à gérer une exception dans votre constructeur, vous obtiendrez une TypeInitializationException. Bien que cela ne semble pas si grave, la vérité est que cela dissimule la véritable cause du problème et le rend plus difficile à localiser.

Si, en revanche, vous utilisez un objet initialisateur vous invoquez chaque propriété individuellement à l'extérieur de du constructeur, et toute exception levée sera très claire et très évidente : elle ne sera pas masquée par la TypeInitializationException.

En général, c'est une mauvaise idée de lancer des exceptions dans un constructeur. Si vous voulez éviter ce scénario, utilisez l'initialisateur.

1 votes

+1 pour m'avoir fait réaliser que l'initialisation d'un objet ne se fait qu'APRES l'exécution du constructeur.

1voto

David Points 65209

Comme d'autres l'ont dit, non, il n'y a pas de différence. Notez que le premier exemple n'utilise pas réellement un constructeur pour ces arguments. Il utilise la fonctionnalité de langage "initialisateur d'objet" introduite en C# 3.0. Le constructeur appelé est le constructeur par défaut sans paramètre, comme dans le deuxième exemple.

Les deux exemples se compilent en fait avec (presque) le même code IL et font, à toutes fins utiles, la même chose. Le premier exemple n'est qu'une syntaxe relativement nouvelle pour accomplir la tâche <opinion>d'une manière plus facile et plus expressive</opinion>.

0voto

Non. La première méthode est nouvelle dans .NET 3.5 mais le deuxième exemple est pour les versions précédentes de C#.

0voto

En termes de performances, il n'y a pas de différence significative, comme l'ont montré d'autres réponses.

Cependant, la création d'un objet à l'aide d'un initialisateur avec 2 paramètres me semble comme si vous én én én de votre intention à tous ceux qui l'utilisent, formant un "contrat" disant : "ces 2 paramètres sont le minimum pour la fonctionnalité de la classe" (bien que la façon correcte d'exprimer cette intention serait d'utiliser un constructeur).

J'ai tendance à considérer la syntaxe de l'initialisateur de cette façon, bien qu'il s'agisse plus ou moins d'un simple sucre syntaxique. J'utilise un mélange des deux syntaxes dans mon code. Mais là encore, c'est mon style personnel.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X