2012-03-20 26 views
1

ユニオンのようなデータ型をシリアル化しようとしています。共用体に格納されているデータのタイプを示す列挙型フィールドと、さまざまなフィールド型があります。WCFのコンテンツに基づいてデータのシリアル化をカスタマイズする方法は?

結果はDataContractSerializerであり、生成されたXMLには列挙型と関連するフィールドのみが含まれています。まだ試みられてきたどれも

可能な解決策は、以下のとおりです。

  • カスタム・シリアライザを使用してthis questionに似たカスタム属性、と労働組合の性質をマーク。カスタムシリアライザは不要なメンバーを取り除きます。
  • ISerializationSurrogateを使用し、関連するデータだけを含む別のオブジェクトをシリアル化します。
  • ユニオンで別のフィールドを使用しないでください.1つのオブジェクトフィールドを使用してください(ISerializationSurrogateアプローチの実装の一部として使用できます)。
  • その他...?

例えば:

[DataContract] 
public class WCFTestUnion 
{ 
    public enum EUnionType 
    { 
     [EnumMember] 
     Bool, 
     [EnumMember] 
     String, 
     [EnumMember] 
     Dictionary, 
     [EnumMember] 
     Invalid 
    }; 

    EUnionType unionType = EUnionType.Invalid; 

    bool boolValue = true; 
    string stringValue = "Hello"; 
    IDictionary<object, object> dictionaryValue = null; 

    // Could use custom attribute here ? 
    [DataMember] 
    public bool BoolValue 
    { 
     get { return this.boolValue; } 
     set { this.boolValue = value; } 
    } 

    // Could use custom attribute here ? 
    [DataMember] 
    public string StringValue 
    { 
     get { return this.stringValue; } 
     set { this.stringValue = value; } 
    } 

    // Could use custom attribute here ? 
    [DataMember] 
    public IDictionary<object, object> DictionaryValue 
    { 
     get { return this.dictionaryValue; } 
     set { this.dictionaryValue = value; } 
    } 

    [DataMember] 
    public EUnionType UnionType 
    { 
     get { return this.unionType; } 
     set { this.unionType = value; } 
    } 
} // Ends class WCFTestUnion 

テスト

class TestSerializeUnion 
    { 
     internal static void Test() 
     { 
      Console.WriteLine("===TestSerializeUnion.Test()==="); 

      WCFTestUnion u = new WCFTestUnion(); 
      u.UnionType = WCFTestUnion.EUnionType.Dictionary; 
      u.DictionaryValue = new Dictionary<object, object>(); 
      u.DictionaryValue[1] = "one"; 
      u.DictionaryValue["two"] = 2; 

      System.Runtime.Serialization.DataContractSerializer serialize = new System.Runtime.Serialization.DataContractSerializer(typeof(WCFTestUnion)); 
      System.IO.Stream stream = new System.IO.MemoryStream(); 

      serialize.WriteObject(stream, u); 

      stream.Seek(0, System.IO.SeekOrigin.Begin); 
      byte[] buffer = new byte[stream.Length]; 
      int length = checked((int)stream.Length); 
      int read = stream.Read(buffer, 0, length); 
      while (read < stream.Length) 
      { 
       read += stream.Read(buffer, 0, length - read); 
      } 

      string xml = Encoding.Default.GetString(buffer); 

      System.Xml.XmlDocument doc = new System.Xml.XmlDocument(); 
      doc.LoadXml(xml); 

      System.Xml.XmlTextWriter xmlwriter = new System.Xml.XmlTextWriter(Console.Out); 
      xmlwriter.Formatting = System.Xml.Formatting.Indented; 

      doc.WriteContentTo(xmlwriter); 
      xmlwriter.Flush(); 

      Console.WriteLine(); 
     } 
    } // Ends class TestSerializeUnion 

出力:

<WCFTestUnion xmlns="http://schemas.datacontract.org/2004/07/WCFTestServiceContracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> 
    <BoolValue>true</BoolValue> 
    <DictionaryValue xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"> 
    <a:KeyValueOfanyTypeanyType> 
     <a:Key i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">1</a:Key> 
     <a:Value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">one</a:Value> 
    </a:KeyValueOfanyTypeanyType> 
    <a:KeyValueOfanyTypeanyType> 
     <a:Key i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">two</a:Key> 
     <a:Value i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">2</a:Value> 
    </a:KeyValueOfanyTypeanyType> 
    </DictionaryValue> 
    <StringValue>Hello </StringValue> 
    <UnionType>Dictionary</UnionType> 
</WCFTestUnion> 

所望の出力(使用されている唯一のフィールドが列挙と共に、シリアル化され):

<WCFTestUnion xmlns="http://schemas.datacontract.org/2004/07/WCFTestServiceContracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> 
    <DictionaryValue xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"> 
    <a:KeyValueOfanyTypeanyType> 
     <a:Key i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">1</a:Key> 
     <a:Value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">one</a:Value> 
    </a:KeyValueOfanyTypeanyType> 
    <a:KeyValueOfanyTypeanyType> 
     <a:Key i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">two</a:Key> 
     <a:Value i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">2</a:Value> 
    </a:KeyValueOfanyTypeanyType> 
    </DictionaryValue> 
    <UnionType>Dictionary</UnionType> 
</WCFTestUnion> 

答えて

2

ここにはいくつかのオプションがあります。使用するものは、このシナリオの複雑さに依存します(他に、このようなことを行う必要がある場合、このデータやパフォーマンスをシリアル化する頻度や方法など)。これらのオプションを見て、より多くの質問がありますが、主に、1つまたはハイブリッドソリューションを選ぶ前に、以下のリストから複数の戦略を試して試してみることをおすすめします。

  • Use a data contract resolver。シリアライズおよびデシリアライズ時にワイヤ表現との間でタイプを動的にマッピングするためのメカニズムを提供するので、あなたはすぐに使用できるよりもはるかに多くのタイプをサポートできます。

  • Use IObjectReference。デシリアライズ後に、別のオブジェクトへの参照を実装して返すクラスを持つことができます。

  • Use a data contract surrogate。これはあなたが参照しているシリアライゼーションサロゲートと異なりますが、同様です。私はこれらがうまくあなたのためにうまくいくと思います。

+0

私は既にデータ契約のサロゲートを持っていて、彼らは非常にきれいに作業しました。しかし、この質問に戻って忘れてしまった。 リゾルバを見ても、正しい方法だとは思わなかった。 IObjectReferenceを見ていなかったので、それに感謝します。 – WaffleSouffle

関連する問題