ProtoBuf无法序列化/反序列化自定义代理列表?

时间:2017-08-10 06:41:46

标签: c# .net protocol-buffers protobuf-net

我们正在尝试使用protobuf序列化,以下模型:

[ProtoContract]
private class Container
{

    [ProtoMember(2)]
    //This does not make much sense in this example, but this is the easiest representation of our biggest model
    public ItemCollection<ISomeOtherInterface> ContainedObjects { get; set; }


    public Container()
    {
        ContainedObjects=  new ItemCollection<ISomeOtherInterface>();
    }
}


[ProtoContract(AsReferenceDefault = true)]
public interface IAnyConfigurationNode
{
    int Id { get; set; }
    String Name { get; set; }
}
[ProtoContract(AsReferenceDefault = true)]
private interface ISomeOtherInterface : IAnyConfigurationNode
{
    int Order { get; set; }
}
[ProtoContract(AsReferenceDefault = true)]
private abstract class SomeBaseType : IAnyConfigurationNode
{
    [ProtoMember(1)]
    public String Name { get; set; }

    [ProtoMember(3)]
    public int Id { get; set; }
}

[ProtoContract(AsReferenceDefault = true)]
private class SomeType : SomeBaseType, ISomeOtherInterface
{
    [ProtoMember(2)]
    public int Order { get; set; }
}

由于我们引用(在这种情况下它确实很有意义,但我们有一些商业案例,我们必须)SomeType虽然另一个界面不在IAnyConfigurationNode - &gt; { {1}} - &gt; SomeBaseType树(我们不能说SomeType扩展SomeTypeSomeBaseType,这将是ProtoBuf中的多种类型,我们有制作了一个代理,基本上将对象保存为ISomeOtherInterface而不是“IAnyConfigurationNode

ISomeOtherInterface

容器中的有趣部分: [ProtoContract] private class ProtoSurrogate<T> where T: class, IAnyConfigurationNode { [ProtoMember(1)] private IAnyConfigurationNode ContainedObject { get; set; } [ProtoConverter] public static ProtoSurrogate<T> To(T toBeSurogated) { return toBeSurogated == null ? null : new ProtoSurrogate<T>() { ContainedObject = toBeSurogated}; } [ProtoConverter] public static T From(ProtoSurrogate<T> surrogate) { return surrogate?.ContainedObject as T; } } 是一个自定义条件(在我们的实际情况中,使用此集合的类提供一些委托来进行一些回调操作(比如将自己设置为其列表中新添加项的父级),如下所示:

ItemCollection

我们有这样指定的遗产/代理:

[ProtoContract(AsReferenceDefault = true)]
public class ItemCollection<T> : ICollection<T>
{
    [ProtoMember(1)]//Only thing that is serialized here
    private readonly List<T> m_items;
    public int Count => m_items.Count;
    public ItemCollection(){m_items = new List<T>();}
    public void Add(T item){m_items.Add(item);}
    public bool Contains(T item){return m_items.Contains(item);}
    public void Clear(){m_items.Clear();}
    public void Sort(){m_items.Sort();}
    IEnumerator<T> IEnumerable<T>.GetEnumerator(){return m_items.GetEnumerator();}
    IEnumerator IEnumerable.GetEnumerator(){return m_items.GetEnumerator();}
    void ICollection<T>.CopyTo(T[] array, int arrayIndex){m_items.CopyTo(array, arrayIndex);}
    bool ICollection<T>.IsReadOnly => false;
    bool ICollection<T>.Remove(T item){return m_items.Remove(item);}
}

然后在最后,我只有一个执行以下操作的UnitTest:

RuntimeTypeModel.Default.Add(typeof(ISomeOtherInterface), false).SetSurrogate(typeof(ProtoSurrogate<ISomeOtherInterface>));
RuntimeTypeModel.Default[typeof(IAnyConfigurationNode)].AddSubType(1000, typeof(SomeBaseType));
RuntimeTypeModel.Default[typeof(SomeBaseType)].AddSubType(1000000, typeof(SomeType));

执行此操作时,我们遇到此错误:

SomeType node = new SomeType { Name = "Name one", Order = 1 ,Id = 1};
Container container = new Container();
container.ContainedObjects.Add(node);
byte[] bytes;
using (MemoryStream stream = new MemoryStream())
{
    Serializer.Serialize(stream, container);
    bytes= stream.ToArray();
}
Container container2;
using (MemoryStream stream = new MemoryStream(bytes))
{
    container2= Serializer.Deserialize<Container>(stream);
}

有趣的部分是System.ArgumentException : Object of type 'Test.ProtoBufSurrogateTest2+ProtoSurrogate`1[ProtoBufSurrogateTest2+ISomeOtherInterface]' cannot be converted to type 'Test.ProtoBufSurrogateTest2+IAnyConfigurationNode'. at System.RuntimeType.TryChangeType(Object value, Binder binder, CultureInfo culture, Boolean needsSpecialCast) at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig) at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, Object[] index) at ProtoBuf.Serializers.PropertyDecorator.Read(Object value, ProtoReader source) in D:\Dev\BB\Src\External\Protobuf-Net2\Serializers\PropertyDecorator.cs:line 82 at ProtoBuf.Serializers.TypeSerializer.Read(Object value, ProtoReader source) in D:\Dev\BB\Src\External\Protobuf-Net2\Serializers\TypeSerializer.cs:line 227 at ProtoBuf.Serializers.SurrogateSerializer.Read(Object value, ProtoReader source) in D:\Dev\BB\Src\External\Protobuf-Net2\Serializers\SurrogateSerializer.cs:line 129 at ProtoBuf.Meta.RuntimeTypeModel.Deserialize(Int32 key, Object value, ProtoReader source) in D:\Dev\BB\Src\External\Protobuf-Net2\Meta\RuntimeTypeModel.cs:line 832 at ProtoBuf.ProtoReader.ReadTypedObject(Object value, Int32 key, ProtoReader reader, Type type) in D:\Dev\BB\Src\External\Protobuf-Net2\ProtoReader.cs:line 607 at ProtoBuf.BclHelpers.ReadNetObject(Object value, ProtoReader source, Int32 key, Type type, NetObjectOptions options) in D:\Dev\BB\Src\External\Protobuf-Net2\BclHelpers.cs:line 616 at ProtoBuf.Serializers.NetObjectSerializer.Read(Object value, ProtoReader source) in D:\Dev\BB\Src\External\Protobuf-Net2\Serializers\NetObjectSerializer.cs:line 45 at ProtoBuf.Serializers.TagDecorator.Read(Object value, ProtoReader source) in D:\Dev\BB\Src\External\Protobuf-Net2\Serializers\TagDecorator.cs:line 80 at ProtoBuf.Serializers.ListDecorator.Read(Object value, ProtoReader source) in D:\Dev\BB\Src\External\Protobuf-Net2\Serializers\ListDecorator.cs:line 563 at ProtoBuf.Serializers.PropertyDecorator.Read(Object value, ProtoReader source) in D:\Dev\BB\Src\External\Protobuf-Net2\Serializers\PropertyDecorator.cs:line 77 at ProtoBuf.Serializers.TypeSerializer.Read(Object value, ProtoReader source) in D:\Dev\BB\Src\External\Protobuf-Net2\Serializers\TypeSerializer.cs:line 227 at ProtoBuf.Meta.RuntimeTypeModel.Deserialize(Int32 key, Object value, ProtoReader source) in D:\Dev\BB\Src\External\Protobuf-Net2\Meta\RuntimeTypeModel.cs:line 832 at ProtoBuf.Meta.TypeModel.DeserializeCore(ProtoReader reader, Type type, Object value, Boolean noAutoCreate) in D:\Dev\BB\Src\External\Protobuf-Net2\Meta\TypeModel.cs:line 744 at ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, Type type, SerializationContext context) in D:\Dev\BB\Src\External\Protobuf-Net2\Meta\TypeModel.cs:line 607 at ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, Type type) in D:\Dev\BB\Src\External\Protobuf-Net2\Meta\TypeModel.cs:line 584 at ProtoBuf.Serializer.Deserialize[T](Stream source) in D:\Dev\BB\Src\External\Protobuf-Net2\Serializer.cs:line 84 at Test.ProtoBufSurrogateTest2.TestSurrogateHavingReferenceType() in D:\XXXXXXXTest\ProtoBufSurrogateTest2.cs:line 41 课程中的IF,我只是为简单Container而不是ContainedObject更改List的类型,一切运作良好。< / p>

我已经采用了ProtoBuf代码,进行了一些调查,似乎它与使用的序列化器不同。如果我们有自定义列表,我们会在某些时候使用ItemCollection,如果我们使用标准列表,则使用TypeSerializer。在这种情况下,我们快速调用SubItemSerializer,它试图BclHelper.ReadNetObject第一个“下一个”对象,在这种情况下是代理。在正常情况下,我们不Trap代理,而是子项。

我知道它会生成很多代码,所以我已经实现了一个完整的UnitTest来显示问题: https://pastebin.com/auhm35EH

我正在尝试调试3天,我真的希望@MarcGravell能够提供一点帮助。

0 个答案:

没有答案
相关问题