web-dev-qa-db-fra.com

C #: attribue des données aux propriétés via le constructeur et l'instanciation

Supposons 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;
    }
}

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

Via constructeur

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

ou lors de l'instanciation

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

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

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

est un raccourci syntaxique pour ce code équivalent:

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

Les deux sont identiques après la compilation. Donc, si le constructeur sans paramètre n'était pas public:

public Album() { }

dans ce cas, vous ne pourriez pas utiliser l’initialiseur d’objets du tout. La question principale n'est donc pas de savoir laquelle utiliser lors de l'initialisation de l'objet, mais quel constructeur (s) l'objet expose en premier lieu. Si l'objet expose deux constructeurs (comme celui de votre exemple) , alors on peut supposer que les deux voies sont également valables pour la construction d’un objet.

Parfois, les objets n'exposent pas les constructeurs sans paramètre car ils nécessitent certaines valeurs pour la construction. Bien que dans de tels cas, vous pouvez toujours utiliser la syntaxe d'initialisation pour d'autres valeurs. Par exemple, supposons que vous ayez ces constructeurs sur votre objet:

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

Comme le constructeur sans paramètre est privé, vous ne pouvez pas l'utiliser. Mais vous pouvez utiliser l’autre tout en utilisant la syntaxe d’initialisation:

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

Le résultat post-compilation serait alors identique à:

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

Les initialiseurs d’objets sont cool parce qu’ils vous permettent de configurer une classe en ligne. Le compromis est que votre classe ne peut pas être immuable. Considérer:

public class Album 
{
    // Note that we make the 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 façon, cela signifie qu’il n’est pas vraiment facile de modifier le contenu de la classe après sa construction. L'immuabilité a des avantages. Quand quelque chose est immuable, il est BEAUCOUP plus facile de déterminer que c'est correct. Après tout, si cela ne peut pas être modifié après la construction, il n’y aura aucun moyen de le "tromper" (une fois que vous aurez 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 pourront plus être modifiées après la construction), car l'immutabilité est tout à fait utile. La plupart des guides de style C++/Java encouragent souvent la création de membres const (C++) ou final (Java) uniquement pour cette raison. Les applications plus volumineuses sont beaucoup plus faciles à vérifier lorsque le nombre de pièces en mouvement est réduit.

Cela étant dit, il existe des situations dans lesquelles vous souhaitez 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; }

    // ... and some other configuration stuff... 
}

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

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

et cela me permet de configurer ne combinaison sans avoir à définir un nouveau constructeur pour tous éventuellement permutation.

Globalement, je dirais que rendre vos classes immuables vous fera gagner beaucoup de temps de développement à long terme, mais la syntaxe d'initialisation d'objet facilite beaucoup la configuration de certaines permutations de configuration.

28
sircodesalot

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

Les initialiseurs d’objets vous permettent d’attribuer des valeurs aux champs ou propriétés d’un objet accessibles au moment de la création sans avoir à appeler explicitement un constructeur .

La première approche

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

appelle explicitement le constructeur, alors que dans la seconde approche, l'appel du constructeur est implicite. Avec l'initialiseur d'objet, vous pouvez également omettre certaines propriétés. Comme:

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

L'initialiseur d'objet se traduirait par quelque chose comme:

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

Pourquoi utilise-t-il un objet temporaire (en mode débogage) , une réponse ici par Jon Skeet.

En ce qui concerne les avantages des deux approches, l'initialisation d'objet IMO serait plus facile à utiliser, spécialement si vous ne vouliez pas initialiser tous les champs. En ce qui concerne la différence de performance, je ne pense pas que ce serait le cas, puisque l’initialiseur d’objet appelle le constructeur sans paramètre, puis attribue les propriétés. Même s'il doit y avoir une différence de performance, elle devrait être négligeable.

13
Habib