序列化私人成员数据


74

我正在尝试将对象序列化为具有许多属性的XML,其中一些属性为只读。

public Guid Id { get; private set; }

我已经标记了[Serializable]类,并且实现了ISerializable接口。

下面是我用来序列化对象的代码。

public void SaveMyObject(MyObject obj)
{
    XmlSerializer serializer = new XmlSerializer(typeof(MyObject));
    TextWriter tw = new StreamWriter(_location);
    serializer.Serialize(tw, obj);
    tw.Close();
}

不幸的是,它落在此消息的第一行。

未处理InvalidOperationException:无法生成临时类(结果= 1)。错误CS0200:无法将属性或索引器'MyObject.Id'分配给它-只读

如果我将Id属性设置为public,则效果很好。有人可以告诉我我是否正在做某事,或者至少可以做某件事?

Answers:


62

您可以使用DataContractSerializer(但请注意,您不能使用xml属性-只能使用xml元素):

using System;
using System.Runtime.Serialization;
using System.Xml;
[DataContract]
class MyObject {
    public MyObject(Guid id) { this.id = id; }
    [DataMember(Name="Id")]
    private Guid id;
    public Guid Id { get {return id;}}
}
static class Program {
    static void Main() {
        var ser = new DataContractSerializer(typeof(MyObject));
        var obj = new MyObject(Guid.NewGuid());
        using(XmlWriter xw = XmlWriter.Create(Console.Out)) {
            ser.WriteObject(xw, obj);
        }
    }
}

另外,您也可以IXmlSerializable自己实施和执行所有操作-但这XmlSerializer至少可以与一起使用。


我已经更改了代码以使用DataContractSerializer,并且注意到它仍在运行GetObjectData方法。我是否在考虑可以将属性放在属性上以对其进行序列化,还是可以实现ISerializable接口?
乔恩·米切尔

如果您实现ISerializable(或IXmlSeializable?),则基本上是您自己在做所有工作……
Marc Gravell

4
这对我有用,但是后来我发现,使用DataMemberAttribute序列化私有成员仅在完全信任环境下运行,而不是在部分信任环境下运行。一种解决方案是使成员成为内部成员而不是私有成员。有关详细信息,请参阅blog.walteralmeida.com/2010/05/…
佩拉道

6

您可以使用System.Runtime.Serialization.NetDataContractSerializer。它功能更强大,并修复了经典Xml Serializer的某些问题。

请注意,此属性有不同的属性。

[DataContract]
public class X
{
  [DataMember]
  public Guid Id { get; private set; }
}


NetDataContractSerializer serializer = new NetDataContractSerializer();
TextWriter tw = new StreamWriter(_location);
serializer.Serialize(tw, obj);

编辑:

根据Marc的评论进行更新:您可能应该使用 System.Runtime.Serialization.DataContractSerializer在案例中以获得清晰的XML。其余代码相同。


NetDataContractSerializer不会写xml ...-或者,它不是适合外部使用的干净xml-它具有程序集元数据。
马克·格拉韦尔

@马克:谢谢你的提示。它总是取决于人们想要实现的目标。DataContractSerializer可能是这里期望的。
Stefan Steinegger,2009年

2

只读字段将不会使用 XmlSerializer,这是由于readonly关键字的性质

从MSDN:

只读关键字是修改,你可以在字段中使用。当字段声明包含只读修饰符时,对声明所引入的字段的分配只能作为声明的一部分或在同一类的构造函数中进行。

所以...您几乎需要在默认构造函数中设置字段值...


我以为,因为我已经实现了ISerializable.GetObjectData方法,所以XmlSerializer会使用它来获取我想要序列化的信息,而不是尝试访问只读属性。
乔恩·米切尔

XmlSerializer不在乎ISerializable-仅在乎IXmlSerializable
Marc Gravell

0

使用特定的序列化模式是不可能的(有关其他解决方法,请参见其他注释)。如果您真的想保持序列化模式不变,则必须解决该框架的限制。看到这个例子

实质上,标记属性public,但是如果在除反序列化之外的任何时间都可以访问它,则抛出异常。


5
“但是抛出异常”-由于XmlSerializer不支持序列化回调,因此您无法知道...
Marc Gravell

1
您可以使用它System.Diagnostics.StackTrace来查找所谓的财产,但我不建议您使用这种解决方案:-)
路易·萨默斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.