これは、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];
}