C# 言語は、異なるライブラリ内の 基底 クラスと派生クラスの間のバージョン管理が進化し、下位互換性を維持できるように設計されています。 つまり、たとえば、派生クラスのメンバーと同じ名前の基底 クラス に新しいメンバーを導入することは、C# で完全にサポートされており、予期しない動作には至りません。 また、クラスは、メソッドが継承されたメソッドをオーバーライドすることを意図しているかどうか、またはメソッドが同様の名前の継承メソッドを非表示にする新しいメソッドであるかどうかを明示的に指定する必要があることを意味します。
C# では、派生クラスには基底クラス メソッドと同じ名前のメソッドを含めることができます。
派生クラスのメソッドの前に 新しい キーワードまたは オーバーライド キーワードがない場合、コンパイラは警告を発行し、メソッドは
new
キーワードが存在するかのように動作します。派生クラスのメソッドの前に
new
キーワードが付いている場合、メソッドは基底クラスのメソッドに依存しないと定義されます。派生クラスのメソッドの前に
override
キーワードが付いている場合、派生クラスのオブジェクトは基底クラス メソッドの代わりにそのメソッドを呼び出します。派生クラスのメソッドに
override
キーワードを適用するには、基底クラス メソッドを 仮想として定義する必要があります。基底クラス メソッドは、
base
キーワードを使用して派生クラス内から呼び出すことができます。override
、virtual
、およびnew
キーワードは、プロパティ、インデクサー、およびイベントにも適用できます。
既定では、C# メソッドは仮想ではありません。 メソッドが仮想として宣言されている場合、メソッドを継承するクラスは、独自のバージョンを実装できます。 メソッドを仮想にするには、基底クラスのメソッド宣言で virtual
修飾子が使用されます。 派生クラスは、 override
キーワードを使用して基本仮想メソッドをオーバーライドするか、 new
キーワードを使用して基底クラスの仮想メソッドを非表示にすることができます。
override
キーワードも new
キーワードも指定されていない場合、コンパイラは警告を発行し、派生クラスのメソッドは基底クラスのメソッドを非表示にします。
実際にこれを示すために、A 社がプログラムで使用する GraphicsClass
という名前のクラスを作成したとします。
GraphicsClass
を次に示します。
class GraphicsClass
{
public virtual void DrawLine() { }
public virtual void DrawPoint() { }
}
あなたの会社はこのクラスを使用し、それを使用して独自のクラスを派生させ、新しいメソッドを追加します。
class YourDerivedGraphicsClass : GraphicsClass
{
public void DrawRectangle() { }
}
A 社が新しいバージョンの GraphicsClass
をリリースするまで、アプリケーションは問題なく使用されます。これは次のコードのようになります。
class GraphicsClass
{
public virtual void DrawLine() { }
public virtual void DrawPoint() { }
public virtual void DrawRectangle() { }
}
新しいバージョンの GraphicsClass
には、 DrawRectangle
という名前のメソッドが含まれるようになりました。 最初は何も発生しません。 新しいバージョンは引き続き古いバージョンとバイナリ互換性があります。 展開したソフトウェアは、新しいクラスがそれらのコンピューター システムにインストールされている場合でも、引き続き動作します。
DrawRectangle
メソッドに対する既存の呼び出しは、あなたの派生クラスのバージョンを引き続き参照します。
ただし、新しいバージョンの GraphicsClass
を使用してアプリケーションを再コンパイルすると、コンパイラ CS0108 から警告が表示されます。 この警告は、 DrawRectangle
メソッドをアプリケーションでどのように動作させるかを検討する必要があることを通知します。
メソッドで新しい基底クラス メソッドをオーバーライドする場合は、 override
キーワードを使用します。
class YourDerivedGraphicsClass : GraphicsClass
{
public override void DrawRectangle() { }
}
override
キーワードを使用すると、YourDerivedGraphicsClass
から派生したオブジェクトで、派生クラス バージョンの DrawRectangle
が使用されるようになります。
YourDerivedGraphicsClass
から派生したオブジェクトは、base キーワードを使用して基底クラスバージョンのDrawRectangle
に引き続きアクセスできます。
base.DrawRectangle();
メソッドが新しい基底クラスのメソッドをオーバーライドしないようにしたい場合、次の事項を考慮してください。 2 つのメソッド間の混乱を避けるために、メソッドの名前を変更できます。 これは時間がかかり、エラーが発生しやすい場合があり、場合によっては実用的ではありません。 ただし、プロジェクトが比較的小さい場合は、Visual Studio のリファクタリング オプションを使用してメソッドの名前を変更できます。 詳細については、「 クラスと型のリファクタリング (クラス デザイナー)」を参照してください。
または、派生クラス定義でキーワード new
を使用して警告を回避することもできます。
class YourDerivedGraphicsClass : GraphicsClass
{
public new void DrawRectangle() { }
}
new
キーワードを使用すると、基底クラスに含まれる定義が定義によって非表示になっていることをコンパイラに指示します。 これが既定の動作です。
オーバーライドとメソッドの選択
クラスにメソッドの名前が付けられている場合、C# コンパイラは、同じ名前のメソッドが 2 つあり、渡されたパラメーターと互換性のあるパラメーターがある場合など、複数のメソッドが呼び出しと互換性がある場合に、呼び出しに最適なメソッドを選択します。 次のメソッドは互換性があります。
public class Derived : Base
{
public override void DoWork(int param) { }
public void DoWork(double param) { }
}
DoWork
のインスタンスでDerived
が呼び出されると、C# コンパイラは最初に、DoWork
で最初に宣言されたDerived
のバージョンと互換性のある呼び出しを試みます。 オーバーライド メソッドはクラスで宣言されているとは見なされず、基底クラスで宣言されたメソッドの新しい実装です。 C# コンパイラが、 Derived
の元のメソッドの呼び出しと一致できない場合にのみ、同じ名前と互換性のあるパラメーターを持つオーバーライドされたメソッドの呼び出しとの照合を試みます。 例えば次が挙げられます。
int val = 5;
Derived d = new();
d.DoWork(val); // Calls DoWork(double).
変数val
暗黙的に double に変換できるため、C# コンパイラはDoWork(double)
の代わりにDoWork(int)
を呼び出します。 これを回避するには 2 つの方法があります。 最初に、仮想メソッドと同じ名前の新しいメソッドを宣言しないようにします。 次に、 Derived
のインスタンスを Base
にキャストして基底クラスメソッドの一覧を検索することで、仮想メソッドを呼び出すように C# コンパイラに指示できます。 メソッドは仮想であるため、DoWork(int)
でのDerived
の実装が呼び出されます。 例えば次が挙げられます。
((Base)d).DoWork(val); // Calls DoWork(int) on Derived.
new
とoverride
のその他の例については、「オーバーライドと新しいキーワードを使用するタイミングを把握する」を参照してください。
こちらも参照ください
.NET