Protobuf-net serialization error = " тип не может быть изменен после создания сериализатора"
Следующий сценарий, по-видимому, вызывает исключение в 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:tempantRules.bin"))
{
ProtoBuf.Serializer.Serialize(fs, antRules);
fs.Close();
}
using (var fs = File.OpenRead(@"c:tempantRules.bin"))
{
List<IRule<Ant>> list;
list = ProtoBuf.Serializer.Deserialize<List<IRule<Ant>>>(fs);
fs.Close();
}
using (var fs = File.Create(@"c:tempcatRules.bin"))
{
ProtoBuf.Serializer.Serialize(fs, catRules);
fs.Close();
}
using (var fs = File.OpenRead(@"c:tempcatRules.bin"))
{
List<IRule<Cat>> list;
list = ProtoBuf.Serializer.Deserialize<List<IRule<Cat>>>(fs);
fs.Close();
}
}
}
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
...У каждого из них есть" n " родителей, что не очень хорошо. Давайте вместо этого предположим, чтоIRule<Ant>
имеет 2 муравьиных правила и так далее... (в конце концов, я сомневаюсь, чтоCatRule1
действительно является реализациейIRule<Ant>
). В настоящее время это может быть выражено только черезRuntimeTypeModel
, так как атрибуты будут применяться всегда для всех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>
. Но я все еще в двух головах.