Je sais que c'est soi-disant une question très simple, mais je lutte avec le concept depuis quelque temps déjà. Ma question est la suivante: comment enchaîner les constructeurs en c #? Je suis dans mon premier OOP cours, alors j'apprends seulement. Je ne comprends pas comment fonctionne l'enchaînement des constructeurs ni comment l'implémenter, ni même pourquoi c'est mieux que de simplement faire des constructeurs sans chaînage.
J'apprécierais quelques exemples avec une explication.
Alors, comment les enchaîner? Je sais avec deux ça va:
public SomeClass this: {0}
public SomeClass
{
someVariable = 0
}
Mais comment faites-vous avec trois, quatre et ainsi de suite?
Encore une fois, je sais que c’est une question de débutant, mais j’ai du mal à comprendre cela et je ne sais pas pourquoi.
Vous utilisez la syntaxe standard (en utilisant this
comme une méthode) pour choisir la surcharge, à l'intérieur la classe:
class Foo {
private int id;
private string name;
public Foo() : this(0, "") {
}
public Foo(int id, string name) {
this.id = id;
this.name = name;
}
public Foo(int id) : this(id, "") {
}
public Foo(string name) : this(0, name) {
}
}
ensuite:
Foo a = new Foo(), b = new Foo(456,"def"), c = new Foo(123), d = new Foo("abc");
Notez aussi:
base(...)
base()
Pour quoi?":
nécessaire pour appeler un constructeur de base autre que celui par défaut, par exemple:
SomeBaseType(int id) : base(id) {...}
Notez que vous pouvez également utiliser les initialiseurs d’objet de la même manière (sans rien écrire):
SomeType x = new SomeType(), y = new SomeType { Key = "abc" },
z = new SomeType { DoB = DateTime.Today };
Je veux juste soulever un point valable à quiconque cherche cela. Si vous souhaitez utiliser des versions .NET antérieures à 4.0 (VS2010), veuillez noter que vous devez créer des chaînes de constructeur, comme indiqué ci-dessus.
Cependant, si vous restez en 4.0, j'ai de bonnes nouvelles. Vous pouvez maintenant avoir un seul constructeur avec des arguments optionnels! Je vais simplifier l'exemple de la classe Foo:
class Foo {
private int id;
private string name;
public Foo(int id = 0, string name = "") {
this.id = id;
this.name = name;
}
}
class Main() {
// Foo Int:
Foo myFooOne = new Foo(12);
// Foo String:
Foo myFooTwo = new Foo(name:"Timothy");
// Foo Both:
Foo myFooThree = new Foo(13, name:"Monkey");
}
Lorsque vous implémentez le constructeur, vous pouvez utiliser les arguments facultatifs car les valeurs par défaut ont été définies.
J'espère que vous avez apprécié cette leçon! Je ne peux tout simplement pas croire que les développeurs se sont plaints du chaînage des constructions et ne puissent pas utiliser les arguments optionnels par défaut depuis 2004/2005! Maintenant, il a fallu SO longtemps dans le monde du développement, pour que les développeurs aient peur de l'utiliser car ce logiciel ne sera pas compatible avec les versions antérieures.
Ceci est mieux illustré par un exemple. Imaging nous avons une personne de classe
public Person(string name) : this(name, string.Empty)
{
}
public Person(string name, string address) : this(name, address, string.Empty)
{
}
public Person(string name, string address, string postcode)
{
this.Name = name;
this.Address = address;
this.Postcode = postcode;
}
Nous avons donc ici un constructeur qui définit certaines propriétés et utilise un chaînage de constructeur pour vous permettre de créer l'objet avec juste un nom, ou juste un nom et une adresse. Si vous créez une instance avec juste un nom, cela envoie une valeur par défaut, string.Empty, au nom et à l'adresse, qui envoie ensuite une valeur par défaut pour Code postal jusqu'au constructeur final.
Ce faisant, vous réduisez la quantité de code que vous avez écrit. En fait, vous ne vous répétez pas, seul un constructeur contient du code. Ainsi, par exemple, si vous modifiez le nom d'une propriété en un champ interne, vous ne devez modifier qu'un seul constructeur - si vous définissez cette propriété dans les trois constructeurs. ce serait trois endroits pour le changer.
J'ai une classe de journal et donc je ne suis pas en train d'écrire le réglage des valeurs encore et encore
public Diary() {
this.Like = defaultLike;
this.Dislike = defaultDislike;
}
public Diary(string title, string diary): this()
{
this.Title = title;
this.DiaryText = diary;
}
public Diary(string title, string diary, string category): this(title, diary) {
this.Category = category;
}
public Diary(int id, string title, string diary, string category)
: this(title, diary, category)
{
this.DiaryID = id;
}
Quelle est l'utilisation de "Chaîne de Constructeurs"?
Vous l'utilisez pour appeler un constructeur à partir d'un autre constructeur.
Comment peut-on implémenter une "chaîne de constructeur"?
Utilisez le mot-clé ": this (yourProperties)" après la définition du constructeur. par exemple:
Class MyBillClass
{
private DateTime requestDate;
private int requestCount;
public MyBillClass()
{
/// ===== we naming "a" constructor ===== ///
requestDate = DateTime.Now;
}
public MyBillClass(int inputCount) : this()
{
/// ===== we naming "b" constructor ===== ///
/// ===== This method is "Chained Method" ===== ///
this.requestCount= inputCount;
}
}
Pourquoi est-ce utile?
La raison importante est la réduction du codage et la prévention de la duplication du code. tel que le code répété pour l'initialisation de la propriété Supposons qu'une propriété de la classe doit être initialisée avec une valeur spécifique (dans notre exemple, requestDate). Et la classe a 2 ou plus constructeur. Sans "chaîne de constructeur", vous devez répéter le code d'initialisation dans tous les constructeurs de classe.
Comment ça marche? (Ou, quelle est la séquence d'exécution dans "Chaîne de constructeurs")?
Dans l'exemple ci-dessus, la méthode "a" sera exécutée en premier, puis la séquence d'instructions retournera à la méthode "b". En d'autres mots, le code ci-dessus est égal à ci-dessous:
Class MyBillClass
{
private DateTime requestDate;
private int requestCount;
public MyBillClass()
{
/// ===== we naming "a" constructor ===== ///
requestDate = DateTime.Now;
}
public MyBillClass(int inputCount) : this()
{
/// ===== we naming "b" constructor ===== ///
// ===== This method is "Chained Method" ===== ///
/// *** --- > Compiler execute "MyBillClass()" first, And then continue instruction sequence from here
this.requestCount= inputCount;
}
}
Demandez-vous à ce sujet?
public class VariantDate {
public int day;
public int month;
public int year;
public VariantDate(int day) : this(day, 1) {}
public VariantDate(int day, int month) : this(day, month,1900){}
public VariantDate(int day, int month, int year){
this.day=day;
this.month=month;
this.year=year;
}
}
J'espère que l'exemple suivant éclaircira un peu l'enchaînement des constructeurs.
Mon cas d'utilisation ici, par exemple, vous attendez de l'utilisateur qu'il passe un répertoire à votre constructeur. L'utilisateur ne sait pas quel répertoire utiliser et décide de vous laisser attribuer un répertoire par défaut. vous accélérez et attribuez un répertoire par défaut qui, selon vous, fonctionnera.
Au fait, j’ai utilisé LINQPad pour cet exemple au cas où vous vous demanderiez ce que * .Dump () est.
acclamations
void Main()
{
CtorChaining ctorNoparam = new CtorChaining();
ctorNoparam.Dump();
//Result --> BaseDir C:\Program Files (x86)\Default\
CtorChaining ctorOneparam = new CtorChaining("c:\\customDir");
ctorOneparam.Dump();
//Result --> BaseDir c:\customDir
}
public class CtorChaining
{
public string BaseDir;
public static string DefaultDir = @"C:\Program Files (x86)\Default\";
public CtorChaining(): this(null) {}
public CtorChaining(string baseDir): this(baseDir, DefaultDir){}
public CtorChaining(string baseDir, string defaultDir)
{
//if baseDir == null, this.BaseDir = @"C:\Program Files (x86)\Default\"
this.BaseDir = baseDir ?? defaultDir;
}
}
Il y a un autre point important dans l'enchaînement des constructeurs: l'ordre. Pourquoi? Supposons qu'un objet soit construit au moment de l'exécution par un framework qui attend son constructeur par défaut. Si vous voulez pouvoir passer des valeurs tout en ayant la possibilité de passer des arguments de constructeur quand vous le souhaitez, cela est extrêmement utile.
Je pourrais par exemple avoir une variable de sauvegarde qui est définie sur une valeur par défaut par mon constructeur par défaut mais qui peut être écrasée.
public class MyClass
{
private IDependency _myDependency;
MyClass(){ _myDependency = new DefaultDependency(); }
MYClass(IMyDependency dependency) : this() {
_myDependency = dependency; //now our dependency object replaces the defaultDependency
}
}