gpt4 book ai didi

c# - protobuf-net AddField 忽略 IgnoreListHandling

转载 作者:太空宇宙 更新时间:2023-11-03 15:07:42 27 4
gpt4 key购买 nike

我有这个数据结构声明:

[ProtoContract]
public class NotACollectionHolder
{
public NotACollection some_objects;
}

[ProtoContract(IgnoreListHandling = true, ImplicitFields = ImplicitFields.AllPublic)]
public class NotACollection : IEnumerable<int>
{
public int some_data;

// something looks like a collection API
public void Add(int a) { }
public IEnumerator<int> GetEnumerator() { throw new NotImplementedException(); }
IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); }
}

我正在通过以下代码手动将字段注册到 MetaType:

MetaType meta = RuntimeTypeModel.Default.Add(typeof(NotACollectionHolder), false);
ValueMember member = meta.AddField(1, "some_objects", itemType: null, defaultType: null);
string proto = Serializer.GetProto<NotACollectionHolder>();

我将 NotACollection 标记为 IgnoreListHandling。我试图通过提供 itemType: null, defaultType: null 来强制 AddField 忽略 NotACollection 看起来像集合的事实。

不过,我的 member.ItemType 不为空,member.DefaultType 也不为空。并且 some_objects 成为生成的 proto 中的一个 repeated 字段:

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 将此字段视为非集合字段?

提前致谢。

最佳答案

我认为这可能是 RuntimeTypeModel 的错误或限制应用程序接口(interface)。

确定是否为 ValueMember 的方法是一个集合是RuntimeTypeModel.ResolveListTypes() .当传入的 itemType 为 null 时,它会尝试推断集合项类型。仅使用静态属性为 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]是只获取的,所以似乎没有一个简单的 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];
}

关于c# - protobuf-net AddField 忽略 IgnoreListHandling,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42600663/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com