代码之家  ›  专栏  ›  技术社区  ›  mafu

为什么xmlserializer这么难使用?

  •  7
  • mafu  · 技术社区  · 16 年前

    我设想使用这样的xml序列化:

    class Foo {
        public Foo (string name) {
            Name1 = name;
            Name2 = name;
        }
    
        [XmlInclude]
        public string Name1 { get; private set; }
    
        [XmlInclude]
        private string Name2;
    }
    
    StreamWriter wr = new StreamWriter("path.xml");
    new XmlSerializer<Foo>().Serialize (wr, new Foo ("me"));
    

    编辑: 我知道这个密码是错的。只是为了展示我想如何使用它。

    但这根本不起作用:

    • XmlSerializer不是泛型的。在(反)序列化时,我必须在对象之间进行转换。
    • 所有的财产都必须完全公开。为什么我们不使用反射来访问私有setter呢?
    • 无法序列化专用字段。我想用一个属性来修饰私有字段,使xmlserializer包含它们。

    我错过了什么吗,xmlserializer实际上提供了所描述的可能性?有没有XML的替代序列化程序可以更复杂地处理这些情况?

    如果不是:我们毕竟在2010年,.net已经存在多年了。XML序列化经常被使用,完全是标准的,应该很容易执行。或者我的理解可能是错误的,XML序列化不应该公开所描述的特性是有充分理由的吗?

    编辑: 遗产不是我的好理由。 List 一开始也不一般。

    (请随意调整标题或标签。如果这应该是CW,请留下一张便条。)

    5 回复  |  直到 16 年前
        1
  •  10
  •   Marc Gravell    16 年前

    首先是固定代码,然后是问题的答案:

    public class Foo {
        public Foo() : this("") {}
        public Foo (string name) {
            Name1 = name;
            Name2 = name;
        }
        // note only this will be serialized
        public string Name1 { get; private set; }
        // this won't
        private string Name2;
    }
    

    或在3:

    [DataContract]
    class Foo {
        public Foo (string name) {
            Name1 = name;
            Name2 = name;
        }
        [DataMember]
        public string Name1 { get; private set; }
        [DataMember]
        private string Name2;
    }
    

    (及使用) DataContractSerializer 而不是 XmlSerializer )

    XmlSerializer不是泛型的。在(反)序列化时,我必须在对象之间进行转换。

    这对于序列化程序来说很常见。我有自己的序列化程序,最初 使其完全通用。结果发现这是一个很大的设计错误。巨大的。不,说真的。我正在重新写 每一个 一行代码将其关闭。

    简单地说,序列化程序通常涉及某种程度的反射(对于代码生成器或实际工作,取决于实现)。反射和泛型不能很好地发挥作用,特别是在某些框架(如wcf)上。让你的代码做最后的转换是一个公平的妥协。我有一个 如果你真的想…

    所有的财产都必须完全公开。

    这确实是一个限制 XmlSerializer程序 (尽管是一个列表/集合 没有 二传手很好 如果你有一个公共的get和private集,就抛出)。此外,该类型需要是公共的,并且具有无参数构造函数。

    为什么我们不使用反射来访问私有setter呢?

    为了表演, XmlSerializer程序 动态生成程序集以执行所需的操作。它不能自动访问代码的内部。为了获得信息,我做了一些类似的事情,但是我提供了两个级别的生成:完全静态(到一个可部署的dll中),然后它只对公共成员有效,或者在内存中,它 可以 仍然可以访问私人成员。我想他们只想解决一个模型,这是有意义的-他们需要“sgen”,这决定了第一个模型。

    无法序列化专用字段。我想用一个属性来修饰私有字段,使xmlserializer包含它们。

    然后使用 数据合同序列化程序 ,它将序列化任何标记为 [DataMember] .

        2
  •  11
  •   John Saunders    16 年前

    XmlSerializer class . 你会发现你用错了。 XmlInclude 有完全不同的目的。

    你说得对。XML序列化程序从.NET 1.0开始就存在了。那是在我们有泛型之前,顺便说一句,所以不太可能支持它们。

    此外,从那时起,更好的技术已经出现:

    • DataContractSerializer更快,并且支持作为二进制文件序列化
    • linq-to-xml可以用于许多序列化场景,并且更加灵活

    XML序列化程序在将来不太可能得到增强。我建议你学习其他的选择。

        3
  •  7
  •   itsmatt    16 年前

    1:遗产。XML序列化程序早于泛型。它与.net 1.0一样。

    2:设计决策。与其他解决方案相比,XML序列化程序应该使用非常有限的权限。

    3:和2一样。

    您可以部分使用wcf datacontract序列化程序。

    你的假设是“有限错误”。XML序列化应该是用于传输文档的,在我的项目中,这些文档总是单独的类,什么也不做。因此,我对所有的限制都没有问题。

        4
  •  1
  •   galford13x    16 年前

    你不需要 [XMLICAN] 就像你拥有它一样。你可以使用 [XMLYNET] [xmltattribute] … 描述类序列化的方式。

    取出[xmlclude]看看是否有效。

    class Foo { 
        public Foo (string name) { 
            Name1 = name; 
            Name2 = name; 
        } 
    
        [XmlAttribute] 
        public string Name1 { get; set; } 
    
        [XmlAttribute] 
        public string Name2; 
    } 
    
    Foo myFoo = new Foo("FirstName", "LastName");
    StreamWriter wr = new StreamWriter("path.xml"); 
    XmlSerializer serializer = new XmlSerializer(typeof(Foo));
    serializer.Serialize(wr,  myFoo);
    

    已更新,序列化属性应为公共属性。

        5
  •  0
  •   Kerem Kusmezer    16 年前

    顺便说一下,datacontract从不支持二进制序列化,它序列化为xml,但支持二进制编码。

    推荐文章