Les initialiseurs d'objets sont assez impressionnants. Ils donnent au client d'un type un format très flexible et lisible pour créer un objet, et ils sont particulièrement parfaits pour la création d'objets imbriqués où toute une arborescence d'objets est créée en une seule fois. En voici une simple:
Code C# : | Sélectionner tout |
1 2 3 4 5 | new Person { FirstName = "Scott", LastName = "Hunter" } |
La seule grande limitation aujourd'hui est que les propriétés doivent être modifiables pour que les initialiseurs d'objet fonctionnent: ils fonctionnent en appelant d'abord le constructeur de l'objet (par défaut, sans paramètre dans ce cas), puis en les affectant aux setters de propriété.
Les propriétés init-only corrigent cela! Elles introduisent un accesseur init qui est une variante de l'accesseur set qui ne peut être appelé que lors de l'initialisation de l'objet:
Code C# : | Sélectionner tout |
1 2 3 4 5 | public class Person { public string FirstName { get; init; } public string LastName { get; init; } } |
Avec cette déclaration, le code client ci-dessus est toujours légal, mais toute affectation ultérieure aux propriétés FirstName et LastName est une erreur.
Accesseurs init et champs readonly
Étant donné que les accesseurs init ne peuvent être appelés que lors de l'initialisation, ils sont autorisés à muter les champs readonly de la classe englobante, tout comme vous le pouvez dans un constructeur.
Code C# : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class Person { private readonly string firstName; private readonly string lastName; public string FirstName { get => firstName; init => firstName = (value ?? throw new ArgumentNullException(nameof(FirstName))); } public string LastName { get => lastName; init => lastName = (value ?? throw new ArgumentNullException(nameof(LastName))); } } |
Records
Les propriétés init-only sont idéales si vous souhaitez rendre les propriétés individuelles immuables. Si vous voulez que l'objet entier soit immuable et se comporte comme une valeur, alors vous devriez envisager de le déclarer comme un record (enregistrement) :
Code C# : | Sélectionner tout |
1 2 3 4 5 | public data class Person { public string FirstName { get; init; } public string LastName { get; init; } } |
Le mot-clé data sur la déclaration de classe le marque comme un enregistrement. Cela lui confère plusieurs comportements similaires à des valeurs. De manière générale, les enregistrements sont censés être davantage considérés comme des « valeurs » (des données) et moins comme objets. Ils ne sont pas censés avoir un état encapsulé mutable. Au lieu de cela, vous représentez le changement au fil du temps en créant de nouveaux enregistrements représentant le nouvel état. Ils sont définis non pas par leur identité, mais par leur contenu.
Expressions with
Lorsque vous travaillez avec des données immuables, un modèle courant consiste à créer de nouvelles valeurs à partir de celles existantes pour représenter un nouvel état. Par exemple, si notre personne devait changer son nom de famille, nous le représenterions comme un nouvel objet qui est une copie de l'ancien, exception faite du nom de famille qui est différent. Cette technique est souvent appelée mutation non destructive. Au lieu de représenter la personne au fil du temps, l'enregistrement représente l'état de la personne à un moment donné.
Pour aider avec ce style de programmation, les enregistrements permettent un nouveau type d'expression; l'expression with :
Code C# : | Sélectionner tout |
var otherPerson = person with { LastName = "Hanselman" };
Les expressions with utilisent la syntaxe d'initialisation d'objet pour indiquer ce qui est différent dans le nouvel objet de l'ancien objet. Vous pouvez spécifier plusieurs propriétés.
Un enregistrement définit implicitement un « constructeur de copie » protected - un constructeur qui prend un objet d'enregistrement existant et le copie champ par champ dans le nouveau:
Code C# : | Sélectionner tout |
protected Person(Person original) { /* copy all the fields */ } // generated
L'expression with provoque l'appel du constructeur de copie, puis applique l'initialiseur d'objet en haut pour modifier les propriétés en conséquence.
Si vous n'aimez pas le comportement par défaut du constructeur de copie généré, vous pouvez définir le vôtre à la place, et celui-ci sera repris par l'expression with.
Source : Microsoft