119 votes

C# : attribuer des données aux propriétés via le constructeur vs. instancier

En supposant que j'ai une classe Album :

public class Album 
{
    public string Name {get; set;}
    public string Artist {get; set;}
    public int Year {get; set;}

    public Album()
    { }

    public Album(string name, string artist, int year)
    {
        this.Name = name;
        this.Artist = artist;
        this.Year = year;
    }
}

Quand je veux attribuer des données à un objet de type Album, quelle est la différence entre les 2 approches suivantes :

Par le biais du constructeur

var albumData = new Album("Albumius", "Artistus", 2013);

ou lors de l'instanciation

var albumData = new Album 
                    {
                         Name = "Albumius",
                         Artist = "Artistus",
                         Year = 2013
                    };

143voto

David Points 65209

Les deux approches appellent un constructeur, elles appellent juste des constructeurs différents. Ce code :

var albumData = new Album 
                {
                     Name = "Albumius",
                     Artist = "Artistus",
                     Year = 2013
                };

est une abréviation syntaxique pour ce code équivalent :

var albumData = new Album();
albumData.Name = "Albumius";
albumData.Artist = "Artistus";
albumData.Year = 2013;

Les deux sont presque identiques après la compilation (assez proches pour la plupart des usages). Donc si le constructeur sans paramètres n'était pas public :

public Album() { }

alors vous ne seriez de toute façon pas en mesure d'utiliser l'initialiseur d'objet du tout. Donc la question principale n'est pas laquelle utiliser lors de l'initialisation de l'objet, mais quels constructeurs l'objet expose en premier lieu. Si l'objet expose deux constructeurs (comme celui dans votre exemple), alors on peut supposer que les deux façons sont également valides pour construire un objet.

Parfois les objets n'exposent pas de constructeurs sans paramètres car ils requièrent certaines valeurs pour la construction. Bien que dans des cas comme celui-là vous pouvez toujours utiliser la syntaxe de l'initialiseur pour d'autres valeurs. Par exemple, supposez que vous avez ces constructeurs sur votre objet :

private Album() { }
public Album(string name)
{
    this.Name = name;
}

Puisque le constructeur sans paramètres est privé, vous ne pouvez pas l'utiliser. Mais vous pouvez utiliser l'autre et toujours utiliser la syntaxe de l'initialiseur :

var albumData = new Album("Albumius")
                {
                     Artist = "Artistus",
                     Year = 2013
                };

Le résultat après la compilation serait alors identique à :

var albumData = new Album("Albumius");
albumData.Artist = "Artistus";
albumData.Year = 2013;

34voto

sircodesalot Points 3982

Les initialiseurs d'objet sont cool car ils vous permettent de configurer une classe en ligne. Le compromis est que votre classe ne peut pas être immutable. Considérez :

public class Album 
{
    // Notez que nous rendons le setter 'private'
    public string Name { get; private set; }
    public string Artist { get; private set; }
    public int Year { get; private set; }

    public Album(string name, string artist, int year)
    {
        this.Name = name;
        this.Artist = artist;
        this.Year = year;
    }
}

Si la classe est définie de cette manière, cela signifie qu'il n'y a pas vraiment de moyen facile de modifier le contenu de la classe après sa construction. L'immuabilité a des avantages. Lorsque quelque chose est immuable, il est BEAUCOUP plus facile de déterminer s'il est correct. Après tout, s'il ne peut pas être modifié après la construction, alors il n'y a aucun moyen pour qu'il soit jamais 'faux' (une fois que vous avez déterminé que sa structure est correcte). Lorsque vous créez des classes anonymes, telles que :

new { 
    Name = "Some Name",
    Artist = "Some Artist",
    Year = 1994
};

le compilateur créera automatiquement une classe immuable (c'est-à-dire que les classes anonymes ne peuvent pas être modifiées après la construction), car l'immutabilité est simplement si utile. La plupart des guides de style C++/Java encouragent souvent à rendre les membres const (C++) ou final (Java) pour cette raison. Les grandes applications sont juste beaucoup plus faciles à vérifier lorsqu'il y a moins de pièces mobiles.

Cela étant dit, il y a des situations où vous voulez pouvoir modifier rapidement la structure de votre classe. Disons que j'ai un outil que je veux configurer :

public void Configure(ConfigurationSetup setup);

et j'ai une classe qui a un certain nombre de membres tels que :

class ConfigurationSetup {
    public String Name { get; set; }
    public String Location { get; set; }
    public Int32 Size { get; set; }
    public DateTime Time { get; set; }

    // ... et d'autres trucs de configuration... 
}

L'utilisation de la syntaxe d'initialisation d'objet est utile lorsque je veux configurer une combinaison de propriétés, mais pas nécessairement toutes en une fois. Par exemple si je veux juste configurer le Name et Location, je peux juste faire :

ConfigurationSetup setup = new ConfigurationSetup {
    Name = "Some Name",
    Location = "San Jose"
};

et cela me permet de configurer une combinaison sans avoir à définir un nouveau constructeur pour chaque permutation possible.

Dans l'ensemble, je soutiendrais que rendre vos classes immuables vous fera gagner beaucoup de temps de développement à long terme, mais avoir une syntaxe d'initialisation d'objet facilite la configuration de certaines permutations de configuration.

15voto

Habib Points 93087

La deuxième approche est l'initialiseur d'objets en C#

Les initialiseurs d'objets vous permettent d'attribuer des valeurs à n'importe quel champ ou propriété accessible d'un objet au moment de sa création sans avoir à invoquer explicitement un constructeur.

La première approche

var albumData = new Album("Albumius", "Artistus", 2013);

appelle explicitement le constructeur, tandis que dans la deuxième approche l'appel au constructeur est implicite. Avec l'initialiseur d'objets, vous pouvez également omettre certaines propriétés. Par exemple :

 var albumData = new Album
        {
            Name = "Albumius",
        };

L'initialiseur d'objets se traduirait quelque chose comme ceci :

var albumData; 
var temp = new Album();
temp.Name = "Albumius";
temp.Artist = "Artistus";
temp.Year = 2013;
albumData = temp;

La raison pour laquelle il utilise un objet temporaire (en mode de débogage) est expliquée ici par Jon Skeet.

En ce qui concerne les avantages des deux approches, à mon avis, l'initialiseur d'objets serait plus facile à utiliser surtout si vous ne voulez pas initialiser tous les champs. En ce qui concerne la différence de performances, je ne pense pas qu'il y en ait car l'initialiseur d'objets appelle le constructeur sans paramètres puis attribue les propriétés. Même s'il y avait une différence de performances, elle devrait être négligeable.

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