2011-09-21 35 views
19

をシリアルIは、次の形式上のオブジェクトから動的に作成されたXMLノードのセットを構築する必要がありますXML動的オブジェクトを

<Root> 
    <Name>My Name</Name> 
    <DynamicValues> 
     <DynamicValue1>Value 1</DynamicValue1> 
     <DynamicValue2>Value 2</DynamicValue2> 
    </DynamicValues> 
</Root> 

DynamicValues -tag内のノードの名前が事前に知られていません。

[DataContract] 
public class Root 
{ 
    [DataMember] 
    public string Name { get; set; } 

    [DataMember] 
    public dynamic DynamicValues { get; set; } 
} 

値でそれを初期化することにより:その後、

var root = new Root 
        { 
         Name = "My Name", 
         DynamicValues = new ExpandoObject() 
        }; 

root.DynamicValues.DynamicValue1 = "Value 1"; 
root.DynamicValues.DynamicValue2 = "Value 2"; 

し、それをXML-シリアライズ:

string xmlString; 

var serializer = new DataContractSerializer(root.GetType()); 
using (var backing = new StringWriter()) 
using (var writer = new XmlTextWriter(backing)) 
{ 
    serializer.WriteObject(writer, root); 
    xmlString = backing.ToString(); 
} 

私の最初に考えたのは、これがExpando Object、例えばを使用可能でなければならないことでしたしかし、これを実行すると、SerializationExceptionというメッセージが表示されます。

"型 'System.Dynamic.ExpandoObject'、データコントラクト名が 'ArrayOfKeyValueOfstringanyType:http://schemas.microsoft.com/2003/10/Serialization/Arrays' であるとは限りません。 KnownTypeAttribute属性を使用するか、DataContractSerializerに渡される既知の種類の リストに追加することで、例えば「

を - DataContractResolverを使用することを検討したり、既知のタイプのリストに静的に知られていない任意の タイプを追加。私はこれを達成することができますどのように任意のアイデア

答えて

24
[Serializable] 
public class DynamicSerializable : DynamicObject, ISerializable 
{ 
    private readonly Dictionary<string, object> dictionary = new Dictionary<string, object>(); 

    public override bool TrySetMember(SetMemberBinder binder, object value) 
    { 
     dictionary[binder.Name] = value; 

     return true; 
    } 

    public void GetObjectData(SerializationInfo info, StreamingContext context) 
    { 
     foreach (var kvp in dictionary) 
     { 
      info.AddValue(kvp.Key, kvp.Value); 
     } 
    } 
} 

[KnownType(typeof(DynamicSerializable))] 
[DataContract] 
public class Root 
{ 
    [DataMember] 
    public string Name { get; set; } 

    [DataMember] 
    public dynamic DynamicValues { get; set; } 
} 

出力:?

<Program.Root xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http:// 
schemas.datacontract.org/2004/07/"> 
    <DynamicValues i:type="Program.DynamicSerializable"> 
    <DynamicValue1 xmlns:d3p1="http://www.w3.org/2001/XMLSchema" i:type="d3p1:st 
ring" xmlns="">Value 1</DynamicValue1> 
    <DynamicValue2 xmlns:d3p1="http://www.w3.org/2001/XMLSchema" i:type="d3p1:st 
ring" xmlns="">Value 2</DynamicValue2> 
    </DynamicValues> 
    <Name>My Name</Name> 
</Program.Root> 
+0

それは確かに例外をスローせずに、ではなく、私は(問題の例のXMLを参照してください)期待したものにシリアライズありません。私は 'KeyValueOfstringanyType'型のノードを取得します。 –

+0

@OlavHaugen、私は私の答えを更新しました。 –

+1

素晴らしい作品です。ありがとう! –

0

がでこれを試してみましたvb.netbutは必要な出力を得ていませんでした。 ヘルプが必要です。

_使用 パブリック・クラスDynamicSerializable 継承System.Dynamic.DynamicObject を実装ISerializable

Private ReadOnly dict As New Dictionary(Of String, Object) 

Public Overrides Function TrySetMember(binder As SetMemberBinder, value As Object) As Boolean 
    If Not dict.ContainsKey(binder.Name) Then 
     dict.Add(binder.Name, value) 
    Else 
     dict(binder.Name) = value 
    End If 
    Return True 
End Function 

Public Overrides Function TryGetMember(binder As GetMemberBinder, ByRef result As Object) As Boolean 
    Return dict.TryGetValue(binder.Name, result) 
End Function 

Public Sub GetObjectData(info As SerializationInfo, context As StreamingContext) Implements ISerializable.GetObjectData 
    For Each keyValPair In dict 
     info.AddValue(keyValPair.Key, keyValPair.Value) 
    Next 
End Sub 

エンドクラス

コード:

薄暗いルート新しいルート root.nameとして= " 1 " root.DynamicValues =新しいDynamicSerializable

root.DynamicValues.DynamicValue1 = "Value1" 
    root.DynamicValues.DynamicValue2 = "Value1" 

    Dim serializer = New DataContractSerializer(Root.GetType) 
    Dim backing As New StringWriter 
    Dim writer As New XmlTextWriter(backing) 
    serializer.WriteObject(writer, Root) 

出力:

関連する問題