【问题标题】:Differences with BinaryFormatter与 BinaryFormatter 的区别
【发布时间】:2012-04-06 16:45:27
【问题描述】:

我正在尝试更改现有 WCF net.tcp 项目中的序列化程序,该项目在客户端和服务器上使用共享实体。我很难弄清楚 protobuf-net(V2480) 图表here 说我可以序列化私有成员但找不到执行此操作的文档,是否可以没有属性?如何按照here 的说明启用图形模式(作为参考)

这会解决 protobuf 触发我的已更改项目标志的问题吗?例如我有一堂课

 public enum FirstEnum
{ 
    First = 0,
    Second,
    Third
}
public enum AnotherEnum
{ 
    AE1 = 0,
    AE2,
    AE3
}
[Serializable()]
public class SomeClass
{
    public int SomeClassId { get; set; }
    public FirstEnum FEnum { get; set; }
    public AnotherEnum AEnum { get; set; }
    string thing;
    public string Thing
    {
        get{return thing;}
        set
        {
            if (string.IsNullOrEmpty(value))
                throw new ArgumentNullException("Thing");

            thing = value;
        }
    }

    private decimal firstAmount;
    public decimal FirstAmount 
    { 
        get{return firstAmount;} 
        set
        {
            if (value != firstAmount)
            {
                firstAmount = value;
                changedItems.Add("FirstAmount changed");
            }
        }
    }
    private decimal secondAmount;
    public decimal SecondAmount
    {
        get { return secondAmount; }
        set
        {
            if (value != secondAmount)
            {
                secondAmount = value;
                changedItems.Add("SecondAmount changed");
            }
        }
    }
    public decimal ThirdAmount { get { return SecondAmount - FirstAmount; } }
    public DateTime? SomeDate { get; set; }

    private List<string> changedItems = new List<string>();
    public List<string> ChangedItems
    {
        get { return changedItems; }
    }
public int PrivateSet { get; private set; }
    public SomeClass() { }

    public SomeClass(decimal first, decimal second)
    {
        FirstAmount = first;
        SecondAmount = second;
    }

    public void ClearChangedItems()
    {
        changedItems.Clear();
    }

当我用 (1000 个项目) 反序列化它时

 var model = CreateModel();
 items = (List<SomeClass>)model.Deserialize(returnStream, null, typeof(List<SomeClass>));

2012-04-06 09:14:28.1222|DEBUG|ProtobufTEsts.Form1|ProtoBuf 更改项数:1000

使用 BinaryFormatter

System.Runtime.Serialization.Formatters.Binary.BinaryFormatter binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
items = (List<SomeClass>)binaryFormatter.Deserialize(returnStream);

2012-04-06 09:14:28.1662|DEBUG|ProtobufTEsts.Form1|BinaryFormatter 更改项数:0

有没有办法让 protobuf 表现得像 binaryFormatter 但保留 protobuf 的性能?

如何允许私有序列化,这失败了

 public static TypeModel CreateModel()
    {
        RuntimeTypeModel model = TypeModel.Create();
        ///var metaType = RuntimeTypeModel.Default.Add(typeof(SomeClass), false);
        model.Add(typeof(SomeClass), false)
            .Add(1, "SomeClassId")
            .Add(2, "FEnum")
            .Add(3, "AEnum")
            .Add(4, "Thing")
            .Add(5, "FirstAmount")
            .Add(6, "SecondAmount")
            .Add(7, "SomeDate")
            .Add(8, "PrivateSet");
        TypeModel compiled = model.Compile();
        return compiled;
    }

【问题讨论】:

  • Re AsReference - IIRC(同样,仍然不是在 PC 上)有一个 MetaType.Add 的变体,它返回 ValueMember;这上面有 AsReference 开关(和许多其他选项)。

标签: c# serialization protobuf-net


【解决方案1】:

啊,我现在明白这个问题了;这行有问题:

TypeModel compiled = model.Compile();
return compiled;

如果您使用 Compile(),它会创建一个正式的程序集(在内存中),该程序集必须遵守程序集的通常规则,特别是:成员可访问性。这意味着它无法访问您的私有 sertter。

改为:

model.CompileInPlace();
return model;

这会执行部分编译,但会继续使用 DynamicMethod。这个厚脸皮的小动物可以选择通过可访问性规则进行欺骗(很像反射可以),因此它可以继续使用私有 setter。

请注意,模型也会根据需要在原地编译(在更细粒度的级别),因此对 CompileInPlace 的调用不是严格必要的,但有助于完成所有工作- 提前一个。

为了完整起见,还有一个额外的 Compile(string,string) 重载,可用于在磁盘上生成单独的序列化 dll,在运行时无需任何元编程即可引用和使用.

【讨论】:

    【解决方案2】:

    是的 protobuf-net 可以序列化私有字段,并且没有属性。我不在电脑上,所以这可能需要调整:

    var metaType = RuntimeTypeModel.Default.Add(typeof(SomeClass), false);
    // for each field in a known order
    metaType.Add(fieldName, someUniqueTag);
    

    在属性驱动的用法中,还有 ImplicitFields.AllFields 会自动配置它以供您使用,但我还没有向 MetaType 添加 ImplicitFields 辅助方法。我会把它添加到我的列表中!

    注意:标签(=field)数字对 protobuf 很重要,并且在反序列化时必须能够重现相同的数字映射。

    您可能要考虑的另一个选项是(反)序列化回调,它可以让您知道它当前正在序列化/反序列化(通过 before/after 方法调用)。这可能是另一种禁用间隔的副作用的方法,例如反序列化。

    【讨论】:

    • @Mark,谢谢,如何从 metaType 转到 RuntimeTypeModel?我在上面添加了createModel代码
    • @Eric 不在电脑前...有 .Model 吗?
    • 不,只有在我在编辑中添加的 CreateModel 方法中创建的内容,我需要做一些不同的事情吗?
    • @Eric 我很困惑;您的方法已经具有模型和元类型。你能澄清一下你卡在哪里了吗?
    • @Mark 当我调用 var model = CreateModel();模型.序列化(文件,项目);我得到无法对属性 ProtobufTEsts.SomeClass.PrivateSet 应用更改
    猜你喜欢
    • 2010-11-12
    • 1970-01-01
    • 2011-04-04
    • 1970-01-01
    • 2015-02-05
    • 2011-11-19
    • 2013-03-14
    • 2017-11-13
    • 1970-01-01
    相关资源
    最近更新 更多