Appel du constructeur et du constructeur de base en C #

J’ai deux classes, Foo et Bar, qui ont des constructeurs comme celui-ci:

class Foo { Foo() { // do some stuff } Foo(int arg) { // do some other stuff } } class Bar : Foo { Bar() : base() { // some third thing } } 

Maintenant, je veux introduire un constructeur pour Bar qui prend un int, mais je veux que le contenu de Bar () fonctionne aussi bien que celui de Foo (int). Quelque chose comme ça:

 Bar(int arg) : Bar(), base(arg) { // some fourth thing } 

Est-il possible de faire cela en C #? Le mieux que j’ai à ce jour est de placer le travail de Bar () dans une fonction, qui est également appelée par Bar (int), mais cela est plutôt inélégant.

Non, ce n’est pas possible. Si vous utilisez Reflector pour examiner l’IL qui est généré pour chaque constructeur, vous verrez pourquoi: vous finirez par appeler les deux constructeurs pour la classe de base. En théorie, le compilateur peut construire des méthodes cachées pour accomplir ce que vous voulez, mais il n’y a vraiment aucun avantage sur le fait de faire la même chose explicitement.

Je ré-enchaînerais les constructeurs, ils sont appelés comme

 Bar() : this(0) Bar(int) : Foo(int) initializes Bar Foo(int) initializes Foo Foo() : this(0) 

Cela convient si les constructeurs sans parameters supposent une sorte de valeur par défaut pour le paramètre int d’un autre constructeur. Si les constructeurs ne sont pas liés, vous faites probablement quelque chose de mal avec votre type, ou peut-être que nous avons besoin de plus d’informations sur ce que vous essayez d’atteindre.

Je recommanderais de changer votre chaîne de constructeurs pour passer du moins spécifique au plus spécifique.

 class Foo { Foo() { // do some stuff } Foo(int arg): this() { // do some other stuff } } class Bar : Foo { Bar() : Bar(0) { // some third thing } Bar(int arg): base(arg) { // something } } 

Toute création de l’object Bar appellera désormais les 4 constructeurs. Le chaînage des constructeurs doit fournir des valeurs par défaut à des constructeurs plus spécifiques, et non l’inverse. Vous devriez vraiment regarder ce que vous essayez d’accomplir et vous assurer que ce que vous faites a du sens. Curt a raison de dire qu’il y a des raisons techniques pour lesquelles vous ne pouvez pas faire cela, mais il y a aussi des raisons logiques pour lesquelles vous ne devriez pas le faire.

C’est la seule chose à laquelle je peux penser …

  public class Foo { public Foo() { } public Foo(int? arg): this() { } } public class Bar : Foo { private int x; public Bar(): this(new int?()) // edited to fix type ambiguity { // stuff that only runs for paramerless ctor } public Bar(int? arg) : base(arg) { if (arg.HasValue) { // Do stuff for both parameterless and parameterized ctor } // Do other stuff for only parameterized ctor } } 

Vous ne pouvez pas avoir le constructeur Bar qui prend un int pour appeler le constructeur sans paramètre?

Pouvez-vous mettre les choses de Bar () dans Bar (int) et appeler Bar (int) avec Bar () avec une valeur par défaut? Ensuite, Bar (int) peut appeler le constructeur de base.

 class Bar : Foo { Bar() : this(0) { } Bar(int arg) : base(arg) { } } 

Cela ne répond pas exactement à votre question, mais selon votre scénario, cela peut être une solution viable.

pouvez-vous prendre le code d’initialisation pour Bar () et en faire une méthode et l’appeler à partir des deux constructeurs, et le nouveau constructeur doit-il simplement appeler base (arg)?

Vous pouvez utiliser ce code:

 public Foo { public Foo() { this.InitializeObject(); } public Foo(int arg) : this() { // do something with Foo's arg } protected virtual void InitializeObject() { // initialize object Foo } } public Bar : Foo { public Bar : base() { } public Bar(int arg) : base(arg) { // do something with Bar's arg } protected override void InitializeObject() { // initialize object Bar base.InitializeObject(); } } 

Remplacez simplement la méthode InitializeObject() comme dans le code ci-dessus, et placez tout votre code que vous souhaitez mettre dans un constructeur sans paramètre. Et enfin, appelez base.InitializeObject() à la fin du code.

J’espère que c’est utile.