如何使用protobuf-net代理序列化继承链中的类型?

时间:2013-04-26 20:49:44

标签: c# inheritance protobuf-net

如果在ineritance链中有两个(或更多)类(在这种情况下GeoCoordinate从PointF2D继承),如何正确使用代理以允许任一类型的序列化?

作为一个例子,我有这两个代理类

    public class SerializablePointF2D
    {
        [ProtoMember(1)]
        public double[] Values { get; set; }

        public static implicit operator SerializablePointF2D(PointF2D value)
        {
            return value == null ? null : new SerializablePointF2D {Values = value.ToArrayCopy()} ;
        }`enter code here`
        public static implicit operator PointF2D(SerializablePointF2D value)
        {
            return value == null ? null : new PointF2D(value.Values);
        }
    }
    [ProtoContract]
    public class SerializableGeoCoordinate        {
        [ProtoMember(1)]
        public double[] Values { get; set; }

        public static implicit operator SerializableGeoCoordinate(GeoCoordinate value)
        {
            return value == null ? null : new SerializableGeoCoordinate { Values = value.ToArrayCopy() };
        }
        public static implicit operator GeoCoordinate(SerializableGeoCoordinate value)
        {
            return value == null ? null : new GeoCoordinate(value.Values);
        }
    }

此代码设置模型

        var model = TypeModel.Create();
        //GeoCoordinate
        model.Add(typeof(PrimitiveSimpleF2D), false).AddSubType(1, typeof(PointF2D));
        model.Add(typeof(PointF2D), false).AddSubType(4, typeof(GeoCoordinate)).SetSurrogate(typeof(SerializablePointF2D));            
        model.Add(typeof(GeoCoordinate), false).SetSurrogate(typeof(SerializableGeoCoordinate));

当我尝试序列化它时,它被序列化为PointF2D而不是GeoCoordinate。我已经尝试了我能想到的每种订购组合 编辑: 根据Marc的代码,我试过

    [ProtoContract]
    public class SerializablePointF2D
    {
        [ProtoMember(1)]
        public double[] Values { get; set; }

        public static implicit operator SerializablePointF2D(PointF2D value)
        {
            if (value == null) return null;
            var geoCoordinate = value as GeoCoordinate;
            if (geoCoordinate != null) return new SerializableGeoCoordinate
            {
                Values = geoCoordinate.ToArrayCopy(),
            };
            return new SerializablePointF2D {Values = value.ToArrayCopy()};
        }
        public static implicit operator PointF2D(SerializablePointF2D value)
        {
            return value == null ? null : new PointF2D(value.Values);
        }
    }
    [ProtoContract]
    public class SerializableGeoCoordinate:SerializablePointF2D
    {

    }

我认为看起来正确。它失败了

System.InvalidOperationException : Unexpected sub-type: OsmSharp.Serialization.OsmSharpSerializer+SerializableGeoCoordinate

3 个答案:

答案 0 :(得分:2)

根据两个答案得到它(谢谢!!!)

    [ProtoContract]
    [ProtoInclude(2, typeof(SerializableGeoCoordinate))]
    public class SerializablePointF2D
    {
        [ProtoMember(1)]
        public double[] Values { get; set; }

        public static implicit operator SerializablePointF2D(PointF2D value)
        {
            if (value == null) return null;
            var geoCoordinate = value as GeoCoordinate;
            if (geoCoordinate != null) return new SerializableGeoCoordinate
            {
                Values = geoCoordinate.ToArrayCopy(),
            };
            return new SerializablePointF2D {Values = value.ToArrayCopy()};
        }
        public static implicit operator PointF2D(SerializablePointF2D value)
        {
            if (value == null) return null;
            var geoCoordinate = value as SerializableGeoCoordinate;
            if (geoCoordinate != null)
            {
                return new GeoCoordinate(geoCoordinate.Values);
            }
            return new PointF2D (value.Values );
        }
    }
    [ProtoContract]
    public class SerializableGeoCoordinate:SerializablePointF2D
    {
    }

答案 1 :(得分:1)

所以:你有3个不可序列化的类型,并且你想为它们添加代理?也许这里的诀窍是要意识到protobuf-net总是转到任何继承模型的根源 - 所以如果在那里声明了代理: 它赢了 ;代理人完全接管序列化/反序列化过程。以下通过使代理模仿原始的继承 - 任何用途?

using ProtoBuf;
using ProtoBuf.Meta;
using System;
public class A
{
    // we'll use this to detect how it was constructed
    public bool ViaOperator { get; set; }

    public int X { get; set; }
}
public class B : A
{
    public int Y { get; set; }
}
public class C : B
{
    public int Z { get; set; }
}


[ProtoContract, ProtoInclude(1, typeof(BSer))]
public class ASer
{
    [ProtoMember(2)] public int X { get; set; }

    protected virtual A ToA()
    {
        return new A { X = X };
    }

    public static implicit operator A(ASer value)
    {
        if (value == null) return null;
        var a = value.ToA();
        a.ViaOperator = true;
        return a;
    }
    public static implicit operator ASer(A value)
    {
        if (value == null) return null;
        var c = value as C;
        if(c != null) return new CSer {
            X = c.X, Y = c.Y, Z = c.Z};
        var b = value as B;
        if(b != null) return new BSer {
            X = b.X, Y = b.Y };
        return new ASer { X = value.X };
    }
}
[ProtoContract, ProtoInclude(1, typeof(CSer))]
public class BSer : ASer
{
    [ProtoMember(2)] public int Y { get; set; }

    protected override A ToA()
    {
        return new B { X = X, Y = Y };
    }
}
[ProtoContract]
public class CSer : BSer
{
    [ProtoMember(2)] public int Z { get; set; }

    protected override A ToA()
    {
        return new C { X = X, Y = Y, Z = Z };
    }
}

static class Program
{
    static void Main()
    {
        var model = TypeModel.Create();
        model.Add(typeof(A), false).AddSubType(2, typeof(B)).SetSurrogate(typeof(ASer));
        model[typeof(B)].AddSubType(2, typeof(C));

        A obj = new B { X = 1, Y = 2 };

        var clone = (B)model.DeepClone(obj);
        Console.WriteLine("{0}, {1}, {2}", clone.X, clone.Y, clone.ViaOperator);

    }
}

答案 2 :(得分:1)

您是否尝试过使用ProtoInclude中的PointF2D来加入GeoCoordinate?像这样:

[Serializable,
ProtoContract(ImplicitFields = ImplicitFields.AllFields, ImplicitFirstTag = 1), 
ProtoInclude(20, "GeoCoordinate")]
public class PointF2D
{
...etc...
}

这应该强制它使用代理SerializableGeoCoordinate