C#序列化私有类成员

41
class Person
{
    public string m_name;
    private int m_age; // << how do I serialize the darn little rat?
}

这是一个简单的问题,但当试图回答它时似乎变成了一团乱麻。
每个人都建议使用公共getter/setter,但我的应用程序太大了,为每个成员创建getter/setter只会导致可维护性问题。

我是否被迫在此处创建自定义序列化,或者是否有一个神奇的属性可以解决这些成员的序列化问题?
如何序列化私有类成员?

编辑#1:
好的各位,对于不够清晰表示抱歉,我写这个问题时有点沮丧,因为我已经尝试了几个小时才找到解决方案。
无论如何,以下是更多的事实:
1. 我正在尝试将此类XML序列化。 目前我正在使用 System.Xml.Serialization.XmlSerializer 。
2. 我正在进行 XML序列化以实现版本兼容性,据我所知,二进制不能提供这种兼容性。
3. 我希望有某种类似的属性

<code>class Person
{
    public string m_name;
    [SerializeThat(ElementName="Age")]
    private int m_age; // << how do I serialize the darn little rat?
}
</code>

或者(事实 #3 的延续)一个应用于 class 的属性,看起来像这样:

<code>[Serializable(DoPrivate = true, DoProtected = true)]
class Person
{
    public string m_name;
    private int m_age; // << how do I serialize the darn little rat?
}
</code>

现在,我应该怎么做才能实现它?


2
我猜 public int m_age; 应该改成 private 吧?不然,没问题吗? - Jan Sverre
3
你想进行哪种类型的序列化? - Travis Gockel
你遇到了什么“大麻烦”?我不明白为什么你不能在类上加上[Serializable],然后就完成了。也许你在示例代码中过于简化了某些东西,这意味着你隐藏了问题的根本原因。 - Jon Hanna
7
我要如何对这个可恶的小老鼠进行序列化?哈哈哈哈!+1 让我笑出声了。 - Lzh
1
可能是序列化私有成员数据的重复问题。 - Chris Pickford
7个回答

20

假设出现了一个打字错误,我想引导您到这篇SO文章,文章提出的解决方案是使用DataContractSerializer


嗨Brad,感谢你的回答 - 我甚至无法编译代码,也许是因为我正在尝试在ASP.NET Web应用程序上这样做? - Poni
通常情况下会出现这个错误:"error CS0246: 找不到类型或命名空间名称 'DataMember'。" 真奇怪。 - Poni
不是要冒犯您的智慧,但您是否在引用中包含了System.Runtime.Serialization?编辑如果是这样,请右键单击该引用并转到属性,然后选择“复制本地”,看看是否解决了问题。 - Brad Christie
@Brad - 谢谢,我一直将这个引用中的“Runtime”部分与“Xml”混淆了,这就是我没有获得DataContract的原因。 - Poni
现在一切都正常了,还在调整属性吗?你可以将其分解为控制台应用程序并测试最少的部分(将输出指向Console.Out)。 - Brad Christie
显示剩余2条评论

13

不知道您是否可以使用 DataContract。但是,使用它,您可以编写:

[DataContract]
class Person
{
    [DataMember]
    public string m_name;

    [DataMember]
    private int m_age;
}

DataContract 的优点是可以序列化私有字段,而且你的类不需要一个默认构造函数。


谢谢。我正在说话的同时检查这个。 - Poni
好的回答,Oliver,谢谢。但希望你能用不同的措辞表达,这样可以节省我的时间 (: - Poni
1
如果不需要自定义处理(如排除),这可能会更简单,只需具有Serializable属性,DataContractSerializer现在将选择类的所有成员,而无需使用[DataMember]标记它们。 - nawfal

8
如果您使用BinaryFormatter,它将会访问您类的私有部分。
请给您的每个类都打上[Serializable]标记,否则会受阻。
还有,请看这里:为什么需要Serializable属性才能对一个对象进行序列化 如果您需要XML,也许您可以试试SoapFormatter。详情请见这里
顺便说一下,关于版本兼容性:我使用BinaryFormatter,在模式升级方面没有遇到问题。请自行处理模式更改,或者用适当的默认构造函数替换被Deserialize省略的空指针。如果您不真正需要XML提供的功能,请使用二进制格式,您永远不会回头。
还有一点要补充:
BF会轻松解决您所有的多重引用问题,因此不会一遍又一遍地创建相同引用的多个实例。猜想XmlSerializer做不到这一点,很明显它没有存储该信息的位置。
示例:
class Data
{
    int a;
}

class ManyData
{
    Data d1;
    Data d2;
}

...

ManyData md=new ManyData();
md.d1=new Data();
md.d2=md.d1;

尝试使用几种替代方法对md进行序列化/反序列化...


不,不,没关系。我一直使用BF,我们过着幸福的生活 :) - Daniel Mošmondor
2
@Daniel - 并非所有的婚姻都会有好的结局。我非常不喜欢 BF。 - Marc Gravell
@Daniel - 对于二进制数据?我有偏见,但我会使用protobuf-net;速度更快,输出更小,版本兼容性好,可在其他平台之间互操作。 - Marc Gravell
9
“它会针对你班级的私处。”-哎呀,听起来很疼。 :) - Ani
2
@Daniel - 我会尝试二进制,但目前规格要求序列化为XML,可能是因为它将被存储到数据库中,而数据库也应该由人类读取。撇开这些不谈,我忍不住告诉你,我希望SO的每个成员,实际上是每个社区的成员,都能像你一样拥有良好的态度 - 保持下去,你正在走向10万声望。(: - Poni
显示剩余2条评论

5
你目前使用的序列化器是什么?几乎所有的序列化器都可以与其一起使用。但公共字段**一个不好的想法。XmlSerializer和JavaScriptSerializer将忽略私有成员。DataContractSerializer和protobuf-net 可以处理私有成员。BinaryFormatter处理字段(公共或私有),但在我看来,由于许多原因,这不是一个好主意。

Marc,感谢您抽出时间回复 - 正如我在编辑#1中所写的那样,我正在尝试对此类进行XML序列化。此外,“DataContractSerializer”似乎不存在于ASP.NET Web应用程序中。使用VS2008。你有什么建议吗? - Poni
@Poni - 添加对 System.Runtime.Serialization.dll 的引用 - Marc Gravell
“XmlSerializer”存在,但缺少了那个引用……一个小小的缺失属性就能带来如此多的痛苦 :/ - Poni
Yo Marc - 再次感谢。实际上,Brad在另一个SO问题中的回答与你有关,帮助我意识到了一些东西。因此,真的非常感谢! - Poni

2

是的,但在这里有点过头了。 - nawfal


0
使用 IXmlSerializable 接口并控制您想要序列化的字段:
public interface IXmlSerializable
{
    XmlSchema GetSchema();
    void ReadXml(XmlReader reader);
    void WriteXml(XmlWriter writer);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接