2017-03-04 4 views
2

を無視します。私はAddFieldに、itemType: null, defaultType: nullを提供することによって、NotACollectionがコレクションのように見えるという事実を無視するようにしています。いるProtobufネットなaddFieldが、私は、このデータ構造の宣言を持ってIgnoreListHandling

しかし、member.ItemTypeはnullではなく、member.DefaultTypeもnullではありません。そしてsome_objectsは、生成protorepeated場となりました:

message NotACollectionHolder { 
    repeated int32 some_objects = 1; 
} 

私はprotoはこのように見えるように期待:

message NotACollection { 
    optional int32 some_data = 1 [default = 0]; 
} 
message NotACollectionHolder { 
    optional NotACollection some_objects = 1; 
} 

どのように私はそれを達成することができますか?私は間違って何をしていますか? protobuf-netにこのフィールドを非コレクションフィールドのように扱わせるにはどうすればいいですか?

ありがとうございます。

答えて

0

これは実際にprotobuf-netのバグであることがわかりました。

if (model.FindWithoutAdd(miType)?.IgnoreListHandling == true) 
{ 
    itemType = null; 
    defaultType = null; 
} 
else 
    ResolveListTypes(model, miType, ref itemType, ref defaultType); 

別に機能

private ValueMember AddField(int fieldNumber, string memberName, Type itemType, Type defaultType, object defaultValue) 

置き換えるライン

ResolveListTypes(model, miType, ref itemType, ref defaultType); 

でファイルMetaType.cs内:それを修正する最初の方法はいるProtobufネットのソースコードに変更を加えることですオブジェクトのとdefaultTypeのプライベートフィールドを設定するためにリフレクションを使用して、フィールドを追加した後にValueMembernullを追加することです:

ValueMember m = meta.AddField(++last_field_number, f.Name, f.ItemType, f.DefaultType); 
m.GetType().GetField("itemType", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(m, null); 
m.GetType().GetField("defaultType", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(m, null); 

これは誰かを助けることを望みます。

0

これは、RuntimeTypeModel APIのバグまたは制限である可能性があります。

ValueMemberがコレクションであるかどうかを判断する方法は、RuntimeTypeModel.ResolveListTypes()です。受信したitemTypeがヌルの場合、コレクションアイテムタイプを推測しようとします。実行して、たとえば、唯一の静的属性を使用してNotACollectionHolderために契約を構築する場合:

var model = TypeModel.Create(); 
var schema = model.GetSchema(typeof(NotACollectionHolder)); 

その後ProtoBuf.Meta.MetaType.ApplyDefaultBehaviour(bool isEnum, ProtoMemberAttribute normalizedAttribute)ValueMemberを初期化作成するために呼び出されます。それは以下のロジックを持っています:

 // check for list types 
     ResolveListTypes(model, effectiveType, ref itemType, ref defaultType); 
     // but take it back if it is explicitly excluded 
     if(itemType != null) 
     { // looks like a list, but double check for IgnoreListHandling 
      int idx = model.FindOrAddAuto(effectiveType, false, true, false); 
      if(idx >= 0 && model[effectiveType].IgnoreListHandling) 
      { 
       itemType = null; 
       defaultType = null; 
      } 
     } 

IgnoreListHandlingの明示的なチェックに注意してください。これにより、some_objectsがコレクションとしてシリアル化されなくなります。

次のようにプログラム的ValueMemberを追加する場合は逆に、:

var model = TypeModel.Create(); 
var meta = model.Add(typeof(NotACollectionHolder), false); 
var member = meta.AddField(1, "some_objects", null, null); 
var schema = model.GetSchema(typeof(NotACollectionHolder)); 

その後MetaType.AddField(int fieldNumber, string memberName, Type itemType, Type defaultType, object defaultValue)を単に行いいる、と呼ばれる:

 ResolveListTypes(model, miType, ref itemType, ref defaultType); 

お知らせIgnoreListHandlingのためのチェックはありませんか?これがあなたの問題の原因です。

残念ながら、ValueType.itemTypeは読み取り専用で、MetaType[int fieldNumber]はget-onlyですので、これを修正するための簡単なAPIはないようです。あなたはreporting an issueと考えるかもしれません。

私は見つけることができる唯一の回避策はそうのようなNotACollectionHolderタイプの代理を導入することである。その後、

[ProtoContract] 
internal class NotACollectionHolderSurrogate 
{ 
    [ProtoMember(1)] 
    internal NotACollectionSurrogate some_objects; 

    public static implicit operator NotACollectionHolder(NotACollectionHolderSurrogate input) 
    { 
     if (input == null) 
      return null; 
     return new NotACollectionHolder { some_objects = input.some_objects }; 
    } 

    public static implicit operator NotACollectionHolderSurrogate(NotACollectionHolder input) 
    { 
     if (input == null) 
      return null; 
     return new NotACollectionHolderSurrogate { some_objects = input.some_objects }; 
    } 
} 

[ProtoContract] 
internal class NotACollectionSurrogate 
{ 
    [ProtoMember(1)] 
    public int some_data; 

    public static implicit operator NotACollection(NotACollectionSurrogate input) 
    { 
     if (input == null) 
      return null; 
     return new NotACollection { some_data = input.some_data }; 
    } 

    public static implicit operator NotACollectionSurrogate(NotACollection input) 
    { 
     if (input == null) 
      return null; 
     return new NotACollectionSurrogate { some_data = input.some_data }; 
    } 
} 

そして実行します。

var model = TypeModel.Create(); 
model.Add(typeof(NotACollectionHolder), false).SetSurrogate(typeof(NotACollectionHolderSurrogate)); 

var schema = model.GetSchema(typeof(NotACollectionHolder)); 

必要に応じて生成された契約は次のとおりです。

message NotACollectionHolderSurrogate { 
    optional NotACollectionSurrogate some_objects = 1; 
} 
message NotACollectionSurrogate { 
    optional int32 some_data = 1 [default = 0]; 
} 
関連する問題