web-dev-qa-db-ja.com

非抽象クラスの抽象メソッド

非抽象クラス(C#)の抽象メソッドを制限する設計の背後にある理由を知りたい。

クラスインスタンスには定義がないため、呼び出し可能ではないことを理解していますが、静的メソッドが定義されると、インスタンスからも除外されます。抽象メソッドがそのように処理されないのはなぜですか、同じ理由がありますか?

それらは具象クラスで許可され、派生クラスはメソッドを実装することを強制できます。基本的には、抽象クラスの抽象メソッドの場合に行われます。

40
Ashish Jain

まず、あなたが求めていることは論理的に意味をなさないと思います。 abstractメソッドがある場合、それは基本的にメソッドが未完成であることを意味します(@ChrisSinclairが指摘したように)。ただし、クラス全体が未完成であることも意味するため、abstractである必要もあります。

または、別の方法:abstract以外のクラスにabstractメソッドがあった場合、それは呼び出すことができないメソッドを持っていることを意味します。しかし、それはメソッドが役に立たないことを意味します。あなたはそれを削除することができ、すべて同じように動作します。

次に、例を使用して、より具体的にしようとします。次のコードを想像してください。

_Animal[] Zoo = new Animal[] { new Monkey(), new Fish(), new Animal() };

foreach (Animal animal in Zoo)
    animal.MakeSound();
_

ここで、Animalabstract以外の基本クラスです(これが配列に直接配置できる理由です)、MonkeyFishはから派生していますAnimalおよびMakeSound()abstractメソッドです。このコードは何をすべきですか?あなたはそれを明確に述べていませんでしたが、私はいくつかのオプションを想像することができます:

  1. Animalとして型付けされた変数でMakeSound()を呼び出すことはできません。派生クラスの1つとして型付けされた変数を使用してのみ呼び出すことができるため、これはコンパイルエラーです。

    abstractの重要な点は、派生クラスのインスタンスを基本クラスとして扱い、派生クラスに固有の動作を取得できるようにすることであるため、これは良い解決策ではありません。これが必要な場合は、通常の(abstractvirtual、またはoverrideなし)メソッドを各派生クラスに配置し、基本クラスでは何もしません。

  2. ランタイム型が実際にAnimalであるオブジェクトに対してMakeSound()を呼び出すことはできないため、これはランタイムエラー(例外)です。

    これも良い解決策ではありません。 C#は静的に型付けされた言語であるため、コンパイル時に「このメソッドを呼び出すことはできません」などのエラーをキャッチしようとします(リフレクションやdynamicなどの明らかな例外はあります)。残りの言語に適合します。また、例外をスローする基本クラスでvirtualメソッドを作成することにより、これを簡単に行うことができます。

要約すると、あまり意味がなく、デザインの悪臭(派生クラスとは異なる動作をする基本クラス)があり、非常に簡単に回避できるものが必要です。これらはすべて、notを実装する必要がある機能の歌です。

44
svick

だから、許可したい

class C { abstract void M(); }

コンパイルします。そうだとしましょう。誰かがしたときに何をしたいですか

new C().M();

?実行時エラーが必要ですか?まあ、一般的に、C#は実行時エラーよりもコンパイル時エラーを好みます。その哲学が気に入らない場合は、他の言語も利用できます...

12
AakashM

あなたはあなた自身の質問に答えたと思います。抽象メソッドは最初は定義されていません。したがって、クラスをインスタンス化することはできません。あなたはそれを無視するべきだと言っていますが、抽象メソッドを追加するときの定義では、「これから作成されるすべてのクラスはこの{abstractメソッド}を実装する必要があります」と言っているため、抽象クラスを定義するクラスも抽象でなければなりませんその時点では、抽象メソッドは未定義のままです。

4
Dale Burrell

抽象クラスには、抽象メンバーを含めることができます。同じクラスに実装できない抽象キーワードを持つメソッドがある場合、メソッド宣言が唯一あります。したがって、抽象クラスは不完全です。これが、抽象クラス用にオブジェクトが作成されない理由です。

非抽象クラスに抽象メンバーを含めることはできません。

例:

namespace InterviewPreparation
{
   public abstract class baseclass
    {
        public abstract void method1(); //abstract method
        public abstract void method2(); //abstract method
        public void method3() { }  //Non- abstract method----->It is necessary to implement here.
    }
    class childclass : baseclass
    {
        public override void method1() { }
        public override void method2() { }
    }
    public class Program    //Non Abstract Class
    {
        public static void Main()
        {
            baseclass b = new childclass(); //create instance
            b.method1();
            b.method2();
            b.method3();
        }
    }

}
2

「仮想」メソッドを使用して目的を達成することはできますが、仮想メソッドを使用すると、開発が子クラスにロジックを実装する「強制」されないため、ランタイムビジネスロジックエラーが発生する可能性があります。

ここには有効なポイントがあると思います。抽象メソッドは、子でメソッド本体を定義する要件を「強制」するため、完璧なソリューションです。

親クラスがいくつかのロジックを実装しなければならない(またはより効率的になる)多くの状況に出くわしましたが、「子」のみが残りのロジックを実装できます」

そのため、機会があれば、抽象メソッドと完全なメソッドをうまく組み合わせます。

@ AakashM、C#はコンパイル時エラーを好むことを感謝しています。だから私もそうだ。誰もそうだ。これは、既成概念について考えることです。

そして、これをサポートしてもそれに影響はありません。

ここでは、大きな男の子の決定に「hurrah」と言うのではなく、箱から出して考えてみましょう。

C#コンパイラは、 "abstract"キーワードを使用しているため、抽象クラスを直接使用している人を検出および拒否できます。

C#は、子クラスに抽象メソッドの実装を強制することも知っています。どうやって? 「abstract」キーワードを使用しているためです。

これは、プログラミング言語の内部を研究したことがある人なら誰でも簡単に理解できます。

したがって、通常のクラスのメソッドの隣にある「抽象」キーワードをC#が検出して、コンパイル時に処理できないのはなぜですか。

その理由は、「やり直し」が必要であり、努力は小さな需要をサポートする価値がないからです。

特に、大きな男の子が彼らに与えた箱から考える人がいない業界で。

1
Menol

したがって、上記の答えは正しいです。抽象メソッドを使用すると、クラスが本質的に抽象になります。クラスの一部をインスタンス化できない場合、クラス自体をインスタンス化することはできません。ただし、上記の回答では、ここでの選択肢について実際には説明しませんでした。

まず、これは主にpublic staticメソッドの問題です。メソッドがパブリックであることが意図されていない場合、抽象クラス宣言で許可されている非抽象メソッドを保護できます。そのため、これらの静的メソッドを問題なく別の静的クラスに移動することができます。

別の方法として、これらのメソッドをクラスに保持することもできますが、抽象メソッドを使用する代わりに、インターフェイスを宣言します。本質的に、派生クラスが概念的に異なる2つのオブジェクト(パブリック静的メンバーを持つ非抽象親、および抽象メソッドを持つ抽象親)から継承するため、多重継承の問題があります。他のいくつかのフレームワークとは異なり、C#は複数の継承を許可します。代わりに、C#は、この目的を満たすための正式なインターフェイス宣言を提供します。さらに、抽象メソッドのポイントは、実際には、単に特定の概念的なインターフェースを課すことです。

0
Matthew

なぜそれが必要なのかはまだ明らかではありませんが、派生クラスに強制的にデリゲートインスタンスを提供させることもできます。このようなもの

_class MyConcreteClass
{
  readonly Func<int, DateTime, string> methodImpl;

  // constructor requires a delegate instance
  public MyConcreteClass(Func<int, DateTime, string> methodImpl)
  {
    if (methodImpl == null)
      throw new ArgumentNullException();

    this.methodImpl = methodImpl;
  }

  ...
}
_

(署名string MethodImpl(int, DateTime)はもちろん単なる例です。)

そうでなければ、他の回答をお勧めして、あなたの願いがおそらく世界を良くするものではない理由を説明することができます。

0