2016-07-27 6 views
-1

まず、問題の簡単なテストケースとそのトリガー方法を示します。ここにクラスがあります:Protobuf.NET - トリガー参照がリストにあるときに「可能な再帰が検出される」問題

class ProtoRecurseTest 
    { 
     private int nextPayload = 1; 
     public int Payload { get; private set; } = 0; 
     public ProtoRecurseTest Back { get; private set; } = null; 
     public List<ProtoRecurseTest> Children { get; set; } = new List<ProtoRecurseTest>(); 

     public ProtoRecurseTest Add() 
     { 
      ProtoRecurseTest result = new ProtoRecurseTest(this, nextPayload++); 
      Children.Add(result); 
      return result; 
     } 

     public ProtoRecurseTest() 
     { 
     } 

     private ProtoRecurseTest(ProtoRecurseTest parent, int payload) 
     { 
      Back = parent; 
      this.Payload = payload; 
      nextPayload = payload + 1; 
     } 

     private static void ToStringHelper(ProtoRecurseTest proto, StringBuilder sb) 
     { 
      sb.Append(proto.Payload + " -> "); 

      // another little hassle of protobuf due to empty list -> null deserialization 
      if (proto.Children != null) 
      { 
       foreach (var child in proto.Children) 
        ToStringHelper(child, sb); 
      } 
     } 

     public override string ToString() 
     { 
      StringBuilder sb = new StringBuilder(); 
      ToStringHelper(this, sb); 
      return sb.ToString(); 
     } 
    } 

これは、プログラムで処理されているので、protobuf注釈はありません。 BackとChildrenと一緒にクラスが.AsReferenceDefault = trueのスキーマにすべて追加されるよう手動で確認しました。

再帰トリガーは、少なくとも8つの奇妙な深度にインスタンスが移入されたときに発生します。 7は大丈夫です。母集団コードはまっすぐです:

 ProtoRecurseTest recurseTest = new ProtoRecurseTest(); 
     ProtoRecurseTest recurseItem = recurseTest; 
     for (int i = 0; i < 8; i++) 
      recurseItem = recurseItem.Add(); 

そして、recurseTestをシリアル化します。この動作は、子がリストに含まれていてもリスト内にある場合にのみ発生し、リストに1つの子があっても、サンプルが入力されたコードから終了します。私が子供を単一の参照で置き換えたときには、すべてがうまく連載されました。

これはProtoBuf.NET 2.1.0.0を使用しています。

答えて

0

ここでは解決策ですが、特に好きではありません。それはthis質問に対する@ marc-gravellの答えに基づいていました。タイプが彼らのビジネスをやって、その後、その場合は、適切なメソッドを呼び出す前に(ちょうどBeforeSerializationとAfterDeserialization方法を提供して)ISerializationManagementCallbacksにキャストできるのであれば、今デシリアライズ/シリアライズする

class ProtoRecurseTest : ISerializationManagementCallbacks 
    { 
     private int nextPayload = 1; 
     public int Payload { get; private set; } = 0; 
     public ProtoRecurseTest Back { get; private set; } = null; 
     public List<ProtoRecurseTest> Children { get; set; } = new List<ProtoRecurseTest>(); 

     public ProtoRecurseTest Add() 
     { 
      ProtoRecurseTest result = new ProtoRecurseTest(this, nextPayload++); 
      Children.Add(result); 
      return result; 
     } 

     public ProtoRecurseTest() 
     { 
     } 

     private ProtoRecurseTest(ProtoRecurseTest parent, int payload) 
     { 
      Back = parent; 
      this.Payload = payload; 
      nextPayload = payload + 1; 
     } 

     private static void ToStringHelper(ProtoRecurseTest proto, StringBuilder sb) 
     { 
      sb.Append(proto.Payload + " -> "); 

      // another little hassle of protobuf due to empty list -> null deserialization 
      if (proto.Children != null) 
      { 
       foreach (var child in proto.Children) 
        ToStringHelper(child, sb); 
      } 
     } 

     public override string ToString() 
     { 
      StringBuilder sb = new StringBuilder(); 
      ToStringHelper(this, sb); 
      return sb.ToString(); 
     } 

     static void PreSerializationHelper(ProtoRecurseTest instance) 
     { 
      instance.Back = null; 
      foreach (var child in instance.Children) 
       PreSerializationHelper(child); 
     } 

     public void BeforeSerialization() 
     { 
      PreSerializationHelper(this); 
     } 

     static void PostDeserializationHelper(ProtoRecurseTest instance, ProtoRecurseTest parent) 
     { 
      if (instance.Children == null) 
       instance.Children = new List<ProtoRecurseTest>(); 
      instance.Back = parent; 
      foreach (var child in instance.Children) 
       PostDeserializationHelper(child, instance); 
     } 

     public void AfterDeserialization() 
     { 
      PostDeserializationHelper(this, null); 
     } 
    } 

呼び出しは、単にチェック。それはうまく動作します。

しかし、コードセットにシリアル化の問題を混在させることは本当に好きではありません。つまり、実際にスキーマがプログラムによって生成される理由です。理想的には、シリアライゼーションを完全に分離したいが、空のリスト - >ヌルの問題(それは "問題"そのものではなく、protobuf標準の望ましくない部分)は既にそれを不可能にしているが、これは別のもの私はこの問題が本当に問題になるかもしれないと思います。

関連する問題