C# では、シャドーイングという用語はどういう意味ですか? このリンクを読みましたが、完全には理解できませんでした。
11 に答える
シャドウイングは、子クラスの新しい定義を使用して基本クラスのメソッドを非表示にすることで構成されます。
非表示とオーバーライドの違いは、メソッドの呼び出し方法に関係しています。
そのようにして、仮想メソッドがオーバーライドされると、基本クラスのメソッド呼び出しテーブルの呼び出しアドレスが子ルーチンのアドレスに置き換えられます。
一方、メソッドが非表示の場合、子クラスのメソッド呼び出しテーブルに新しいアドレスが追加されます。
問題のメソッドが呼び出されると、次のようになります。
- メソッド呼び出しテーブルのクラス タイプが取得されます。基本クラスへの参照を使用して呼び出している場合は、基本クラスのメソッド テーブルが取得されます。子クラスへの参照がある場合は、子クラスのメソッド テーブルが取得されます。
- メソッドはテーブルで検索され、見つかった場合は呼び出しが行われ、見つからなかった場合は基本クラスのメソッド テーブルが検索されます。
子クラスへの参照を使用してメソッドを呼び出す場合、動作は同じです。メソッドがオーバーライドされている場合、メソッド アドレスは基本クラスで見つかります。メソッドが非表示の場合、メソッド アドレスは子クラスであり、すでに見つかっているため、基底クラス テーブルは検索されません。
基本クラスへの参照を使用してメソッドを呼び出すと、動作が変わります。メソッドのアドレスが基本クラスのエントリを上書きするため、オーバーライドすると、基本クラスへの参照を保持している場合でも、子メソッドが呼び出されます。シャドウイングでは、基本クラスのメソッド テーブル (基本クラスへの参照を保持しているため、表示される唯一のテーブル) に仮想メソッド アドレスが含まれるため、基本クラスのメソッドが呼び出されます。
一般に、シャドウイングは悪い考えです。インスタンスへの参照に応じて、インスタンスの動作に違いが生じるからです。
ケントの正解の展開
どのメソッドがいつ呼び出されるかを明確にするとき、次のようにシャドウとオーバーライドを考えるのが好きです
- シャドウイング: 呼び出されるメソッドは、呼び出しが行われた時点での参照のタイプによって異なります。
- オーバーライド: 呼び出されるメソッドは、呼び出しが行われた時点でのオブジェクトのタイプによって異なります。
Baseクラスのメソッドを非表示にする場合は、baseでオーバーライドを使用します[baseの仮想メソッド]
子クラスのメソッドを非表示にする場合は、ベースでnewを使用します[ベースの非仮想メソッド]-> shadow
Base B=new Child()
B.VirtualMethod()
->子クラスメソッドを呼び出します
B.NonVirtualMethod()
->基本クラスのメソッドを呼び出す
この簡単な説明がお役に立てば幸いです。
Shadowing
- 親クラスの完全な要素を置き換えます
class InventoryAndSales
{
public int InvoiceNumber { get; set; }
}
//if someone calls for this class then the InvoiceNumber type is now object
class NewInventoryAndSales : InventoryAndSales
{
public new object InvoiceNumber { get; set; }
}
Overriding
- 実装のみを置き換えます。たとえば、変数がある場合、それはメソッドに変換されないため、メソッドがある場合はそのメソッドを使用し、実装のみを変更します。
class InventoryAndSales
{
public virtual int GetTotalSales(int a, int b)
{
return a + b;
}
}
class NewInventoryAndSales : InventoryAndSales
{
//it replaces the implementation in parent class
public override int GetTotalSales(int a, int b)
{
return a * b;
}
}
シャドウイングは、問題に本当にうまく「適合」しない限り、理解したり実装したりすることについて心配することではありません。私はそれが不適切に使用され、正しく使用されるよりもはるかに頻繁に奇妙なロジックバグを引き起こすのを見てきました。大きな原因は、プログラマーがメソッドシグネチャにオーバーライドを入れるのを忘れた場合、コンパイラの警告が新しいキーワードを提案することだと思います。代わりにオーバーライドを使用することをお勧めするべきだといつも感じていました。
private static int x = 10;
static void Main(string[] args)
{ int x = 20;
if (Program.x == 10)
{
Console.WriteLine(Program.x);
}
Console.WriteLine(x);}
出力:
10 20