为什么XmlSerializer如此难以使用?

时间:2010-03-23 15:46:09

标签: c# xmlserializer

我想像这样使用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不是通用的。我必须对(de)序列化进行反对操作。
  • 每个房产都必须完全公开。为什么我们不只是使用Reflection访问私人设置器?
  • 无法序列化私有字段。我想用属性装饰私有字段,让XmlSerializer包含它们。

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

如果不是:我们毕竟是在2010年,.NET已经存在多年了。通常使用XML序列化,完全标准化,并且应该非常容易执行。或者我的理解可能是错误的,并且XML序列化不应该出于充分的理由暴露所描述的特征?

编辑:遗产不是一个很好的理由imo。 List一开始也是非通用的。

(随意调整标题或标签。如果这应该是CW,请只需删除一个注释。)

5 个答案:

答案 0 :(得分:11)

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

你是对的。 XML Serializer自.NET 1.0以来就已存在。那是在我们有仿制药BTW之前,所以它不太可能支持它们。

此外,从那时起,更好的技术已经到来:

  • DataContractSerializer更快,并支持序列化为二进制
  • LINQ to XML可以在许多序列化场景中使用,并且更加灵活

将来不太可能增强XML Serializer。我建议你学习其他选择。

答案 1 :(得分:10)

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

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.0:

[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不是通用的。我必须对(de)序列化进行反对操作。

这对于序列化程序来说很常见。我有自己的序列化程序,最初我做了使它完全通用。结果证明这是一个很大的设计错误。巨大。不,真的。我目前正在重写每个代码行以将其切换出来。

简单;序列化程序通常涉及某种程度的反射(对于代码生成或实际工作,取决于实现)。反射和泛型不能很好地发挥作用,尤其是在像WCF这样的一些框架上。让你的代码做最后的演员是一个公平的妥协。如果您真的想要,我有一个的博客条目

  

每个房产都必须完全公开。

这确实是XmlSerializer的限制(虽然列表/集合没有一个setter是好的,如果你有一个公共获取,它抛出私人套装)。此外,类型需要是公共的并且具有无参数构造函数。

  

为什么我们不只是使用Reflection访问私有设置器?

对于性能,XmlSerializer动态构建程序集以执行您想要的操作。它无法自动访问代码的内部。有关信息,我正在做类似的事情,但我提供2级生成;完全静态(进入可部署的dll),然后只能与公共成员或内存一起使用, 仍然可以访问私有成员。我猜他们只想解决一个模型,这很有意义 - 他们需要“sgen”,它决定了第一个模型。

  

无法序列化私有字段。我想用属性装饰私有字段,让XmlSerializer包含它们。

然后使用DataContractSerializer,它将序列化标记为[DataMember]的任何成员(包括私人)。

答案 2 :(得分:7)

1:遗产。 XML Serializer早于泛型。它与.NET 1.0一样。

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

3:与2相同。

您可以在部分中使用WCF DataContract序列化程序。

你的假设是“有限的错误”。 XML序列化应该用于传输文档,在我的项目中,它总是独立的类,不做其他任何事情。因此,我对所有限制没有任何问题。

答案 3 :(得分:1)

你不需要 [XmlInclude] 就像你拥有它一样。您可以使用 [的XmlElement] [XmlAttribute] ... 描述类序列化的方式。

取出[XmlInclude]并查看是否有效。

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

更新后,序列化属性应该是公开的。

答案 4 :(得分:0)

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