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

本文关键字:序列化 类型 继承 何使用 protobuf-net 代理 | 更新日期: 2023-09-27 18:11:15

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

作为一个例子,我有这两个代理类
    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));

当我尝试序列化这个时,它被序列化为point2d而不是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

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

根据两个答案得出(谢谢!!)

    [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
    {
    }

您是否尝试在PointF2D中使用ProtoInclude来包含GeoCoordinate ?这样的:

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

这应该强制它使用代理SerializableGeoCoordinate

所以:你有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);
    }
}