Protobuf-net 序列化错误 =“一旦生成序列化程序,就不能更改类型"; [英] Protobuf-net serialization error = "The type cannot be changed once a serializer has been generated"

查看:20
本文介绍了Protobuf-net 序列化错误 =“一旦生成序列化程序,就不能更改类型";的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下场景似乎会导致 Protobuf.net 中的反序列化异常.我做错了什么吗?有没有办法解决这个问题?

The following scenario seems to cause the exception in Protobuf.net on deserialization. Have I done something wrong? Is there a way round this?

[ProtoContract]
[ProtoInclude(2, typeof(Ant))]
[ProtoInclude(3, typeof(Cat))]
public interface IBeast
{
    [ProtoMember(1)]
    string Name { get; set; }
}

[ProtoContract]
public class Ant : IBeast
{
    public string Name { get; set; }
}

[ProtoContract]
public class Cat : IBeast
{
    public string Name { get; set; }
}

[ProtoContract]
[ProtoInclude(1, typeof(AntRule1))]
[ProtoInclude(2, typeof(AntRule2))]
[ProtoInclude(3, typeof(CatRule1))]
[ProtoInclude(4, typeof(CatRule2))]
public interface IRule<T> where T : IBeast
{
    bool IsHappy(T beast);
}

[ProtoContract]
public class AntRule1 : IRule<Ant>
{
    public bool IsHappy(IAnt beast)
    {
        return true;
    }
}

[ProtoContract]
public class AntRule2 : IRule<Ant>
{
    public bool IsHappy(IAnt beast)
    {
        return true;
    }
}

[ProtoContract]
public class CatRule1 : IRule<Cat>
{
    public bool IsHappy(ICat beast)
    {
        return true;
    }
}

[ProtoContract]
public class CatRule2 : IRule<Cat>
{
    public bool IsHappy(ICat beast)
    {
        return true;
    }
}

public class TestSerialization
{
    public void Serialize()
    {
        var antRules = new List<IRule<Ant>>();
        antRules.Add(new AntRule1());
        antRules.Add(new AntRule2());

        var catRules = new List<IRule<Cat>>();
        catRules.Add(new CatRule1());
        catRules.Add(new CatRule2());

        using (var fs = File.Create(@"c:\temp\antRules.bin"))
        {
            ProtoBuf.Serializer.Serialize(fs, antRules);

            fs.Close();
        }

        using (var fs = File.OpenRead(@"c:\temp\antRules.bin"))
        {
            List<IRule<Ant>> list;
            list = ProtoBuf.Serializer.Deserialize<List<IRule<Ant>>>(fs);

            fs.Close();
        }

        using (var fs = File.Create(@"c:\temp\catRules.bin"))
        {
            ProtoBuf.Serializer.Serialize(fs, catRules);

            fs.Close();
        }

        using (var fs = File.OpenRead(@"c:\temp\catRules.bin"))
        {
            List<IRule<Cat>> list;
            list = ProtoBuf.Serializer.Deserialize<List<IRule<Cat>>>(fs);

            fs.Close();
        }
    }
}

推荐答案

最终我怀疑这里的问题是:

Ultimately I suspect the issue here is:

    [ProtoContract]
    [ProtoInclude(1, typeof(AntRule1))]
    [ProtoInclude(2, typeof(AntRule2))]
    [ProtoInclude(3, typeof(CatRule1))]
    [ProtoInclude(4, typeof(CatRule2))]
    public interface IRule<T> where T : IBeast

这表示对于任何 TIRule 有 4 个孩子.这具有说if你有多个T的副作用,每个AndRule1...CatRule2每个人都有n"个父母,这不好.让我们假设 IRule 有 2 个蚂蚁规则,依此类推......(毕竟,我怀疑 CatRule1 是否真的是 IRule).目前这只能通过 RuntimeTypeModel 来表达,因为这些属性总是适用于 all T:

This says that for any T, IRule<T> has 4 children. This has the side effect of saying if you have more than one T, each of AndRule1...CatRule2 each have "n" parents, which isn't good. Let's instead assume that IRule<Ant> has 2 ant-rules, and so on... (after all, I doubt that CatRule1 is really an implementation of IRule<Ant>). Currently this can only be expressed via RuntimeTypeModel, since the attributes would always apply for all T:

[ProtoContract]
public interface IRule<T> where T : IBeast

// note these are unrelated networks, so we can use the same field-numbers
RuntimeTypeModel.Default[typeof(IRule<Ant>)]
    .AddSubType(1, typeof(AntRule1)).AddSubType(2, typeof(AntRule2));
RuntimeTypeModel.Default[typeof(IRule<Cat>)]
    .AddSubType(1, typeof(CatRule1)).AddSubType(2, typeof(CatRule2));

然后它就起作用了.请注意,配置只需进行一次,通常在应用启动时进行.

and then it works. Note the configuration only needs to be done once, usually at app-startup.

考虑一下,我可以可能只在运行时进行测试,而在泛型的情况下,只需忽略任何不适用的 - 我的意思是在评估 IRule;,如果它们实现 IRule,则只考虑特定类型.不过,我仍然有两种想法.

Thinking about it, I could probably just test at runtime, and in the case of generics simply ignore any that don't apply - by which I mean when evaluating IRule<Dog>, only consider the specific types if they implement IRule<Dog>. I'm still in two minds, though.

这篇关于Protobuf-net 序列化错误 =“一旦生成序列化程序,就不能更改类型";的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆