同じページにいることを確認するために、メソッドの「非表示」は、派生クラスが基本クラスのメンバーと同じ名前のメンバーを定義するときです(メソッド/プロパティの場合、仮想/オーバーライド可能とマークされません) )、および「派生コンテキスト」の派生クラスのインスタンスから呼び出された場合、派生メンバーが使用されますが、その基本クラスのコンテキストで同じインスタンスによって呼び出された場合、基本クラスメンバーが使用されます。これは、基本クラスのメンバーが派生クラスが置換を定義することを期待するメンバーの抽象化/オーバーライド、および目的のスコープ外のコンシューマーからメンバーを「隠す」スコープ/可視性修飾子とは異なります。
許可されている理由に対する簡単な答えは、そうしないと、開発者がオブジェクト指向設計のいくつかの重要な教義に違反することを余儀なくされることです。
長い答えは次のとおりです。最初に、C#でメンバーの非表示が許可されていない代替ユニバースの次のクラス構造を検討します。
public interface IFoo
{
string MyFooString {get;}
int FooMethod();
}
public class Foo:IFoo
{
public string MyFooString {get{return "Foo";}}
public int FooMethod() {//incredibly useful code here};
}
public class Bar:Foo
{
//public new string MyFooString {get{return "Bar";}}
}
Barのメンバーのコメントを解除し、そうすることで、Barが別のMyFooStringを提供できるようにします。ただし、メンバーの非表示に関する代替現実の禁止に違反するため、これを行うことはできません。この特定の例はバグが多いため、なぜそれを禁止したいのかという典型的な例です。たとえば、次の操作を実行した場合、どのコンソール出力が得られますか?
Bar myBar = new Bar();
Foo myFoo = myBar;
IFoo myIFoo = myFoo;
Console.WriteLine(myFoo.MyFooString);
Console.WriteLine(myBar.MyFooString);
Console.WriteLine(myIFoo.MyFooString);
私は頭のてっぺんから外れて、その最後の行に「Foo」と「Bar」のどちらが表示されるかわかりません。3つの変数すべてがまったく同じ状態のまったく同じインスタンスを参照している場合でも、最初の行に「Foo」、2番目の行に「Bar」が必ず表示されます。
そのため、言語のデザイナーは、私たちの別の世界では、プロパティの非表示を防ぐことにより、この明らかに悪いコードを思いとどまらせます。今、あなたはコーダーとして、まさにこれを行う必要があります。制限をどのように回避しますか?1つの方法は、Barのプロパティに異なる名前を付けることです。
public class Bar:Foo
{
public string MyBarString {get{return "Bar";}}
}
完全に合法ですが、私たちが望む行動ではありません。Barのインスタンスは、プロパティMyFooStringに対して "Foo"を常に生成します( "Bar"を生成したい場合)。IFooが特にバーであることを知る必要があるだけでなく、別のアクセサーを使用することも知っている必要があります。
また、親子関係を忘れて、インターフェースを直接実装することもできます。
public class Bar:IFoo
{
public string MyFooString {get{return "Bar";}}
public int FooMethod() {...}
}
この簡単な例では、FooとBarが両方ともIFooであることにだけ気をつけている限り、完璧な答えです。バーがFooではなく、そのように割り当てることができないため、いくつかの例の使用コードはコンパイルに失敗します。ただし、FooがBarに必要な便利なメソッド「FooMethod」を持っている場合、そのメソッドを継承することはできません。Barでコードを複製するか、クリエイティブにする必要があります。
public class Bar:IFoo
{
public string MyFooString {get{return "Bar";}}
private readonly theFoo = new Foo();
public int FooMethod(){return theFoo.FooMethod();}
}
これは明らかなハックであり、OO言語仕様の一部の実装はこれより少ししか多くありませんが、概念的には間違っています。バーニーズの消費者はFooのの機能を公開する場合は、バーがすべきことではない、フー持って Fooのを。
もちろん、Fooを制御した場合、仮想化してからオーバーライドできます。これは、メンバーがオーバーライドされることが予想される現在のユニバースでの概念上のベストプラクティスであり、非表示を許可しない代替ユニバースを保持します。
public class Foo:IFoo
{
public virtual string MyFooString {get{return "Foo";}}
//...
}
public class Bar:Foo
{
public override string MyFooString {get{return "Bar";}}
}
これに伴う問題は、仮想メンバーへのアクセスが内部で実行するのに比較的コストがかかるため、通常は必要なときにのみ実行することです。ただし、非表示がないため、ソースコードを制御していない別のコーダーが再実装したいメンバーについて悲観的になります。封印されていないクラスの「ベストプラクティス」は、特に望まない限り、すべてを仮想化することです。また、非表示の正確な動作も提供されません。インスタンスがバーの場合、文字列は常に「バー」になります。作業中の継承レベルに基づいて、隠された状態データのレイヤーを活用することが本当に役立つ場合があります。
要約すると、メンバーの非表示を許可することは、これらの悪の少ない方です。それがないと、一般的にオブジェクト指向の原則に対して、それを許可するよりもひどい残虐行為につながります。