Protobuf-net 序列化错误 =“一旦生成了序列化程序,就无法更改类型”
Posted
技术标签:
【中文标题】Protobuf-net 序列化错误 =“一旦生成了序列化程序,就无法更改类型”【英文标题】:Protobuf-net serialization error = "The type cannot be changed once a serializer has been generated" 【发布时间】:2011-09-07 11:40:07 【问题描述】:以下场景似乎导致 Protobuf.net 中反序列化异常。我做错了什么吗?有没有办法解决这个问题?
[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();
【问题讨论】:
我很高兴看到,但我在编译您的示例时遇到了困难;添加缺少的ICat
/IAnt
后仍然有一些构建失败。如果我玩得太多,我不知道我在看同样的问题......你能发布一个编译的例子吗?
其实,我认为我有repro...看着
啊,对不起,我在编辑和剪切和粘贴的过程中一定丢失了一些东西。如果您需要我重新复制代码,请告诉我。
抱歉 - IAnt 和 ICat 不应该存在。规则应该是这样的...... public class AntRule1 : IRule
我认为我有足够的时间发布答案 - 无论哪种方式都让我知道。
【参考方案1】:
最终我怀疑这里的问题是:
[ProtoContract]
[ProtoInclude(1, typeof(AntRule1))]
[ProtoInclude(2, typeof(AntRule2))]
[ProtoInclude(3, typeof(CatRule1))]
[ProtoInclude(4, typeof(CatRule2))]
public interface IRule<T> where T : IBeast
这表示对于任何T
,IRule<T>
有 4 个孩子。这样做的副作用是说如果你有多个T
,每个AndRule1
...CatRule2
每个都有“n”个父母,这不好。让我们假设IRule<Ant>
有2 条蚂蚁规则,依此类推……(毕竟,我怀疑CatRule1
真的是IRule<Ant>
的实现)。目前这只能通过RuntimeTypeModel
表达,因为属性总是适用于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));
然后它就可以工作了。注意配置只需要进行一次,通常在应用启动时。
考虑一下,我可以可能只在运行时进行测试,对于泛型,只需忽略任何不适用的 - 我的意思是在评估 IRule<Dog>
时,只考虑特定类型,如果他们实现 IRule<Dog>
。不过,我仍然有两种想法。
【讨论】:
另一个快速准确的响应。效果很好。再次感谢。 @MarcGravell 在使用RuntimeTypeModel
时,您是否还必须使用[ProtoContract]
属性(如果不需要,会使用该属性破坏任何东西)?以上是关于Protobuf-net 序列化错误 =“一旦生成了序列化程序,就无法更改类型”的主要内容,如果未能解决你的问题,请参考以下文章
protobuf-net:反序列化 Guid 属性的错误线型异常
Protobuf-net“反序列化期间引用跟踪对象更改引用”错误(2)
Protobuf-net 错误 - 序列化设置为 null 的固定数组