我可以根据proto buf序列化比较对象

时间:2011-11-16 09:36:34

标签: c# comparison protobuf-net

我有一些模型对象,我保存在使用protobuf序列化的数据库中。我想将我将保存的版本与现有版本进行比较,以避免将相同版本添加两次。

理想情况下我应该

byte[] existingBlob = GetFromDBExistingModelObject();
ModelType existingModel = existingBlob.Deserialize();
if (!model.Equals(existingModel))
{
    byte[] serializedModel = model.Serialize();
    Save(serializedModel); //Save in DB the new blob
}

但是我必须在每个模型对象上实现.Equals,这非常痛苦。我想做

byte[] existingBlob = GetFromDBExistingModelObject();
byte[] serializedModel = model.Serialize();
if (!compareBlob(existingBlob, serializedModel)
{
    Save(serializedModel);
}

private bool compareBlob(byte[] existingBlob, byte[] serializedModel)
{
    if (serializedModel.Length != existingBlob.Length)
    {
        return false;
    }

    return !serializedModel.Where((t, i) => t != existingBlob[i]).Any();
}

我也是为了表现,因为我没有反序列化existingBlob

您对此实施有何看法?你认为我可以依靠这种比较吗?我使用protobuf进行序列化。

感谢您的评论。

1 个答案:

答案 0 :(得分:1)

protobuf-net 产生可预测的输出,但严格来说不受规范保证; - 有两个边缘情况(字段顺序和子规范形式用于varint编码)技术上可以产生具有相同含义的不同输出,但是protobuf-net将始终产生相同的输出。

玩弄故意使用子正常varint表单来避免一些内存改组,但这只是选择加入。

因此;只要你没有通过附加构建你的二进制文件(protobuf是一种可附加的格式,但显然所有的赌注都是关闭的,如果你以任意顺序附加),那么是:线上的数据应该是可预测的,你可以比较字节序列来测试是否相等。

作为次要注释,为了提高效率,我建议在此处使用常规for循环:

if (serializedModel.Length != existingBlob.Length)
{
    return false;
}
for(int i = 0 ; i < serializedModel.Length ; i++)
    if(serializedModel[i] != existingBlob[i]) return false;
return true;

(如果您特别速度疯狂,您甚至可以使用unsafe代码并将其作为int*long*进行比较(取1 / 4或1/8的测试),并手动检查最后几个字节)

您也可以考虑比较 hash (sha1等)而不是逐字节;这对于大型模型尤其有用,特别是如果您可以将散列值与原始值一起存储(因此您永远不必获取原始的现有BLOB - 只是现有的散列)。


:具体来说,varint“big end”的位序列1000000000000000只是意味着“大端的零点更多”(有或没有更多数据要遵循),因此对数量没有影响;因此,varint末尾的任何(合理)数量的0x80 0x80 0x00都不会改变结果;有一个用例,通过故意使用超大的varint作为长度前缀,可以用来避免必须移动数据。