2

在。NET中可以将字段标记为不可序列化,在序列化过程中会被跳过。

我正在寻找一种简单的方法,该方法允许我在运行时控制是否应序列化特定字段。

4

1 回答 1

3

您指的是“将字段标记为不可序列化”,因此我假设您正在使用BinaryFormatterand [NonSerialized]。如果是这样,进行条件序列化的唯一方法是实现ISerializable和添加类似的构造函数,并将逻辑放入GetObjectData实现中。不过,这很乏味且容易出错。我建议查看 protobuf-net,它具有更简单的条件序列化,使用TypeDescriptorand使用的标准模式XmlSerializer,但仍然是二进制输出(BinaryFormatter实际上比 更有效)。具体来说:

[ProtoContract]
public class SomeType {
    [ProtoMember(1)]
    public string Name {get;set;}

    private bool ShouldSerializeName() {
       // return true to serialize Name, false otherwise
    }
}

ShouldSerialize*是一个标准的基于名称的约定——没有特定于这个序列化程序。

这是相同的 via ISerializable

[Serializable]
public class SomeType : ISerializable
{
    public SomeType() { }
    public string Name { get; set; }


    void ISerializable.GetObjectData(
             SerializationInfo info, StreamingContext context)
    {
        if (/* should serialize Name */) info.AddValue("Name", Name);
        //... all other fields
    }
    protected SomeType(SerializationInfo info, StreamingContext context)
    {
        foreach (SerializationEntry entry in info)
        {
            switch (entry.Name)
            {
                case "Name": Name = (string)entry.Value; break;
                //... all other fields
            }
        }
    }
}

还有更多需要维护;特别是,您必须在使用时对所有成员负责ISerializable- 但是,如果您只使用 protobuf-net,您可以根据具体情况处理每个成员。

实际上,你也可以混合搭配,即如果你坚持使用BinaryFormatter,你仍然可以将工作卸载到 protobuf-net,但它会改变格式(因此不会与旧数据兼容)。例如:

[Serializable, ProtoContract]
public class SomeType : ISerializable
{
    public SomeType() { }
    [ProtoMember(1)]
    public string Name { get; set; }
    private bool ShouldSerializeName() { /* condition */ }

    void ISerializable.GetObjectData(
        SerializationInfo info, StreamingContext context)
    {
        Serializer.Serialize(info, this); 
    }
    protected SomeType(SerializationInfo info, StreamingContext context)
    {
        Serializer.Merge(info, this);
    }
}
于 2012-08-09T09:58:58.687 回答