2016-07-27 3 views
-1

먼저 문제의 간단한 테스트 사례와 트리거 방법을 보여줍니다. 다음은 클래스입니다 :Protobuf.NET - 트리거링 참조가 목록에있는 경우 "재귀 감지"문제 발생

프로그래밍 방식으로 처리되는 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를 직렬화 : 인구 코드는 정직이다. 이 동작은 자식이 목록에 있지만 목록에있는 경우 자식 채우기 코드로 끝날 때마다 목록 당 단 하나의 자식으로도 발생합니다. 내가 하나의 참조로 아이들을 대체했을 때 모든 것이 잘 연재되었다.

이것은 ProtoBuf.NET 2.1.0.0을 사용하고 있습니다.

답변

0

다음은 해결책이지만, 특별히 좋아하지는 않습니다. 그것은 this 질문에 대한 @ marc-gravell의 대답을 기반으로했습니다.

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

통화는 유형이 ISerializationManagementCallbacks에 캐스트 할 수있는 경우 단순히 확인 지금/역 직렬화를 직렬화 (이 단지 BeforeSerialization 및 AfterDeserialization 방법을 제공했다) 자신의 사업을하고 경우에 따라서 적절한 방법을 호출하기 전에합니다. 그리고 그것은 잘 작동합니다.

그러나 코드베이스에 직렬화 문제가 더 많이 혼합되는 것은 아닙니다. 실제로 스키마가 프로그래밍 방식으로 생성되는 이유입니다. 이상적으로는 직렬화를 완전히 분리하고 싶지만 비어있는 목록 - null 문제 ("문제"자체는 아니지만 protobuf 표준의 원하지 않는 부분)로 인해 이미 불가능하다는 것을 알 수 있습니다. 그러나 이것은 또 다른 것입니다. 이보다 더 밀교적인 이슈가 해결되어야하며이 문제가 실제로 문제가 될 수 있다고 생각합니다.