XML Сериализованный динамический объект
Мне нужно построить набор динамически созданных узлов XML из объектов в следующем формате:
<Root>
<Name>My Name</Name>
<DynamicValues>
<DynamicValue1>Value 1</DynamicValue1>
<DynamicValue2>Value 2</DynamicValue2>
</DynamicValues>
</Root>
Имя узлов в DynamicValues
-tag неизвестно заранее. Моя первоначальная мысль заключалась в том, что это должно быть возможно с помощью Expando Object, например:
[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();
}
Однако, когда я запускаю это, я получаю сообщение SerializationException:
"Тип" System.Dynamic.ExpandoObject "с именем контракта данных 'ArrayOfKeyValueOfstringanyType: http://schemas.microsoft.com/2003/10/Serialization/Arrays' не ожидается. Рассмотрите возможность использования DataContractResolver или добавьте типы, неизвестные статически списку известных типов - например, используя атрибут KnownTypeAttribute или добавив их в список известных типов, переданных DataContractSerializer. "
Любые идеи, как я могу это достичь?
Ответы
Ответ 1
[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>
Ответ 2
Пробовал это в vb.net, но не получил требуемый вывод.
Нужна помощь.
_
Открытый класс 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)
Выход: