重複の可能性:
C#がデフォルトでメソッドを非仮想として実装するのはなぜですか?
私は主にC#、. NET 3.5について話していますが、一般に、すべてを「仮想」と見なさないことの利点は何でしょうか。つまり、子クラスのインスタンスで呼び出されるメソッドは、常に子のほとんどのバージョンを実行します。その方法の。C#では、親メソッドが「仮想」修飾子でラベル付けされていない場合、これは当てはまりません。例:
public class Parent
{
public void NonVirtual() { Console.WriteLine("Non-Virtual Parent"); }
public virtual void Virtual(){ Console.WriteLine("Virtual Parent"); }
}
public class Child : Parent
{
public new void NonVirtual() { Console.WriteLine("Non-Virtual Child"); }
public override void Virtual() { Console.WriteLine("Virtual Child"); }
}
public class Program
{
public static void Main(string[] args)
{
Child child = new Child();
Parent parent = new Child();
var anon = new Child();
child.NonVirtual(); // => Child
parent.NonVirtual(); // => Parent
anon.NonVirtual(); // => Child
((Parent)child).NonVirtual(); // => Parent
child.Virtual(); // => Child
parent.Virtual(); // => Child
anon.Virtual(); // => Child
((Parent)child).Virtual(); // => Child
}
}
上記で観察された非仮想動作の利点は正確には何ですか?私が考えることができた唯一のことは、「親の作者が彼のメソッドを仮想化したくない場合はどうなるか」ということでした。しかし、そのとき、私はそのための良いユースケースを考えることができないことに気づきました。クラスの動作は非仮想メソッドの動作に依存していると主張する人もいるかもしれませんが、カプセル化が不十分であるか、メソッドを封印する必要があるように思われます。
これらの同じ線に沿って、「隠す」は通常悪い考えのようです。結局のところ、Childオブジェクトとメソッドが作成された場合、Parentをオーバーライドする特定の理由で作成されたようです。また、ChildがNonVirtual()を実装(および親を非表示)する場合、Child :: NonVirtual()を呼び出すことの「予想される」動作を多くの人が考える可能性のあるものを取得しないのは非常に簡単です。(「非表示」が発生していることに気付かないことがあるため、「期待」と言います)。
では、すべてに「仮想」動作を許可しないことの利点は何でしょうか。予期しない動作が発生しやすい場合に、非仮想の親を非表示にするための適切なユースケースは何ですか?
なぜ私がこの質問をするのか知りたい人がいたら、私は最近CastleProjectsDynamicProxyライブラリを調べていました。これを使用する際の主なハードルの1つは、プロキシするメソッド(またはプロパティ)が仮想である必要があることです。そして、これは開発者にとって常にオプションであるとは限りません(ソースを制御できない場合)。言うまでもなく、DynamicProxyの目的は、プロキシされたクラスと、プロキシで達成しようとしている動作(Loggingやメモ化の実装など)との結合を回避することです。そして、仮想メソッドにこれを強制的に実行させることで、代わりに達成されることは非常に薄いですが、DynamicProxyをプロキシしているすべてのクラスに鈍く結合します-想像してみてください。継承およびオーバーライドされることはありませんが、virtualというラベルの付いたメソッドがたくさんあります。
とにかく、そこでの欲求不満は、すべてが仮想であることがより明確であり(IMO、私は推測する)、おそらく(?)より多くの利点があるように見えるときに、非仮想の利点は何であるか疑問に思いました。
編集:主観的な答えがあるかもしれない質問のように見えるので、コミュニティウィキとしてラベル付けする