これは.NETプラットフォームに関するより哲学的な質問ですが、他の言語にも役立つかもしれません。私は多くの単体テストを行っていますが、特に私がよく悩んでいるサードパーティのコンポーネントを使用している場合はそうです。 .NETでは、コンポーネントの設計者に対して、仮想化する方法かどうかを選択するという大きな主張があります。一方はコンポーネントの使用法(仮想であることが理にかなっている)であり、もう一方はコンポーネントのモック性です。 Shims を使用してサードパーティのコンポーネントをモックアップすることができますが、これはしばしば設計の悪さと複雑さの原因となります。私が.NETですべてのメソッドを仮想化する(Javaは最初からそれを持っている)ことについての議論は、パフォーマンスに関するものであったことを覚えています。しかし、それはまだ問題ですか?なぜすべてのメソッドが.NET virtualではないのか、または各クラスに少なくとも1つのインターフェイスがないのはなぜですか?
Andersが言うように 、その一部はパフォーマンスに関するもので、一部は不十分に考えられたデザインをロックダウンして、継承するように設計されていないものを盲目的に継承する人々によって引き起こされるトラブルの範囲を減らすことです。
パフォーマンスは明らかなようです。ほとんどのメソッドは最新のハードウェアでは気付かれませんが、CPUパイプラインの予測が容易な命令にますます依存する最新のハードウェアでも、仮想ゲッターはかなりのヒットを引き起こす可能性があります。
現在、デフォルトですべてを仮想化する理由は、単体テストフレームワークという1つの要素のみによって推進されているようです。これは、フレームワークを適切に設計するのではなく、フレームワークに合うようにコードを変更するのは悪い理由だと私には思えます。
おそらく問題はここで使用されているフレームワークにあります。これらは、実行時にコードを構築するのではなく、シムを挿入して実行時に関数を置き換えることができるように改善する必要があります(すべてのハックで、プライベートメソッドだけでなく非仮想メソッドも取得します)静的およびサードパーティの機能について言及する)
したがって、メソッドがデフォルトで仮想ではない理由は、Anders氏が述べたとおりであり、ユニットテストツールに合わせて仮想化したいという要望は、カートを馬の前に置くことであり、適切な設計は人工的な制約に勝るものです。
これで、インターフェースを使用するか、コードベース全体を作り直して、直接有線のメソッド呼び出しではなくメッセージパッシングを介して通信するコンポーネント(またはマイクロサービス)を使用することで、これらすべてを軽減できます。テストのためにユニットの表面を拡大してコンポーネントにし、そのコンポーネントが完全に自己完結型である場合、それを単体テストするために実際にねじ込む必要はありません。
質問には2つの要素があるので、順番に説明していきます。
.NETメソッドがデフォルトで仮想化されないのはなぜですか?
継承、実際には 多くの問題があります 。したがって、デザインの一部として使用する場合は、慎重に検討する必要があります。メソッドをデフォルトで非仮想化することにより、クラスを設計するときに開発者が継承について考えることが奨励されるという理論があります。それが実際に機能するかどうかはもちろん別の問題です。
すべてのクラスがインターフェースを実装しないのはなぜですか?
貧弱なデザインは簡単な答えです。非常に長い間、一般に優れた手法として認識されているにもかかわらず、悲しいことに、多くの人々はDIおよびTDDを考慮してシステムを設計していません。
完全に継承可能ではなく、簡単にモック化されないクラスの組み合わせは、テストが難しいコードの「完全な嵐」を作り出します。誰もがDIとデザインからインターフェイスへの原則を使用する日がくるまで、痛みを軽減するためにできることはあまりありません。