为什么 XmlSerializer 这么难用?

发布于 2024-08-26 05:54:13 字数 882 浏览 5 评论 0原文

我想像这样使用 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 序列化不应该有充分的理由公开所描述的功能?

编辑:在我看来,遗留问题并不是一个很好的理由。 List 起初也是非泛型的。

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

I imagine to use XML serialization like this:

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

Edit: I know this code is wrong. It was just to display how I would like to use it.

But this does not work at all:

  • XmlSerializer is not generic. I have to cast from and to object on (de)serialization.
  • Every property has to be fully public. Why aren't we just using Reflection to access private setters?
  • Private fields cannot be serialized. I'd like to decorate private fields with an attribute to have XmlSerializer include them.

Did I miss something and XmlSerializer is actually offering the described possibilities? Are there alternate serializers to XML that handle these cases more sophisticatedly?

If not: We're in 2010 after all, and .NET has been around for many years. XML serialization is often used, totally standard and should be really easy to perform. Or is my understanding possibly wrong and XML serialization ought not to expose the described features for a good reason?

Edit: Legacy is not a good reason imo. Listwas nongeneric at first, too.

(Feel free to adjust caption or tags. If this should be CW, please just drop a note.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

娇纵 2024-09-02 05:54:13

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

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

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

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

XML Serializer 将来不太可能得到增强。我建议您了解其他替代方案。

See XmlSerializer class. You'll see you're using it wrong. XmlInclude has a totally different purpose.

You're right. The XML Serializer has been around since .NET 1.0. That's before we had generics, BTW, so it's unlikely to support them.

Also, better technologies have arrived since then:

  • The DataContractSerializer is faster, and supports serializing as binary
  • LINQ to XML can be used in many serialization scenarios, and is much more flexible

The XML Serializer is unlikely to be enhanced in the future. I recommend you learn the other alternatives.

勿忘初心 2024-09-02 05:54:13

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

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 的限制(尽管没有 setter 的列表/集合也可以,但如果您有公共 get 和,它将会抛出异常私人套装)。此外,该类型必须是公共的并且具有无参数构造函数。

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

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

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

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

First the fixed code, then the answers to your questions:

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

or in 3.0:

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

(and use DataContractSerializer instead of XmlSerializer)

XmlSerializer is not generic. I have to cast from and to object on (de)serialization.

That is common for serializers. I have my own serializer, and initially I did make it fully generic. And it turned out to be a big design mistake. Huge. No, seriously. I'm currently in the process of re-writing every line of code to switch it out.

Simply; serializers generally involve some level of reflection (either for code-gen or for the actual work, depending on the implementation). Reflection and generics don't play nicely, especially on some of the frameworks like WCF. Having your code do the final cast is a fair compromise. I have a number of blog entries on this if you really want...

Every property has to be fully public.

That is indeed a limitation of XmlSerializer (although a list/colletion without a setter is fine, it will throw if you have a public get and private set). Also, the type needs to be public and have a parameterless constructor.

Why aren't we just using Reflection to access private setters?

For performance, XmlSerializer builds an assembly on the fly to do what you want. It doesn't have automatic access to your code's internals. For info, I'm doing something similar but I offer 2 levels of generation; fully static (into a deployable dll), which then only works with public members, or in-memory, which can still access private members. I guess they wanted to settle on only 1 model, which makes sense - and they needed "sgen", which dictates the first model.

Private fields cannot be serialized. I'd like to decorate private fields with an attribute to have XmlSerializer include them.

Then use DataContractSerializer, which will serialize any member (including private) marked [DataMember].

大海や 2024-09-02 05:54:13

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

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

3:与2相同。

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

你的假设是“有限的错误”。 XML 序列化据说是用于传输文档的,在我的项目中,这些文档始终是单独的类,不执行任何其他操作。因此,我对所有限制都没有问题。

1: legacy. XML Serializer predates generics. It as in with .NET 1.0.

2: Design decision. XML serializer is supposed to work with very limtied rights, compared to other solutions.

3: same as 2.

You can use WCF DataContract serializer in parts.

Your assumption is "limited wrong". XML serialization is supposedly for transfer documents, which - in my projects - are always separate classes doing nothing more. As such, I have no problem with all the limitations.

沙与沫 2024-09-02 05:54:13

你不需要
[Xml包含]
就像你拥有它一样。您可以使用
[Xml元素]
[Xml属性]
...
描述类的序列化方式。

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

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

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

You don't need the
[XmlInclude]
Like you have it. You can use
[XmlElement]
[XmlAttribute]
...
To describe the way the class is serialized.

Take out the [XmlInclude] and see if that works.

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

Updated, the serialized properties should be public.

橙幽之幻 2024-09-02 05:54:13

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

By the way DataContract never supports binary serialization , it serializes to xml but supports binary encoding.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文