178 votes

Remplacer des champs ou des propriétés dans les sous-classes

J'ai une classe de base abstraite et je veux déclarer un champ ou une propriété qui aura une valeur différente dans chaque classe qui hérite de cette classe mère.

Je veux le définir dans la classe de base afin de pouvoir y faire référence dans une méthode de la classe de base - par exemple en surchargeant ToString pour dire "Cet objet est du type propriété/champ ". Je vois trois façons de procéder, mais je me demandais : quelle est la meilleure façon de procéder ? Question de débutant, désolé.

Option 1 :
Utiliser une propriété abstraite et la surcharger sur les classes héritées. Cette méthode a l'avantage d'être appliquée (vous devez la surcharger) et elle est propre. Mais, cela semble légèrement incorrect de retourner une valeur codée en dur plutôt que d'encapsuler un champ et cela représente quelques lignes de code au lieu d'une seule. Je dois également déclarer un corps pour "set" mais c'est moins important (et il existe probablement un moyen d'éviter cela dont je n'ai pas connaissance).

abstract class Father
{
    abstract public int MyInt { get; set;}
}

class Son : Father
{
    public override int MyInt
    {
        get { return 1; }
        set { }
    }
}

Option 2
Je peux déclarer un champ public (ou un champ protégé) et le surcharger explicitement dans la classe héritée. L'exemple ci-dessous me donnera un avertissement pour utiliser "new" et je peux probablement le faire, mais cela semble faux et cela brise le polymorphisme, qui était le point principal. Cela ne semble pas être une bonne idée...

abstract class Mother
{
    public int MyInt = 0;
}

class Daughter : Mother
{
    public int MyInt = 1;
}

Option 3
Je peux utiliser un champ protégé et définir la valeur dans le constructeur. Cela semble assez simple, mais je dois m'assurer que le constructeur définit toujours cette valeur et, avec plusieurs constructeurs surchargés, il y a toujours une chance qu'un chemin de code ne définisse pas la valeur.

abstract class Aunt
{
    protected int MyInt;
}

class Niece : Aunt
{
    public Niece()
    {
        MyInt = 1;
    }
}

C'est une question un peu théorique et je pense que la réponse doit être l'option 1, car c'est la seule sûr mais je commence tout juste à me familiariser avec le C# et je voulais poser cette question à des personnes plus expérimentées.

0 votes

Abstract public int MyInt { get ; set;} => public abstract string IntentName { get ; set;} :D

3 votes

@Camo Il n'est pas approprié d'éditer les titres comme vous le faites. Les tags sont là pour accomplir cela.

0 votes

La langue doit figurer dans le titre. Personne n'a le temps de chercher et de lire des petits tags quelque part à la fin de la question alors qu'il faut chercher des tonnes de résultats. Merci de votre compréhension

4voto

Keith Aymar Points 491

Si vous construisez une classe et que vous voulez qu'il y ait une valeur de base pour la propriété, alors utilisez l'attribut virtual dans la classe de base. Cela vous permet de remplacer la propriété de manière facultative.

En utilisant votre exemple ci-dessus :

//you may want to also use interfaces.
interface IFather
{
    int MyInt { get; set; }
}

public class Father : IFather
{
    //defaulting the value of this property to 1
    private int myInt = 1;

    public virtual int MyInt
    {
        get { return myInt; }
        set { myInt = value; }
    }
}

public class Son : Father
{
    public override int MyInt
    {
        get {

            //demonstrating that you can access base.properties
            //this will return 1 from the base class
            int baseInt = base.MyInt;

            //add 1 and return new value
            return baseInt + 1;
        }
        set
        {
            //sets the value of the property
            base.MyInt = value;
        }
    }
}

Dans un programme :

Son son = new Son();
//son.MyInt will equal 2

1voto

Blair Conrad Points 56195

Vous pouvez choisir l'option 3 si vous modifiez votre classe de base abstraite pour exiger la valeur de la propriété dans le constructeur, vous ne manquerez aucun chemin. Je considérerais vraiment cette option.

abstract class Aunt
{
    protected int MyInt;
    protected Aunt(int myInt)
    {
        MyInt = myInt;
    }

}

Bien entendu, vous avez toujours la possibilité de rendre le champ privé puis, selon les besoins, d'exposer un récepteur de propriété protégé ou public.

0voto

8r13n Points 1

J'ai fait ça...

namespace Core.Text.Menus
{
    public abstract class AbstractBaseClass
    {
        public string SELECT_MODEL;
        public string BROWSE_RECORDS;
        public string SETUP;
    }
}

namespace Core.Text.Menus
{
    public class English : AbstractBaseClass
    {
        public English()
        {
            base.SELECT_MODEL = "Select Model";
            base.BROWSE_RECORDS = "Browse Measurements";
            base.SETUP = "Setup Instrument";
        }
    }
}

De cette façon, vous pouvez toujours utiliser les champs.

0voto

L'exemple d'implémentation quand vous voulez avoir une classe abstraite avec une implémentation. Les sous-classes doivent le faire :

  1. Paramétrer l'implémentation d'une classe abstraite.
  2. Hériter entièrement de l'implémentation de la classe abstraite ;
  3. Ayez votre propre mise en œuvre.

Dans ce cas, les propriétés nécessaires à l'implémentation ne doivent pas être disponibles à l'utilisation, sauf pour la classe abstraite et sa propre sous-classe.

    internal abstract class AbstractClass
    {
        //Properties for parameterization from concrete class
        protected abstract string Param1 { get; }
        protected abstract string Param2 { get; }

        //Internal fields need for manage state of object
        private string var1;
        private string var2;

        internal AbstractClass(string _var1, string _var2)
        {
            this.var1 = _var1;
            this.var2 = _var2;
        }

        internal void CalcResult()
        {
            //The result calculation uses Param1, Param2, var1, var2;
        }
    }

    internal class ConcreteClassFirst : AbstractClass
    {
        private string param1;
        private string param2;
        protected override string Param1 { get { return param1; } }
        protected override string Param2 { get { return param2; } }

        public ConcreteClassFirst(string _var1, string _var2) : base(_var1, _var2) { }

        internal void CalcParams()
        {
            //The calculation param1 and param2
        }
    }

    internal class ConcreteClassSecond : AbstractClass
    {
        private string param1;
        private string param2;

        protected override string Param1 { get { return param1; } }

        protected override string Param2 { get { return param2; } }

        public ConcreteClassSecond(string _var1, string _var2) : base(_var1, _var2) { }

        internal void CalcParams()
        {
            //The calculation param1 and param2
        }
    }

    static void Main(string[] args)
    {
        string var1_1 = "val1_1";
        string var1_2 = "val1_2";

        ConcreteClassFirst concreteClassFirst = new ConcreteClassFirst(var1_1, var1_2);
        concreteClassFirst.CalcParams();
        concreteClassFirst.CalcResult();

        string var2_1 = "val2_1";
        string var2_2 = "val2_2";

        ConcreteClassSecond concreteClassSecond = new ConcreteClassSecond(var2_1, var2_2);
        concreteClassSecond.CalcParams();
        concreteClassSecond.CalcResult();

        //Param1 and Param2 are not visible in main method
    }

0voto

Winston Smith Points 12029

Je choisirais l'option 3, mais en ayant une méthode abstraite setMyInt que les sous-classes sont obligées d'implémenter. De cette façon, vous n'aurez pas le problème d'une classe dérivée qui oublie de la définir dans le constructeur.

abstract class Base 
{
 protected int myInt;
 protected abstract void setMyInt();
}

class Derived : Base 
{
 override protected void setMyInt()
 {
   myInt = 3;
 }
}

Au fait, avec la première option, si vous ne spécifiez pas set ; dans la propriété de votre classe de base abstraite, la classe dérivée n'aura pas à l'implémenter.

abstract class Father
{
    abstract public int MyInt { get; }
}

class Son : Father
{
    public override int MyInt
    {
        get { return 1; }
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X