既知のデータ コントラクト型
KnownTypeAttribute クラスを使用すると、逆シリアル化において考慮する必要のある型を事前に指定できます。実施例については、「Known Types」を参照してください。
通常は、クライアントとサービス間でパラメータを渡したり、値を返したりするときに、転送するデータのデータ コントラクトのすべてが両方のエンドポイントで共有されます。ただし、次の場合はこれが該当しません。
- 送信データ コントラクトが、予想データ コントラクトから派生する場合 (詳細な情報については、次のページを参照してください。 「データ コントラクトの等価性」の継承に関するセクションを参照してください)。この場合、送信されるデータには、受信エンドポイントで予想しているデータ コントラクトが含まれません。
- クラス、構造体、または列挙とは対照的に、送信される情報の宣言型がインターフェイスである場合。したがって、インターフェイスを実装するどの型が実際に送信されるかを事前に知ることができないため、受信エンドポイントでは送信されるデータのデータ コントラクトを事前に確認することができません。
- 送信される情報の宣言型が Object である場合。すべての型が Object から継承され、どの型が実際に送信されるかを事前に知ることができないため、受信エンドポイントでは送信されるデータのデータ コントラクトを事前に確認することができません。これは最初の項目についての特殊なケースです。すべてのデータ コントラクトは既定で、Object に対して生成された空のデータ コントラクトから派生します。
- .NET Framework 型を含む一部の型に、前述した 3 つのカテゴリの 1 つに分類されるメンバが含まれる場合。たとえば、Hashtable は Object を使用して、ハッシュ テーブルに実際のオブジェクトを保存します。これらの型をシリアル化する場合、受信側ではこれらのメンバのデータ コントラクトを事前に確認することができません。
KnownTypeAttribute クラス
データが受信エンドポイントに到着すると、WCF ランタイムはデータを共通言語ランタイム (CLR: Common Language Runtime) 型のインスタンスに逆シリアル化しようとします。逆シリアル化するためにインスタンス化される型は、まず受信メッセージを調べてメッセージの内容が従うデータ コントラクトを特定することで選択されます。次に逆シリアル化エンジンは、メッセージの内容と互換性のあるデータ コントラクトを実装する CLR 型を探します。逆シリアル化エンジンによってこの処理中に逆シリアル化の候補の型として許可される一連の型は、逆シリアル化の "既知の型" のセットと呼ばれます。
逆シリアル化エンジンに型の情報を知らせる方法として、KnownTypeAttribute を使用する方法があります。この属性は、データ コントラクト型全体に適用できるだけで、個々のデータ メンバには適用できません。この属性は、クラスまたは構造体にすることが可能な外部型に適用されます**。最も簡単な使用方法は、属性を適用するときに "既知の型" として型を指定することです。これによって、外部型のオブジェクトまたはメンバを通して参照される任意のオブジェクトが逆シリアル化されるときに、必ず、その既知の型が既知の型のセットに追加されます。複数の KnownTypeAttribute 属性を同じ型に適用することができます。
既知の型とプリミティブ
プリミティブとして扱われる特定の型 (DateTime、XmlElement など) と同様に、プリミティブ型は、常に "既知" であり、このメカニズムを通して追加する必要がありません。ただし、プリミティブ型の配列は明示的に追加する必要があります。ほとんどのコレクションは、配列と同等に扱われます。(非ジェネリック コレクションは、Object の配列と同等に扱われます)。プリミティブ、プリミティブ配列、およびプリミティブ コレクションの使用例については、例 4 を参照してください。
メモ : |
---|
他のプリミティブ型とは異なり、DateTimeOffset 構造は、既定では既知の型ではないため、既知の型のリストに手動で追加する必要があります。 |
例
KnownTypeAttribute クラスの使用例を次に示します。
例 1
継承関係にある 3 つのクラスがあります。
次の CompanyLogo
クラスはシリアル化できますが、ShapeOfLogo
メンバが CircleType
オブジェクトと TriangleType
オブジェクトのどちらかに設定されている場合は、逆シリアル化エンジンが "Circle" や "Triangle" という名前のデータ コントラクト型を認識しないため、逆シリアル化することはできません。
CompanyLogo
型の正しいコードの記述方法は次のとおりです。
外部型の CompanyLogo2
が逆シリアル化されるときは、必ず、逆シリアル化エンジンが CircleType
と TriangleType
を認識するため、"Circle" データ コントラクトおよび "Triangle" データ コントラクトと一致する型を検出できます。
例 2
次の例では、CustomerTypeA
と CustomerTypeB
の両方が Customer
データ コントラクトを持っている場合でも、逆シリアル化エンジンは CustomerTypeB
だけを認識するため、PurchaseOrder
が逆シリアル化されるときは必ず CustomerTypeB
のインスタンスが作成されます。
例 3
次の例では、Hashtable が Object として内部的にその内容を保存します。ハッシュ テーブルを正常に逆シリアル化するには、逆シリアル化エンジンがそのテーブルに現れる可能性のある型のセットを認識している必要があります。この場合は、Book
オブジェクトと Magazine
オブジェクトだけが Catalog
に保存されているため、この 2 つが KnownTypeAttribute 属性を使用して追加されることが事前にわかっています。
例 4
次の例では、データ コントラクトには数値と、その数値に基づいて実行する演算が含まれています。Numbers
データ メンバは、整数、整数の配列、または整数を含む List にすることができます。
アプリケーション コードは次のとおりです。
既知の型、継承、およびインターフェイス
KnownTypeAttribute 属性を使用して既知の型を特定の型に関連付けると、その既知の型がその特定の型から派生したすべての型に関連付けられます。たとえば、次のコードを参照してください。
DoubleDrawing
クラスは、AdditionalShape
フィールドで Square
と Circle
を使用するために KnownTypeAttribute 属性を必要としません。これは、既に基本クラス (Drawing
) にこれらの属性が適用されているためです。
既知の型は、クラスと構造体にのみ関連付けることができます。インターフェイスに関連付けることはできません。
オープン ジェネリック メソッドを使用する既知の型
既知の型としてジェネリック型の追加が必要な場合があります。ただし、オープン ジェネリック型をパラメータとして KnownTypeAttribute 属性に渡すことはできません。
この問題は、型の一覧を返すメソッドを作成して既知の型のコレクションに追加するという代替機構を使用することで解決できます。次に、いくつかの制限事項があるため、このメソッドの名前を KnownTypeAttribute 属性への文字列引数として指定します。
このメソッドは、KnownTypeAttribute 属性を適用する型上に存在し、静的で、パラメータを必要とせず、Type の IEnumerable に代入可能なオブジェクトを返す必要があります。
同じ型上で、メソッド名を持つ KnownTypeAttribute 属性と実際の型を持つ KnownTypeAttribute 属性を組み合わせることはできません。また、メソッド名が同じ複数の KnownTypeAttribute を同じ型に適用することはできません。
次のクラスを参照してください。
theDrawing
フィールドには、ColorDrawing
ジェネリック クラスおよび BlackAndWhiteDrawing
ジェネリック クラスのインスタンスを格納でき、これらのクラスは両方とも Drawing
ジェネリック クラスから継承されています。通常、両クラスとも既知の型に追加する必要がありますが、次の属性の構文は有効ではありません。
// Invalid syntax for attributes:
// [KnownType(typeof(ColorDrawing<T>))]
// [KnownType(typeof(BlackAndWhiteDrawing<T>))]
' Invalid syntax for attributes:
' <KnownType(GetType(ColorDrawing(Of T))), _
' KnownType(GetType(BlackAndWhiteDrawing(Of T)))>
したがって、これらの型を返すメソッドを作成する必要があります。この型の正しいコードの記述方法は次のとおりです。
既知の型を追加するその他の方法
型を ReadOnlyCollection に追加し、DataContractSerializer の KnownTypes プロパティを使用してアクセスできます。
また、既知の型は、構成ファイルを使用して追加することもできます。この方法は、Windows Communication Foundation (WCF) でサードパーティ製の型ライブラリを使用する場合のように、既知の型の逆シリアル化が制御できない場合に便利です。
構成ファイルで既知の型を指定する方法を次に示します。
<configuration>
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="MyCompany.Library.Shape,
MyAssembly, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=XXXXXX, processorArchitecture=MSIL">
<knownType type="MyCompany.Library.Circle,
MyAssembly, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=XXXXXX, processorArchitecture=MSIL"/>
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
</configuration>
前の構成ファイルでは、MyCompany.Library.Shape
というコントラクト型が MyCompany.Library.Circle
を既知の型として持つと宣言されています。
関連項目
リファレンス
KnownTypeAttribute
Hashtable
Object
DataContractSerializer
KnownTypes