2011-09-21 22 views
19

I necesidad de construir un conjunto de nodos XML dinámicamente creados a partir de objetos en el siguiente formato:XML Serializar objeto dinámico

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

El nombre de los nodos dentro de la DynamicValues -tag no se conocen de antemano. Mi pensamiento inicial fue que esto debería ser posible el uso de un Expando Object, por ejemplo:

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

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

inicializando con los valores:

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

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

y luego XML-serializar:

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(); 
} 

Sin embargo, cuando ejecuto esto, obtengo una SerializationException que dice:

"Escriba 'System.Dynamic.ExpandoObject' con el nombre del contrato de datos 'ArrayOfKeyValueOfstringanyType: http://schemas.microsoft.com/2003/10/Serialization/Arrays' no se espera. Considere el uso de un DataContractResolver o añadir cualquier tipos desconocidos de forma estática a la lista de tipos conocidos -. Por ejemplo, mediante el atributo KnownTypeAttribute o mediante su inclusión en la lista de tipos conocidos pasados ​​a DataContractSerializer "

alguna idea de cómo puedo lograr esto

Respuesta

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; } 
} 

salida:?

<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

Efectivamente, es serializar sin lanzar excepciones, pero no en lo que esperaba (véase el ejemplo XML en cuestión). Obtengo nodos del tipo 'KeyValueOfstringanyType'. –

+0

@OlavHaugen, actualicé mi respuesta. –

+1

Funciona muy bien. ¡Gracias! –

0

intentado esto en vb.net pero no obtuvo el resultado requerido. Necesita ayuda.

_ Clase DynamicSerializable Pública Hereda System.Dynamic.DynamicObject Implementa 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 

End Class Código

utilizado:

raíz dévil como nueva raíz root.name = " 1 " root.DynamicValues ​​= New 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) 

Salida:

Cuestiones relacionadas