如何使用 XElement 在 C# 中使用 List 序列化对象? [英] How to serialize object with List inside in C# using XElement?

查看:49
本文介绍了如何使用 XElement 在 C# 中使用 List 序列化对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有像这样不同类型成员的对象:

公共类 MyObject{公共字符串 Str1 = string.Empty;public MyEnums.Enum1 E1 = MyEnums.Enum1.Unknown;public bool Done = false;};

我有这些对象的字典:

DictionaryMyObjectsDic = new Dictionary();

像这样的序列化器:

public static void ToXml(string file, string collectionName, Dictionary 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(文件);}

序列化程序将抽象的 Dictionary 作为参数,我需要手动转换我的 MyObjectsDic.可能是我在这里弄错了.

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

我使用了这个建议 制作序列化程序.效果很好,但我需要添加到 MyObject 新成员

ListCodes = new List();

并在此处存储一些值

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

但是这些列表被序列化到文件中

Code1Code2

没有任何空格或分隔符.而且我不知道如何在不修改序列化程序和不添加新的奇怪代码的情况下使其更具可读性.我唯一的想法是在 MyObject 中保留已经准备好的字符串,而不是 List<...>.它并不优雅,但简单而有效.我不读取这些数据,只是写入并另存为登录文件.
或者我需要改变我这么酷的序列化器?

更新.

我使用了以下解决方案,但我在 Windows XP 上收到异常.在其他操作系统上它运行良好.我修改了代码,使它像 helper 而不是类扩展.

转储 MyObjectsDic 期间出现异常:反映类型MyObject"时出现错误.在 System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel 模型,字符串 ns,ImportContext 上下文,字符串数据类型,XmlAttributes a,布尔重复,布尔 openModel,RecursionLimiter 限制器)在 System.Xml.Serialization.XmlReflectionImporter.ImportElement(TypeModel 模型,XmlRootAttribute 根,字符串 defaultNamespace,RecursionLimiter 限制器)在 System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(Type type, XmlRootAttribute root, String defaultNamespace)在 System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)在 System.Xml.Serialization.XmlSerializer..ctor(类型类型)在 MyXmlSerializerHelper.SerializeToXElement[T](T obj, XmlSerializer serializer, Boolean omitStandardNamespaces) 在 MyXmlSerializerHelper.cs:line 16在 MyXmlSerializerHelper.<SerializeToFile>b__0[T](KeyValuePair'2 x) in MyXmlSerializerHelper.cs:line 5

我唯一的想法 - 不同版本的框架或 XP 上的其他一些宗教问题......不幸的是,我无法在生产中安装任何其他软件或 .Net 版本.

解决方案

与其尝试使用反射来手动序列化 MyObject 类,不如使用 XmlSerializer 序列化您的使用以下方法将字典值直接添加到 XElement,然后将结果包含在您正在构建的元素树中:

公共静态类 XObjectExtensions{public static XElement SerializeToXElement(这个IDictionary collection, string collectionName){return new XElement(collectionName, collection.Select(x => new XElement("Item", new XAttribute("Object", x.Key), x.Value.SerializeToXElement().Elements())));}公共静态 XElement SerializeToXElement(这个 T obj,XmlSerializer 序列化器 = null,bool omitStandardNamespaces = true){var doc = new XDocument();使用 (var writer = doc.CreateWriter()){XmlSerializerNamespaces ns = null;如果(省略标准命名空间)(ns = new XmlSerializerNamespaces()).Add("", "");//禁用 xmlns:xsi 和 xmlns:xsd 行.(serializer ?? new XmlSerializer(obj.GetType())).Serialize(writer, obj, ns);}var element = doc.Root;如果(元素!= null)element.Remove();返回元素;}}

这会自动使 MyObject 的所有字段和属性正确序列化.使用它,生成的 XML 将如下所示:

<块引用>

<项目对象="Obj1"><Str1>测试对象</Str1><E1>未知</E1><Done>false</Done><代码><Enum2>Code1</Enum2><Enum2>Code2</Enum2></代码></项目></我的对象>

I have object with members of different types like this:

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

I have Dictionary of these objects:

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

And serializer for it like this:

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

The serializer tooks abstract Dictionary as argument and I need to convert my MyObjectsDic manually. May be I mistaken here.

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

I used this advice to make the serializer. It works good, but I need to add to MyObject new member

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

And store some values here

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

But these list is serialized into file like

<Codes>Code1Code2<Codes/>

Without any space or delimiter. And I don't know how to make it more readable without modifications in serializer and without adding new odd code. The only idea I got is to keep already prepared string in MyObject instead of List<...>. It isn't graceful, but simple and works. I don't read these data, just only write and save as log into file.
Or I need to change my so cool serializer?

Upd.

I used the solution below, but I'm receiving an exception on Windows XP. On other OS's it works good. I modified code to make it like helper not an 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

The only idea I have - different versions of framework or some other religious issues on XP... Unfortunately, I can't install any other software or .Net version in production.

解决方案

Rather than attempting to use reflection to manually serialize your MyObject class, you can use XmlSerializer to serialize your dictionary values directly to an XElement using the following methods, then include the result in the element tree you are building:

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

This automatically causes all fields and properties of MyObject to be serialized properly. Using this, the resulting XML will look like:

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

这篇关于如何使用 XElement 在 C# 中使用 List 序列化对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆