web-dev-qa-db-ja.com

内部ヘルパーを共有する良い方法は何ですか?

私のすべてのプロジェクトは、かなり長い間構築してきた同じベースライブラリを共有しています。ユーティリティと静的ヘルパークラスが含まれており、.NETが私が望んでいるものを正確に提供しない場合にそれらを支援します。もともとすべてのヘルパーは、主に内部の目的に役立つように作成されており、そのようにしておく必要がありますが、他のアセンブリにとって非常に役立つ場合があります。信頼性の高い方法でそれらを公開することは今や、ほとんどの人が考えるよりも複雑です。たとえば、null許容型を想定するすべてのメソッドには引数チェックが含まれている必要があります。価格は無視できるかもしれませんが、それは正しいとはほど遠いです。

リファクタリング中に、私はこのケースを複数回修正し、これまでに次の解決策を考え出しました。

  1. 各ヘルパーに内部クラスとパブリッククラスを用意する
    パブリッククラスは実際のコードを含み、パブリッククラスは引数チェックを行うアクセスポイントとして機能します。
    短所:
    • 内部クラスには、あいまいさを避けるために接頭辞が必要です(最適な表現は、パブリックタイプ用に予約する必要があります)
    • 引数のチェックを必要としないメソッドを区別することはできません
  2. (。NETフレームワークで従来実装されているように)内部メンバーとパブリックメンバーの両方を含む1つのクラスがあります。
    最初は、これは最良の解決策のように聞こえるかもしれませんが、解決策1と同じ最初の不快な欠点があります。
    短所:
    • あいまいさを避けるために内部メソッドには接頭辞が必要です
  3. 引数のチェックを必要とするメンバーをオーバーライドするパブリッククラスによって実装される内部クラスがあります。
    短所:
    • 非静的であり、少なくとも1つのインスタンス化が必要です。これはヘルパークラスのアイデアに実際には適合しません。これは通常、コードの独立したフラグメントで構成されているため、インスタンス化を必要としないはずです。
    • 非静的メソッドも無視できる程度に遅くなりますが、これもこのオプションを正当化するものではありません。

一般的で不可避の結果が1つあります。すべての内部メンバーが公的な対応を必要とするため、多くのメンテナンスが必要です。

ソリューション1に関する注意:最初の結果は、両方のクラスを異なる名前空間に置くことで回避できます。たとえば、ルートネームスペースに実際のヘルパーを、「Helpers」という名前空間にパブリックヘルパーを置くことができます。

3
toplel32

いいえ、これはあなたの質問に直接答えるものではありませんが、主にあなたの問題が他の場所に根付いていると私が信じているためです。

個人的には「ヘルパークラス」やライブラリから離れている傾向があります。このようなコードは、ホームを持たないコードのゴミ捨て場になりがちであり、デザインが貧弱になります。私が収集したものから、いくつかの一般的なコードを共有できるように、各「実際の」プロジェクトにアセンブリをアタッチするように提案しました。そして、私が目にしているのは、アプリドメインに読み込まれるコードの束であり、おそらくその10%がドメインの特定のセグメントで実際に使用されています。結局、あなたは公のメンバーに対して数回のチェック以上の費用がかかるかもしれません。

ドメインのどの部分で実際に特定のコードを共有する必要があるかを分析し、その周りの再利用可能なコードを設計することをお勧めします。個人的には、拡張メソッドの使用を好みます。特定の再利用可能なコードを特定のタイプに結び付けることができ(stringintなどを拡張しないでください)、快適でわかりやすいコードを提供します。

他のすべてが失敗したときは、次のことを覚えておいてください。「パフォーマンスは問題になるまで問題になりません。時間は、数CPUサイクルよりも価値があります」

1
Jay

.NET Framework自体で使用されている規則に従うことができます。

.NET Frameworkのソースコードを監視する場合、パブリックメソッドには必要なチェックが含まれており、作業自体をプライベートメソッドに委任します。これらのプライベートメソッドの名前は、特定のサフィックス( "内部")があることを除いて、パブリックメソッドと同じです。どちらのメソッドも同じクラス内にあります。

たとえば、 System.String にはSplit(行948)というメソッドがあり、作業をSplitInternal(行983)に委任します。

作成者が接頭辞の代わりに接尾辞を使用するという事実は重要であり、それを非常に魅力的な解決策にします。 Visual Studioのクラス。Intellisenseで機能するSplitメソッドにアクセスするために「InternalS」と入力する必要はありません。

3

これらを信頼できる方法で公開することは、ほとんどの人が考えるよりも複雑になります。たとえば、null許容型を前提とするすべてのメソッドには、内部ユーティリティにその代償を払わせずに引数チェックを含める必要があります。価格は無視できるかもしれませんが、それは正しくないです。

どうして?内部コードは何とか間違いから免れるためですか?

いいえ、適切な解決策は、自分のドッグフードを食べることです。クラス/関数が境界チェックを行う必要がある場合、すべての人に対して境界チェックを行う必要があります。 「ガベージインガベージアウト」が許容可能なアプローチであるほど使用法が明確である場合、すべての人にそれを行う必要があります。

確かに-場合によっては、境界チェックを回避するバリアントが受け入れ可能で適切なシナリオに出くわしますが、私の経験では、これらのケースは内部ではなくプライベートアクセスを必要とする傾向があり、それらは標準ではありません。物事があなたのために役立つ場合、それらはほぼ確実に皆のためになるでしょう。それらをそのように設計します。

1
Telastyn