我认为这可能是一个错误或限制RuntimeTypeModel https://www.codeproject.com/Articles/642677/Protobuf-net-the-unofficial-manual#without API.
判断是否存在的方法ValueMember https://github.com/mgravell/protobuf-net/blob/master/protobuf-net/Meta/ValueMember.cs是一个集合是RuntimeTypeModel.ResolveListTypes() https://github.com/mgravell/protobuf-net/blob/master/protobuf-net/Meta/RuntimeTypeModel.cs#L1851。当传入数据时,它会尝试推断集合项类型itemType
一片空白。签订合同时NotACollectionHolder
仅使用静态属性,例如通过执行以下操作:
var model = TypeModel.Create();
var schema = model.GetSchema(typeof(NotACollectionHolder));
Then ProtoBuf.Meta.MetaType.ApplyDefaultBehaviour(bool isEnum, ProtoMemberAttribute normalizedAttribute) https://github.com/mgravell/protobuf-net/blob/master/protobuf-net/Meta/MetaType.cs#L1097被调用来创建一个初始化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));
Then MetaType.AddField(int fieldNumber, string memberName, Type itemType, Type defaultType, object defaultValue) https://github.com/mgravell/protobuf-net/blob/master/protobuf-net/Meta/MetaType.cs#L1395被调用,它的作用很简单:
ResolveListTypes(model, miType, ref itemType, ref defaultType);
请注意,没有检查IgnoreListHandling
?这就是你的问题的原因。
很遗憾,ValueType.itemType https://github.com/mgravell/protobuf-net/blob/master/protobuf-net/Meta/ValueMember.cs#L36是只读的并且MetaType[int fieldNumber] https://github.com/mgravell/protobuf-net/blob/master/protobuf-net/Meta/MetaType.cs#L1546是 get-only,所以似乎没有一个简单的 API 可以调用来解决这个问题。你可能会考虑报告问题 https://github.com/mgravell/protobuf-net/issues.
我能找到的唯一解决方法是引入代理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];
}