58

Stack Overflowで以前に説明したようにマーカーインターフェイス(メンバーのないインターフェイス)よりも属性を優先する必要があります。MSDNのインターフェイスデザインの記事でも、この推奨事項が主張されています。

マーカーインターフェイス(メンバーのないインターフェイス)の使用は避けてください。

カスタム属性は、タイプをマークする方法を提供します。カスタム属性の詳細については、「カスタム属性の記述」を参照してください。コードが実行されるまで属性のチェックを延期できる場合は、カスタム属性が推奨されます。シナリオでコンパイル時のチェックが必要な場合、このガイドラインに準拠することはできません。

この推奨事項を適用するためのFxCopルールもあります。

空のインターフェースは避けてください

インターフェイスは、動作または使用契約を提供するメンバーを定義します。インターフェイスによって記述された機能は、継承階層のどこにタイプが表示されているかに関係なく、どのタイプでも採用できます。タイプは、インターフェースのメンバーに実装を提供することによってインターフェースを実装します。空のインターフェースはメンバーを定義しないため、実装可能なコントラクトを定義しません。

タイプに実装が期待される空のインターフェイスがデザインに含まれている場合は、インターフェイスをマーカーとして使用しているか、タイプのグループを識別する方法を使用している可能性があります。この識別が実行時に発生する場合、これを実現する正しい方法は、カスタム属性を使用することです。属性の有無、または属性のプロパティを使用して、ターゲットタイプを識別します。コンパイル時に識別を行う必要がある場合は、空のインターフェイスを使用できます。

この記事では、警告を無視する可能性がある理由を1つだけ述べています。それは、型のコンパイル時の識別が必要な場合です。(これは、インターフェイスデザインの記事と一致しています)。

コンパイル時にインターフェイスを使用してタイプのセットを識別する場合は、このルールから警告を除外しても安全です。

実際の質問があります。Microsoftは、フレームワーククラスライブラリの設計における独自の推奨事項に準拠していませんでした(少なくともいくつかのケースでは):IRequiresSessionStateインターフェイスIReadOnlySessionStateインターフェイス。これらのインターフェイスは、ASP.NET Frameworkによって使用され、特定のハンドラーのセッション状態を有効にする必要があるかどうかを確認します。明らかに、コンパイル時の型の識別には使用されません。なぜ彼らはそれをしなかったのですか?私は2つの潜在的な理由を考えることができます:

  1. マイクロ最適化:オブジェクトがインターフェースを実装しているかどうかのチェック(obj is IReadOnlySessionState)は、リフレクションを使用して属性(type.IsDefined(typeof(SessionStateAttribute), true))をチェックするよりも高速です。ほとんどの場合、この違いはごくわずかですが、ASP.NETランタイムのパフォーマンスが重要なコードパスでは実際に問題になる可能性があります。ただし、各ハンドラータイプの結果をキャッシュするなど、回避策があります。興味深いのは、ASMX Webサービス(同様のパフォーマンス特性の影響を受ける)が実際にこの目的で属性のEnableSessionプロパティを使用することです。WebMethod

  2. インターフェイスの実装は、サードパーティの.NET言語による属性で型を装飾するよりもサポートされる可能性が高い可能性があります。ASP.NETは言語に依存しないように設計されており、ASP.NETは、ディレクティブの属性に基づいて前述のインターフェイスを実装する型のコードを生成します( CodeDomを使用してサードパーティの言語で生成される可能性があります)。属性の代わりにインターフェースを使用する意味があります。EnableSessionState<%@ Page %>

属性の代わりにマーカーインターフェイスを使用する説得力のある理由は何ですか?

これは単に(時期尚早?)最適化ですか、それともフレームワーク設計の小さな間違いですか?(彼らは反射が「赤い目を持つ大きな怪物」だと思いますか?)考え?

4

6 に答える 6

16

派生型のマークを外すことができないため、私は通常「マーカー インターフェイス」を避けます。しかし、それはさておき、組み込みのメタデータ サポートよりもマーカー インターフェースの方が好ましいと私が見た特定のケースのいくつかを以下に示します。

  1. 実行時のパフォーマンスが重要な状況。
  2. 注釈や属性をサポートしていない言語との互換性。
  3. 対象のコードがメタデータにアクセスできない可能性があるコンテキスト。
  4. 一般的な制約と一般的な分散 (通常はコレクション) のサポート。
于 2010-02-01T20:14:58.680 に答える
12

ジェネリック型の場合、マーカー インターフェイスで同じジェネリック パラメータを使用することができます。これは属性では達成できません:

interface MyInterface<T> {}

class MyClass<T, U> : MyInterface<U> {}

class OtherClass<T, U> : MyInterface<IDictionary<U, T>> {}

この種のインターフェースは、タイプを別のタイプに関連付けるのに役立つ場合があります。

マーカー インターフェイスのもう 1 つの適切な使用法は、一種の mixinを作成する場合です。

interface MyMixin {}

static class MyMixinMethods {
  public static void Method(this MyMixin self) {}
}

class MyClass : MyMixin {
}

非環式の訪問者パターンもそれらを使用します。「縮退インターフェース」という用語も使用されることがあります。

アップデート:

これが重要かどうかはわかりませんが、ポストコンパイラが作業するクラスをマークするためにそれらを使用しました。

于 2010-08-07T23:10:39.907 に答える
7

ガイドラインはフレームワークとともに進化し、APIを変更するには手遅れになるまで学習しなかったルールもあるため、Microsoftは.NET1.0を作成したときにガイドラインに厳密に従っていませんでした。

IIRC、あなたが言及する例はBCL 1.0に属しているので、それはそれを説明するでしょう。

これについては、フレームワーク設計ガイドラインで説明されています。


とは言うものの、この本は「[A]属性テストは型チェックよりもはるかにコストがかかる」と述べています(RicoMarianiによるサイドバーで)。

さらに、コンパイル時のチェックにマーカーインターフェイスが必要になる場合がありますが、これは属性では不可能です。しかし、本(p。88)にある例は納得がいかないので、ここでは繰り返しません。

于 2010-01-18T14:07:52.293 に答える
4

私はMarker Interfacesを強く支持しています。私は属性が好きではありませんでした。私はそれらを、たとえばデバッガーが見ることを目的としたクラスとメンバーのある種のメタ情報と見なしています。私の最も謙虚な意見では、例外と同様に、通常の処理ロジックに影響を与えるべきではありません。

于 2010-01-18T17:55:05.897 に答える