Protobuf字典diserialization抛出空键异常

时间:2017-03-02 15:04:58

标签: c# dictionary exception deserialization protobuf-net

我正在使用C#撰写protobuf-net上的项目。我有代码将Dictionary<MyClass1, MyClass2>序列化/反序列化为文件。另外,我有一个包含序列化数据的文件。当我尝试反序列化时,我收到异常key无法null。由于Dictionary不允许null,我不明白它是如何可能的,看起来我无法序列化这样的词典。我认为该文件已损坏,但我不确定。我试图调试它,看起来几个键和值被正确反序列化,但在反序列化过程中,null键出现,我看到异常。我尝试使用ProductName代理here,但它没有帮助。

如何反序列化此文件? 可能有一种方法可以反序列化到某个对象,而不是null的{​​{1}}吗?

例外:

  

System.ArgumentNullException:值不能为null。   参数名称:key      在System.Collections.Generic.Dictionary ProductName 2.System.Collections.Generic.ICollection&gt; .Add(KeyValuePair`2 keyValuePair)      在proto_10(Object,ProtoReader)      at ProtoBuf.Meta.TypeModel.DeserializeCore(ProtoReader reader,Type type,Object value,Boolean noAutoCreate)in c:\ Dev \ protobuf-net \ protobuf-net \ Meta \ TypeModel.cs:line 704      at ProtoBuf.Meta.TypeModel.Deserialize(流源,对象值,类型类型,SerializationContext上下文)在c:\ Dev \ protobuf-net \ protobuf-net \ Meta \ TypeModel.cs:第588行      在ProtoBuf.Serializer.Deserialize [T](流源)c:\ Dev \ protobuf-net \ protobuf-net \ Serializer.cs:第77行

代码:

2.Insert(TKey key, TValue value, Boolean add)
     at System.Collections.Generic.Dictionary

1 个答案:

答案 0 :(得分:0)

首先,要测试文件是否确实已损坏,您可以尝试按照Recovering corrupted file serialize with Protobuf-net中的说明检查文件是否已损坏。

接下来,无论文件是否损坏,要尽可能反序列化,您可以使用Serializer.Merge<T>(Stream source, T instance)将文件合并到预先分配的ProductNameIndex上,如下所示:

var index = new ProductNameIndex();
try
{
    Serializer.Merge(stream, index);
}
catch (Exception ex)
{
    // Log the error
    Debug.WriteLine(ex);
}

index现在应包含尽可能多的条目,以便完全反序列化。

现在,如果文件 损坏,除非您想将其加载到MemoryStream并尝试逐字节手动修复,否则这可能是您可以做的最好的事情。 。但是如果文件损坏,则需要调试以找出问题所在。要采取的一项措施是将为ProductNameIndex生成的合同与文件中实际使用的合同进行比较。要查看ProductNameIndex的合同,您可以执行以下操作:

Debug.WriteLine(ProtoBuf.Meta.RuntimeTypeModel.Default.GetSchema(typeof(ProductNameIndex)));

然后比较Recovering corrupted file serialize with Protobuf-net的输出,我相信只转储顶级字段。如果字段编号和连线类型不匹配,您将知道您正在读取其根对象实际上不是ProductNameIndex的文件。您还可以使用GetSchema()中的合同infortmation手动进入重复字段(字符串)和嵌套对象。

最后,如果合同匹配,但发送系统发出KeyValuePair_ProductName_ProductId消息时遗漏了optional ProductName Key,您可以修改ProductNameIndex以使用代理项忽略此类无效条目数组属性:

[DataContract]
[ProtoContract]
public class ProductNameIndex
{
    [ProtoMember(1, Name = "Products")]
    KeyValuePair<ProductName, ProductId>[] ProductsSurrogateArray
    {
        get
        {
            return Products.ToArray();
        }
        set
        {
            if (value == null)
                return;
            foreach (var p in value)
            {
                if (p.Key == null)
                    Debug.WriteLine("Ignoring invalid null key");
                else
                    Products.Add(p);
            }
        }
    }

    [ProtoIgnore]
    [DataMember(Order = 1)]
    public IDictionary<ProductName, ProductId> Products { get; private set; }

    public ProductNameIndex()
    {
        this.Products = new Dictionary<ProductName, ProductId>();
    }
}

或者,如果您无法为您的类型添加protobuf属性,您可以为ProductNameIndex引入代理类型并进行必要的检查,如here所述。

最后,看看Using Protobuf-net, I suddenly got an exception about an unknown wire-type,它有一些诊断protobuf-net问题的有用建议,包括:

  

最可能的原因(根据我的经验)是您已覆盖现有文件,但未截断它;即它是200字节;你重写了它,但只有182个字节。现在流的末尾有18个字节的垃圾正在绊倒它。重写协议缓冲区时必须截断文件。