8

我想像这样使用 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 不是通用的。我必须从和反对(反)序列化。
  • 每个财产都必须完全公开。为什么我们不只是使用反射来访问私有设置器?
  • 私有字段不能被序列化。我想用一个属性装饰私有字段,让 XmlSerializer 包含它们。

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

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

编辑:遗产不是imo的好理由。List起初也是非通用的。

(随意调整标题或标签。如果这应该是 CW,请记下。)

4

5 回答 5

12

请参阅XmlSerializer 类。你会发现你用错了。XmlInclude有完全不同的目的。

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

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

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

XML 序列化程序在未来不太可能得到增强。我建议您学习其他替代方法。

于 2010-03-23T15:52:02.093 回答
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 不是通用的。我必须从和反对(反)序列化。

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

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

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

这确实是一个限制XmlSerializer(尽管没有设置器的列表/集合很好,但如果你有一个公共获取和私有集,它抛出)。此外,该类型需要是公共的并且有一个无参数的构造函数。

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

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

私有字段不能被序列化。我想用一个属性装饰私有字段,让 XmlSerializer 包含它们。

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

于 2010-03-23T16:26:01.530 回答
7

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

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

3:同2。

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

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

于 2010-03-23T15:50:33.103 回答
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);

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

于 2010-03-23T15:53:13.033 回答
0

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

于 2010-03-25T13:37:25.120 回答