web-dev-qa-db-fra.com

Pourquoi ne puis-je pas créer un constructeur abstrait sur une classe C # abstraite?

Je crée une classe abstraite. Je veux que chacune de mes classes dérivées soit forcée d'implémenter une signature spécifique de constructeur. En tant que tel, j'ai fait ce que j'aurais fait si j'avais voulu les forcer à mettre en œuvre une méthode, j'en ai fait une abstraite.

public abstract class A
{
    abstract A(int a, int b);
}

Cependant, je reçois un message disant que le modificateur abstrait n'est pas valide sur cet article. Mon objectif était de forcer un code comme celui-ci.

public class B : A
{
    public B(int a, int b) : base(a, b)
    {
        //Some other awesome code.
    }
}

C'est tout le code C # .NET. Quelqu'un peut m'aider?

mise à jour 1

Je voulais ajouter quelques choses. Je me suis retrouvé avec ça.

private A() { }

protected A(int a, int b)
{
    //Code
}

Cela fait ce que certains disent, la valeur par défaut est privée et la classe doit implémenter un constructeur. Cependant cela ne FORCE PAS un constructeur avec la signature A (int a, int b).

public abstract class A
{
    protected abstract A(int a, int b)
    {


    }
}

mise à jour 2

Je devrais être clair, pour contourner ce problème, j'ai rendu mon constructeur par défaut privé et mon autre constructeur protégé. Je ne cherche pas vraiment un moyen de faire fonctionner mon code. J'ai pris soin de ça. Je cherche à comprendre pourquoi C # ne vous laisse pas faire cela.

58
Anthony D

Vous ne pouvez pas avoir de constructeur abstrait, car abstrait signifie que vous devez le remplacer dans n'importe quelle classe enfant non abstraite et vous ne pouvez pas remplacer un constructeur.

Si vous y réfléchissez, cela a du sens, car vous appelez toujours le constructeur de la classe enfant (avec le nouvel opérateur) et jamais la classe de base.

De manière générale, le seul moyen en C # d'imposer une signature de constructeur spécifique est d'utiliser la contrainte générique new (), qui impose l'existence d'un constructeur sans paramètre pour le paramètre type.

51
Tamas Czinege

Changez ce constructeur dans la classe A en

protected A(int a, int b)
{
    // Some initialisation code here
}

Ensuite, vos sous-classes devront l'utiliser, car il n'y a pas de constructeur par défaut.

Ils peuvent cependant toujours modifier la signature réelle du constructeur. Il n'y a aucun moyen de forcer une sous-classe à utiliser une signature spécifique pour son constructeur pour autant que je sache. Je suis presque sûr que les constructeurs ne peuvent pas être abstraits.

De quoi avez-vous besoin exactement? Nous pourrions peut-être suggérer une solution pour cela.

26
Jamie Penney

Bien que vous ne puissiez pas remplacer les constructeurs et ne puissiez donc pas définir un constructeur abstrait, vous pouvez placer une méthode de fabrique abstraite dans votre classe de base abstraite. Toutes les classes dérivées devraient remplacer cela.

public abstract class A 
{ 
    abstract A MakeAInstance(int a, int b); 
} 

public class B : A 
{ 
    // Must implement:
    override A MakeAInstance(int a, int b) {
        // Awesome way to create a B instance goes here
    }
} 
7
John Saunders

Plusieurs raisons:

1) Les constructeurs ne sont pas hérités, vous ne pouvez donc pas les remplacer.

2) Le constructeur est une fonction membre statique car il n'a pas besoin d'appeler une instance spécifique. L'abrégé implique "virtuel", ce qui signifie que l'implémentation peut varier en fonction de la façon dont une instance spécifique est sous-classée, ce qui est l'opposé de l'intention du sens du mot clé "statique".

5
Mats

Vous ne pouvez pas appliquer la signature du constructeur, car chaque classe dérivée peut (doit!) Définir ses propres constructeurs, et ils peuvent prendre tous les paramètres qu'ils souhaitent.

Si vous devez passer un ensemble de variables donné à un objet d'une classe dérivée, définissez une méthode abstraite qui doit être implémentée par des classes dérivées. Si les classes n'implémentent pas la méthode abstraite, vous obtiendrez une erreur de compilation.

4
devio

j'espère que cela aidera quelqu'un newb comme je suis, je cherchais à créer une classe publique "normale" avec un ctor qui prend l'argument et ensuite je devais en faire une classe enfant, donc j'avais besoin d'un ctor vide pour cela.

je ne le savais pas auparavant: si vous créez un ctor protégé, la classe enfant le voit mais le reste du programme ne le voit pas (je suppose que ma confusion est car dans asp.net je vois tous les protégés dans la page aspx qui hérite de le cs ...)

1
bresleveloper

Toutes les sous-classes peuvent toujours spécifier leur propre constructeur tant qu'elles appellent un constructeur de la superclasse - il n'y a donc aucun moyen de forcer la classe a à avoir un constructeur spécifique (du moins, c'est ainsi que cela fonctionne en Java). Vous pourriez voir que l'utilisation d'un modèle d'usine vous mènera quelque part - vous pourriez définir une méthode d'usine dans une interface - mais vous aurez besoin d'une classe d'usine distincte car votre classe de base abstraite ne connaît pas la classe réelle de l'objet qui doit être établi.

Cependant: ajouter peut-être un exemple plus concret du problème que vous rencontrez pourrait inciter d'autres/meilleures réponses. Recherchez-vous un code d'instanciation générique ou craignez-vous que des paramètres spécifiques sur la classe de base abstraite soient effectués?

Si vous êtes uniquement préoccupé par l'initialisation qui doit être effectuée par la classe abstraite, créez une méthode pour ce faire et documentez l'utilisation de cette méthode.

0
Simon Groenewolt

je ne sais pas si cela aide - mais je pense que ce serait une solution à votre problème:

public class A
{
  public A(int a, int b)
  {
    DoSomething(int a, int b);
  }

  virtual public void DoSomething(int a, int b)
  {

  }
}

public class B : A
{
  override public void DoSomething(int a, int b)
  {
    //class specific stuff
  }
}

avec le résultat que vous pouvez appeler un constructeur avec les arguments requis dans n'importe quelle classe dérivée avec le comportement correct.

0
mo.