【问题标题】:.net serialization: how to selectively ignore data fields.net 序列化:如何选择性地忽略数据字段
【发布时间】:2012-08-09 09:46:33
【问题描述】:

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

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

【问题讨论】:

  • .NET 序列化可能意味着多种情况,例如Xml/Binary/Json...你指的是什么类型的序列化?
  • @OphirYoktan “二进制序列化”实际上很模糊;我们是否应该假设这实际上意味着BinaryFormatter?两者不是同义词; .NET 有多个二进制序列化程序,包括在框架中(例如,NetDataContractSerializer)和作为外部库(protobuf-net、msgpack 等)

标签: .net binary-serialization


【解决方案1】:

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-06
    • 2010-11-27
    相关资源
    最近更新 更多