2013-04-26 50 views
1

如果你在一個無害鏈中有兩個(或更多)類(在這種情況下GeoCoordinate繼承自PointF2D),你如何正確使用代理來允許兩種類型的序列化?如何序列化繼承鏈中的類型與protobuf-net代理?

舉個例子,我有這兩個代理類

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而不是會有地理座標。我試着訂購我能想到 編輯的每個組合:基於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 

回答

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

所以:你有3個不可序列化的類型,你想爲它們添加代理嗎?也許這裏的訣竅是要認識到,protobuf網總是去任何繼承模型的根源 - 所以如果在那裏宣佈代理人:它贏得;代理人完全接管了序列化/反序列化過程。通過使替代品模仿原件的繼承 - 任何使用?

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); 

    } 
} 
+0

我的兩個類是相同的數據,我將如何改變你的代碼,這些類工作(我嘗試失敗)。應該返回新的A {X = value.X};返回新的ASer {X = value.X}; ?? – 2013-04-26 21:28:26

+0

@DavidHayes OOPS!是的,我的錯誤。另外:如果數據相同,您希望使用代理人的原因是什麼?你知道如果需要,protobuf-net可以序列化私有字段和邊界構造函數嗎?你*可以*直接配置原始類型直接序列化,即使它們沒有公開友好的API, – 2013-04-26 21:57:23

+0

我將在WP7/8上運行它,所以IIRC私人領域的東西不適用於不完整特色框架 – 2013-04-26 22:00:43

1

您是否嘗試過在PointF2D使用ProtoInclude包括GeoCoordinate?就像這樣:

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

這應該強制其使用的替代SerializableGeoCoordinate

+1

我懷疑代理人的整個觀點是'PointF2D'不能直接操縱。當然,所有的東西都可以通過類型模型而不是屬性進行配置,但有時需要重新設計序列化數據。 – 2013-04-26 21:14:16