161

抽象基本クラスがあり、この親クラスから継承する各クラスで異なる値を持つフィールドまたはプロパティを宣言したいと考えています。

基本クラスで定義して、基本クラスのメソッドで参照できるようにします。たとえば、ToString をオーバーライドして、「このオブジェクトはプロパティ/フィールド型です」と言うようにします。これを行うには3つの方法がありますが、疑問に思っていました-これを行うための最良の方法または受け入れられている方法は何ですか? 初心者の質問です、すいません。

オプション 1:
抽象プロパティを使用し、継承されたクラスでオーバーライドします。これは、強制されることでメリットがあり (オーバーライドする必要があります)、クリーンです。しかし、フィールドをカプセル化するのではなくハードコード値を返すのは少し間違っているように感じます。これは単なるコードではなく数行のコードです。また、「セット」の本体を宣言する必要がありますが、それはそれほど重要ではありません (おそらく、私が気付いていないことを回避する方法があります)。

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

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

オプション 2
public フィールド (または保護フィールド) を宣言し、継承されたクラスで明示的にオーバーライドできます。以下の例では、「new」を使用するようにという警告が表示されます。おそらくそれを実行できますが、それは間違っているように感じられ、ポリモーフィズムが壊れてしまいます。これが要点です。良い考えのようには思えません...

abstract class Mother
{
    public int MyInt = 0;
}

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

オプション 3
保護されたフィールドを使用して、コンストラクターで値を設定できます。これはかなり整頓されているように見えますが、コンストラクターが常にこれを設定し、オーバーロードされたコンストラクターが複数ある場合、一部のコードパスが値を設定しない可能性が常にあることを保証することに依存しています。

abstract class Aunt
{
    protected int MyInt;
}

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

これは少し理論的な質問であり、唯一の安全なオプションであるため、答えはオプション1でなければならないと思いますが、私はC#を理解し始めたばかりで、経験のある人にこれを尋ねたかった.

4

10 に答える 10

147

3 つのソリューションのうち、オプション 1のみがポリモーフィックです。

フィールド自体をオーバーライドすることはできません。これがまさに、オプション 2が新しいキーワードの警告を返す 理由です。

警告に対する解決策は、「new」キーワードを追加するのではなく、オプション 1 を実装することです。

フィールドをポリモーフィックにする必要がある場合は、プロパティでラップする必要があります。

ポリモーフィックな動作が必要ない場合は、オプション 3で問題ありません。ただし、実行時にプロパティ MyInt にアクセスすると、派生クラスは返される値を制御できないことに注意してください。基本クラス自体は、この値を返すことができます。

これは、プロパティの真のポリモーフィック実装がどのように見えるかであり、派生クラスを制御できます。

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

class Father : Parent
{
    public override int MyInt
    {
        get { /* Apply formula "X" and return a value */ }
    }
}

class Mother : Parent
{
    public override int MyInt
    {
        get { /* Apply formula "Y" and return a value */ }
    }
}
于 2008-11-29T12:43:30.917 に答える
18

オプション2は初心者ではありません。フィールドを上書きすることはできず、非表示にすることしかできません。

個人的には、毎回オプション1を選びます。私は常にフィールドをプライベートに保つようにしています。もちろん、本当にプロパティをオーバーライドできる必要がある場合です。もう1つのオプションは、コンストラクターパラメーターから設定される基本クラスに読み取り専用プロパティを設定することです。

abstract class Mother
{
    private readonly int myInt;
    public int MyInt { get { return myInt; } }

    protected Mother(int myInt)
    {
        this.myInt = myInt;
    }
}

class Daughter : Mother
{
    public Daughter() : base(1)
    {
    }
}

インスタンスの存続期間中に値が変化しない場合は、これがおそらく最も適切なアプローチです。

于 2008-11-28T17:11:37.477 に答える
12

あなたはこれを行うことができます

class x
{
    private int _myInt;
    public virtual int myInt { get { return _myInt; } set { _myInt = value; } }
}

class y : x
{
    private int _myYInt;
    public override int myInt { get { return _myYInt; } set { _myYInt = value; } }
}

virtual を使用すると、何かを実行するボディのプロパティを取得できますが、サブクラスはそれをオーバーライドできます。

于 2013-11-13T19:47:38.083 に答える
7

オプション 2 は悪い考えです。これにより、シャドウイングと呼ばれるものが発生します。基本的に、2 つの異なる "MyInt" メンバーがあり、1 つは母親に、もう 1 つは娘にあります。これに関する問題は、母親に実装されたメソッドが母親の「MyInt」を参照し、娘に実装されたメソッドが娘の「MyInt」を参照することです。これにより、深刻な可読性の問題が発生し、後で混乱が生じる可能性があります。

個人的には、最良の選択肢は 3 だと思います。明確な一元化された値を提供し、オプション 1 の問題である独自のフィールドを定義する手間をかけずに、子によって内部的に参照できるためです。

于 2008-11-28T17:33:04.530 に答える
4

次のように定義できます。

abstract class Father
{
    //Do you need it public?
    protected readonly int MyInt;
}

class Son : Father
{
    public Son()
    {
        MyInt = 1;
    }
}

値を読み取り専用に設定することにより、そのクラスの値がオブジェクトの存続期間中変更されないようにします。

次の質問は、なぜそれが必要なのかということだと思います。

于 2008-11-28T17:08:58.293 に答える
0

オプション3を使用しますが、サブクラスに実装を強制する抽象setMyIntメソッドがあります。このようにして、派生クラスがコンストラクターに設定するのを忘れるという問題は発生しません。

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

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

ちなみに、オプション1では、setを指定しない場合。抽象基本クラスプロパティでは、派生クラスはそれを実装する必要はありません。

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

class Son : Father
{
    public override int MyInt
    {
        get { return 1; }
    }
}
于 2008-11-28T17:05:36.320 に答える
0

コンストラクターでプロパティ値を要求するように抽象基本クラスを変更する場合は、オプション3を選択できます。パスを見逃すことはありません。私は本当にこのオプションを検討したいと思います。

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

}

もちろん、フィールドをプライベートにし、必要に応じて、保護されたプロパティまたはパブリックプロパティのゲッターを公開するオプションもあります。

于 2008-11-28T17:06:22.493 に答える
0

これは私がしました...

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";
        }
    }
}

このようにして、フィールドを引き続き使用できます。

于 2015-11-02T20:30:25.507 に答える