In Java et C #, vous pouvez créer un objet avec des propriétés pouvant être définies lors de l'initialisation en définissant un constructeur avec des paramètres, définissant chaque propriété après la construction de l'objet, ou à l'aide de l'interface génératrice/fluide. Motif. Cependant, C # 3 introduit des initialisateurs d'objet et de collecte, ce qui signifiait que le modèle de constructeur était largement inutile. Dans une langue sans initialiseurs, on pourrait implémenter un constructeur, utilisez-le comme si:
Vehicle v = new Vehicle.Builder()
.manufacturer("Toyota")
.model("Camry")
.year(1997)
.colour(CarColours.Red)
.addSpecialFeature(new Feature.CDPlayer())
.addSpecialFeature(new Feature.SeatWarmer(4))
.build();
Inversement, en C # on pourrait écrire:
var vehicle = new Vehicle {
Manufacturer = "Toyota",
Model = "Camry",
Year = 1997,
Colour = CarColours.Red,
SpecialFeatures = new List<SpecialFeature> {
new Feature.CDPlayer(),
new Feature.SeatWarmer { Seats = 4 }
}
}
... éliminer la nécessité d'un constructeur tel que vu dans l'exemple précédent.
Sur la base de ces exemples, les constructeurs sont-ils toujours utiles en C # ou ont-ils été entièrement remplacés par les initialiseurs?
Comme indiqué par @ user248215, le problème réel est une immuabilité. La raison pour laquelle vous utiliseriez un constructeur en C # serait de maintenir l'explicite d'un initialiseur sans avoir à exposer des propriétés réglantes. Ce n'est pas une question d'encapsulation qui est la raison pour laquelle j'ai écrit ma propre réponse. L'encapsulation est relativement orthogonale car l'invocation d'un seigteur n'implique pas ce que le setter ne vous fait réellement ou vous attache à sa mise en œuvre.
La prochaine version de C #, 8.0, est susceptible d'introduire un mot-clé with
qui permettra d'initialiser des objets immutables d'être initialisée clairement et concis sans avoir à écrire des constructeurs.
Une autre chose intéressante que vous puissiez faire avec les constructeurs, par opposition aux initialiseurs, est qu'ils peuvent donner lieu à différents types d'objets en fonction de la séquence de méthodes appelées.
Par exemple
value.Match()
.Case((DateTime d) => Console.WriteLine($"{d: yyyy-mm-dd}"))
.Case((double d) => Console.WriteLine(Math.Round(d, 4));
// void
var str = value.Match()
.Case((DateTime d) => $"{d: yyyy-mm-dd}")
.Case((double d) => Math.Round(d, 4).ToString())
.ResultOrDefault(string.Empty);
// string
Juste pour clarifier l'exemple ci-dessus, il s'agit d'une bibliothèque de correspondance de modèle qui utilise le modèle de constructeur pour constituer une "correspondance" en spécifiant des cas. Les cas sont annexés en appelant la méthode Case
la transmettant une fonction. Si value
_ est assignable au type de paramètre de la fonction qu'il est appelé. Vous pouvez trouver le code source complet sur github et, puisque les commentaires XML sont difficiles à lire en texte brut, voici un lien vers la documentation construite de la château de sable (voir la - Remarques Section)
Les initialisateurs d'objets nécessitent que les propriétés doivent être accessibles par le code d'appel. Les constructeurs imbriqués peuvent accéder aux membres privés de la classe.
Si vous vouliez faire Vehicle
immuable (via faire des configurations privées), le constructeur imbriqué peut être utilisé pour définir les variables privées.