ProtoBuf-Net ProtoInclude Generic Type Subclass

前端 未结 2 1681
迷失自我
迷失自我 2020-12-19 12:07

I\'m having some problems with ProtoBuf-Net with a subclass of an object which inherits from a generic class.

My inheritance tree looks like this:

No         


        
相关标签:
2条回答
  • 2020-12-19 12:21

    You're probably seeing:

    A type can only participate in one inheritance hierarchy

    at the moment, right?

    The issue becomes clearer when you recall that ResourceNode<T> is not a closed type - but ResourceNode<Ship> and ResourceNode<SomeType> are. This means 2 things:

    Firstly, Node needs to know separately about the two (ResourceNode<Ship> and ResourceNode<SomeType>), and secondly: we need to tell ResourceNode<Ship> about ShipResource only, and ResourceNode<SomeType> about SomeResource only.

    The first is easy enough with the attribute approach:

    [ProtoContract]
    [ProtoInclude(1, typeof(SomeNodeType)), ProtoInclude(2, typeof(SomeOtherType))]
    [ProtoInclude(3, typeof(ResourceNode<Ship>))]
    [ProtoInclude(4, typeof(ResourceNode<SomeType>))]
    public class Node { }
    

    However, the second bit can't be cleanly expressed in any current release. We can't currently use:

    [ProtoContract]
    [ProtoInclude(1, typeof(ShipResource)), ProtoInclude(1, typeof(SomeResource))]
    public class ResourceNode<T> : Node { }
    

    since those attributes apply to both of ResourceNode<Ship> and ResourceNode<SomeType>, and represent illegal inheritance chains. The duplicated 1 in the above is intentional, as they are not in conflict, again because they are parallel branches.

    What we can do, in v2, is configure this relationship explicitly:

    RuntimeTypeModel.Default.Add(typeof(ResourceNode<Ship>), true)
         .AddSubType(1, typeof (ShipResource));
    RuntimeTypeModel.Default.Add(typeof(ResourceNode<SomeType>), true)
         .AddSubType(1, typeof(SomeResource));
    

    What I want to do is tweak the resolver such that it is able to detect this as a common-case, so that you can simply use the attributes:

    [ProtoContract]
    [ProtoInclude(1, typeof(ShipResource)), ProtoInclude(1, typeof(SomeResource))]
    public class ResourceNode<T> : Node { }
    

    I have added a "todo" item and failing test for this. However, interestingly while setting that up I also found a scenario where something isn't playing happily, so I'll need to fix that first

    0 讨论(0)
  • 2020-12-19 12:28

    I had the exact same problem, but rather than configuring all the types by hand, the method below seems to work for any type. Call it prior to serialization/deserialization.

    private void PopulateTypes(Type t)
    {
        foreach(object mt in RuntimeTypeModel.Default.GetTypes())
        {
            MetaType theType = mt as MetaType;
            if (null != theType)
            {
                if (theType.Type == t)
                    return;
            }
        }
    
        Type objType = typeof (object);
        List<Type> inheritanceTree = new List<Type>();
        do
        {
            inheritanceTree.Insert(0, t);
            t = t.BaseType;
        } while (null != t && t != objType);
    
        if (!inheritanceTree.Any(gt => gt.IsGenericType))
            return;
    
        int n = 100;
        for (int i = 0; i < inheritanceTree.Count - 1; i++)
        {
            Type type = inheritanceTree[i];
            MetaType mt = RuntimeTypeModel.Default.Add(type, true);
            mt.AddSubType(n++, inheritanceTree[i + 1]);
        }
    }
    
    0 讨论(0)
提交回复
热议问题