74

Java では、メソッドを final としてマークして、オーバーライドできないようにすることができます。

C# では、メソッドを仮想としてマークして、オーバーライドできるようにする必要があります。

クラスをどのように継承できるかがわからない可能性が高いため、C# ではすべてのメソッドを仮想としてマークする必要があるということですか (オーバーライドしたくないいくつかのメソッドを除く)。

4

8 に答える 8

144

C#では、メソッドを仮想としてマークして、オーバーライドできるようにする必要があります。C#では、クラスをどのように継承できるかわからない可能性が高いため、すべてのメソッドを仮想としてマークする必要があるということですか(オーバーライドしたくないいくつかのメソッドを除く)。

いいえ。言語設計者が仮想をデフォルトにすべきだと考えた場合、それがデフォルトになります。

オーバーライド可能性は機能であり、すべての機能と同様にコストがかかります。オーバーライド可能なメソッドのコストはかなりのものです。特にクラスに対する「感度」がある場合は、設計、実装、およびテストに大きなコストがかかります。仮想メソッドは、テストされていないサードパーティのコードをシステムに導入する方法であり、セキュリティに影響を与えます。

クラスをどのように継承するかわからない場合は、まだ設計を完了していないため、クラスを公開しないでください。拡張性モデルは、間違いなく事前に知っておくべきものです。それはあなたの設計とテスト戦略に深く影響するはずです。

封印を解除するか、メソッドを仮想化する実際の顧客中心の理由が得られるまで、すべてのクラスを封印し、すべてのメソッドを非仮想化することをお勧めします。

基本的に、あなたの質問は、「顧客が私のクラスをどのように消費しようとしているのかわからないので、任意に拡張できるようにする必要がありますか?」です。いいえ; あなたは知識が豊富になるはずです!「顧客が私のクラスをどのように使用するのかわからないので、すべてのプロパティを読み取り/書き込みにする必要がありますか?また、すべてのメソッドをデリゲートタイプの読み取り/書き込みプロパティにして、ユーザーが任意のメソッドを独自の実装に置き換えることができますか?」いいえ、ユーザーが実際にその機能を必要としているという証拠が得られるまで、これらのことは何もしないでください。ユーザーが実際に必要としている機能の設計、テスト、実装に貴重な時間を費やし、知識のある立場からそれを実行してください。

于 2013-01-22T04:07:51.887 に答える
31

私の意見では、現在受け入れられている答えは不必要に独断的です。

事実、メソッドをとしてマークしないとvirtual、他の人はその動作をオーバーライドできず、クラスをsealed他の人としてマークすると、他の人はクラスから継承できません。これはかなりの痛みを引き起こす可能性があります。ユースケースを予期していなかったという理由だけで、クラスをマークしsealedたり、メソッドをマークしなかったりするためにAPIを何回呪ったのかわかりません。virtual

理論的には、オーバーライドおよび継承されることを意図したメソッドのオーバーライドとクラスの継承のみを許可するのが正しいアプローチかもしれませんが、実際には、考えられるすべてのシナリオを予測することは不可能であり、そのように閉じられる正当な理由はありません。

  1. 非常に正当な理由がない場合は、クラスをとしてマークしないでください sealed
  2. ライブラリが他の人によって消費されることを意図している場合は、少なくとも、動作を含むクラスのメインメソッドをとしてマークするようにしてくださいvirtual

呼び出しを行う1つの方法は、メソッドまたはプロパティの名前を確認することです。リストのGetLength()メソッドは、名前が意味することを正確に実行し、多くの解釈を許可しません。実装の変更はあまり透過的ではない可能性が高いため、virtualおそらく不要であるとマークします。メソッドを仮想としてマークするAddと、Addメソッドなどを介して一部のオブジェクトのみを受け入れる特別なリストを作成できるため、はるかに便利です。別の例として、カスタムコントロールがあります。他の人が動作の大部分を使用して外観を変更できるように、メインの描画メソッドを作成する必要virtualがありますが、XプロパティとYプロパティをオーバーライドしない可能性があります。

結局、あなたはしばしばその決定をすぐに下す必要はありません。とにかくコードを簡単に変更できる内部プロジェクトでは、これらのことについて心配する必要はありません。メソッドをオーバーライドする必要がある場合は、これが発生したときにいつでも仮想化できます。それどころか、プロジェクトが他の人によって消費され、更新が遅いAPIまたはライブラリである場合、どのクラスとメソッドが役立つかを考えることは確かに報われます。この場合、厳密に閉じているよりも開いている方が良いと思います。

于 2013-01-29T00:10:51.620 に答える
22

いいえ!クラスがどのように継承されるかわからないため、メソッドをオーバーライドすることがわかっているかのようにのみ、メソッドをマークする必要があります。virtual

于 2013-01-22T03:56:19.537 に答える
5

いいえ。派生クラスで指定するメソッドのみを仮想にする必要があります。

Virtual は final とは関係ありません。

使用するC#で仮想メソッドのオーバーライドを防ぐにはsealed

public class MyClass
{
    public sealed override void MyFinalMethod() {...}
}
于 2013-01-22T04:01:49.067 に答える
3

どちらかの陣営の理由を思いつくこともできますが、それはまったく役に立ちません。

Javaには、意図しない非最終的なパブリックメソッドが何百万もありますが、ホラーストーリーはほとんど聞こえません。

C#には何百万もの封印された公開メソッドがあり、ホラーストーリーはほとんど聞こえません。

したがって、それは大したことではありません。パブリックメソッドをオーバーライドする必要はめったにないので、どちらにしても意味がありません。


これは別の議論を思い出させます-ローカル変数がデフォルトでfinalであるべきかどうか。それはかなり良い考えですが、それがどれほど価値があるかを誇張することはできません。最終的な可能性はあるが最終的なものではない数十億のローカル変数がありますが、それは実際の問題であることが示されています。

于 2013-01-22T16:56:32.640 に答える
0

メソッドを仮想化すると、通常、それを呼び出す必要のあるコードの速度が低下します。この速度低下は重要ではありませんが、場合によっては非常に大きくなる可能性があります (特に、非仮想メソッド呼び出しがインライン化される可能性があり、オプティマイザーが不要な操作を排除できる可能性があるため)。仮想呼び出しが実行速度にどの程度影響するかを常に予測できるとは限りません。通常、コードを遅くするようなことを行うことは、明確な利点がある場合を除いて避けるべきです。

メソッドを非仮想にすることによるパフォーマンス上の利点は、多くの場合、メソッドをデフォルトで非仮想にすることを正当化するのに十分でしょう。非仮想メソッドまたはシールされたメソッドの主な使用法は、他の (保護されている可能性がある) 仮想メソッドのラッパーとして使用する必要があります (基になる動作を変更するコードは、ラッパーではなく適切な仮想メソッドをオーバーライドする必要があります)。

sealedクラスをアセンブリとしてマークしたり、アセンブリ内の他のクラスへの継承を制限したりする理由は、パフォーマンスに関連しない場合がよくあります。とりわけ、クラスが外部継承可能である場合、protectedスコープを持つすべてのメンバーがそのパブリック API に効果的に追加され、基本クラスでの動作の変更により、その動作に依存する派生クラスが壊れる可能性があります。一方、クラスが継承可能である場合、そのメソッドを作成しvirtualても実際には露出は増加しません。どちらかといえば、派生クラスではもはや関係のない基本クラス実装の側面を完全に「埋める」ことができるようにすることで、派生クラスの基本クラス内部への依存を減らすことができます [例えば、List<T>List<T>仮想であり、それらすべてをオーバーライドする派生クラスは、配列の配列を使用して物事を保持でき (ラージ オブジェクト ヒープの問題を回避)、配列の配列と一貫性を保つために使用されるプライベート配列を維持しようとする必要はありません。配列。

于 2013-06-05T19:19:15.893 に答える