2015-05-31 2 views
3

У меня есть объект с членами различных типов, как это:Как сериализовать объект со списком внутри в C# с помощью XElement?

public class MyObject 
{ 
    public string Str1 = string.Empty; 
    public MyEnums.Enum1 E1 = MyEnums.Enum1.Unknown; 
    public bool Done = false; 
}; 

У меня есть Dictionary этих объектов:

Dictionary<string, MyObject> MyObjectsDic = new Dictionary<string, MyObject>(); 

И сериалайзер для него, как это:

public static void ToXml(string file, string collectionName, Dictionary<string, object> collection) 
{ 
    XElement root = new XElement(collectionName); 

    root.Add(collection.Select(x => new XElement("Item", new XAttribute("Object", x.Key), 
      x.Value.GetType().GetFields().Select(f => new XElement(f.Name, f.GetValue(x.Value)))))); 

    root.Save(file); 
} 

сериализатора взял абстракцию Dictionary в качестве аргумента, и мне нужно преобразовать свой MyObjectsDic вручную. Возможно, я ошибаюсь здесь.

ToXml("MyFile.xml", "MyObjects", MyObjectsDic.ToDictionary(p => p.Key, p => (object)p.Value)); 

Я использовал this advice сделать сериалайзер. Это хорошо работает, но мне нужно, чтобы добавить к MyObject нового члена

List<MyEnums.Enum2> Codes = new List<MyEnums.Enum2>(); 

И хранить несколько значений здесь

var a = new MyObject {...}; 
a.Codes.Add(MyEnums.Enum2.Code1); 
a.Codes.Add(MyEnums.Enum2.Code2); 
MyObjectsDic.Add("Obj1", a); 

Но это список сериализации в файл как

<Codes>Code1Code2<Codes/> 

Без пространства или разделителем. И я не знаю, как сделать его более читаемым без изменений в сериализаторе и без добавления нового нечетного кода. Единственная идея, которую я получил, - это сохранить уже подготовленную строку в MyObject, а не List < ...>. Это не изящно, а просто и работает. Я не читаю эти данные, просто записываю и сохраняю как запись в файл.
Или мне нужно изменить мой классный сериализатор?

Обновление.

Я использовал нижеприведенное решение, но получаю исключение на Windows XP. На других ОС это работает хорошо. Я модифицировал код, чтобы сделать это как helper не class extension.

Exception during dumping MyObjectsDic: There was an error reflecting type 'MyObject'.
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter) at System.Xml.Serialization.XmlReflectionImporter.ImportElement(TypeModel model, XmlRootAttribute root, String defaultNamespace, RecursionLimiter limiter) at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(Type type, XmlRootAttribute root, String defaultNamespace) at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace) at System.Xml.Serialization.XmlSerializer..ctor(Type type) at MyXmlSerializerHelper.SerializeToXElement[T](T obj, XmlSerializer serializer, Boolean omitStandardNamespaces) in MyXmlSerializerHelper.cs:line 16 at MyXmlSerializerHelper. <SerializeToFile>b__0[T](KeyValuePair'2 x) in MyXmlSerializerHelper.cs:line 5

Единственная идея, у меня есть - разные варианты рамок или некоторых других религиозных вопросов XP ... К сожалению, я не могу установить любое другое программное обеспечение или .Net версии производства.

ответ

3

Вместо того, чтобы использовать отражение вручную сериализации MyObject класса, вы можете использовать XmlSerializer сериализовать словарные значения непосредственно к XElement с помощью следующих методов, а затем включить результат в дереве элементов вы строите:

public static class XObjectExtensions 
{ 
    public static XElement SerializeToXElement<T>(this IDictionary<string, T> collection, string collectionName) 
    { 
     return new XElement(collectionName, collection.Select(x => new XElement("Item", new XAttribute("Object", x.Key), x.Value.SerializeToXElement().Elements()))); 
    } 

    public static XElement SerializeToXElement<T>(this T obj, XmlSerializer serializer = null, bool omitStandardNamespaces = true) 
    { 
     var doc = new XDocument(); 
     using (var writer = doc.CreateWriter()) 
     { 
      XmlSerializerNamespaces ns = null; 
      if (omitStandardNamespaces) 
       (ns = new XmlSerializerNamespaces()).Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines. 
      (serializer ?? new XmlSerializer(obj.GetType())).Serialize(writer, obj, ns); 
     } 
     var element = doc.Root; 
     if (element != null) 
      element.Remove(); 
     return element; 
    } 
} 

Это автоматически приводит к сериализации всех полей и свойств MyObject. Используя это, полученный XML будет выглядеть следующим образом:

<MyObjects> 
    <Item Object="Obj1"> 
    <Str1>Test object</Str1> 
    <E1>Unknown</E1> 
    <Done>false</Done> 
    <Codes> 
     <Enum2>Code1</Enum2> 
     <Enum2>Code2</Enum2> 
    </Codes> 
    </Item> 
</MyObjects> 
+1

Это работает! Большое спасибо! Я не могу понять, что магия идет туда, и разница, но она работает. – Jury

+0

У меня есть исключение .... Windows XP. На других системах работает хорошо. Я обновил свой вопрос. – Jury

+0

@Jury - 1) Было ли внутреннее исключение или дополнительное сообщение? 2) Попробуйте установить любые исправления или обновления на этой машине XP. Последняя версия .Net для XP - это версия 4, которая должна быть в порядке. 3) Можете ли вы поделиться классом, который вызывает исключение? – dbc

 Смежные вопросы

  • Нет связанных вопросов^_^