protobuf-net AddField 忽略 IgnoreListHandling

2023-12-30

我有这个数据结构声明:

[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>();

I mark NotACollection with IgnoreListHandling。我尝试强迫AddField忽略这样一个事实NotACollection看起来像通过提供收集itemType: null, defaultType: null.

尽管如此,我有member.ItemType不为空,并且member.DefaultType也不为空。和some_objects成为了repeated生成的字段proto:

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 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];
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

protobuf-net AddField 忽略 IgnoreListHandling 的相关文章

  • 如何获取变量的各个字节的值?

    我知道要获取变量类型使用的字节数 您可以使用sizeof int 例如 当您存储具有该变量类型的数字时 如何获取所使用的各个字节的值 IE int x 125 您必须知道每个 字节 中的位数 通常为 8 然后 您可以通过将 int 与适当的
  • 向 std::cout 添加“提示”消息的最佳方法

    我正在寻找向所有消息添加自定义初始消息的最佳方法std cout or std cerr 打印到控制台 文件输出 例如 如果我设置这个自定义提示消息将是字符串 Log 那么一个经典的 std cerr lt lt This is a log
  • 我收到“缺少 using 指令或程序集引用”的消息,并且不知道出了什么问题

    我试图允许用户将数据输入到将添加到 web config 文件中的文本框中 我已将相关行添加到 web config 文件中 但是当我创建此类时 一切都会出错 每当我尝试运行我的应用程序时 我总是收到是否缺少 using 指令或程序集引用错
  • 信号发送到子进程和父进程

    据我了解 发送到父进程的信号不应发送给子进程 那么为什么在下面的示例中 SIGINT 会同时到达子级和父级呢 include
  • Excel 在 CSV 导出中添加额外的引号

    我最近创建了一个应用程序 它通过 CSV 将项目添加到数据库 添加项目后 我意识到我的很多值都有不需要的额外引号 这扰乱了我的排序 问题是 当从 Excel 导出到 CSV 时 Excel 会向我所有已包含引号的值添加额外的引号 我在下面展
  • 最好的 C# 分析器?

    Merged https meta stackexchange com questions 158066 what is a merged question with 有哪些好的 NET 分析器 questions 3927 what ar
  • 执行类的成员函数

    我正在尝试以一种方式试验 C 11 线程 它接受类的成员函数作为线程构造函数的参数 如下面第 20 行标记为 的第一个代码片段所示 类定义在第二个代码片段中给出 编译此代码时 我收到第三个片段中显示的一堆错误 谁能告诉我我做错了什么 谢谢
  • 整个工具提示的背景色

    有谁知道一个简单的 XAML 解决方案来更改整个背景ToolTip 我做了以下事情
  • WCF JSON 输出添加了不需要的引号和反斜杠

    好吧 所以我很困惑为什么我正在构建的字符串 神奇地 添加了额外的字符 首先 我看到反斜杠出现在立即窗口中 ID 1 F1 lala F2 hehe ID 2 F1 abc F2 def 但是在谷歌上读到这些只是 视觉 并且实际上并不存在于变
  • Windows 上的 C++ 分析器 [重复]

    这个问题在这里已经有答案了 我刚开始使用 C 有时我不知道我的编译器有多喜欢算法的两种不同实现 有没有simple我可以使用工具来查看我的代码执行需要多长时间 编辑 我使用 gcc 编译器 Free 很困 http www codersno
  • 显式覆盖和最终 c++0x

    根据维基百科 http en wikipedia org wiki C 11 在此示例中 struct Base virtual void some func float struct Derived Base virtual void s
  • 进程退出时释放绑定端口

    如何确保绑定到端口的套接字在进程退出时正确释放 以便可以重用该端口而无需bind EADDRINUSE 失败 我编写了一个小程序 它只创建一个套接字 将其绑定到一个固定端口 等待连接 然后立即终止 当我重新运行程序时 bind 调用因 EA
  • 帮助我在 xaml 中定义 UI [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 这是我将
  • 铸造泛型和泛型类型

    考虑一下 我有以下 3 个类 接口 class MyClass
  • 如何将 QBFC13_0.msm 添加到 Clickonce

    网络上似乎没有记录如何执行此操作的分步过程 如果提到的话 它的记录非常少 而且我无法遵循他们建议的复杂路径 我是 ClickOnce 的新手 我已经能够让我的 C 程序在用户计算机上正确安装 但当然我得到 22E88GD7 FB0B B90
  • QSqlDatabasePrivate::removeDatabase:连接“myConnectionName”仍在使用中,所有查询将停止工作

    我有一个文件夹 里面有很多数据库 有时可能会删除或添加数据库到该文件夹 所以我使用 QTimer 并读取所有数据库 这是我的代码 this gt timer new QTimer this this gt timer gt setInter
  • 如何指向预分配内存上的 2D/3D 空间

    我对用于嵌入式使用的代码进行了内存优化 它工作得很好 但这样做的结果是我在函数中间得到了大量的 1D 2D 和 3D malloc 和 frees 从而减慢了执行时间 出于多种原因 我决定改变我的做法 我想在执行开始时使用单个 malloc
  • 当下载线程之一终止时解锁 FIleStream

    我通过例如下载文件5 个线程 当其中一个线程完成下载文件部分时 它被中止 但所有其余线程都有 ThreadState WaitSleepJoin 并且显然停止下载 怎么解决呢 while bytesSize responseStream R
  • 为我的 C++ 应用程序提供 SDK

    假设我正在用 C 创建一个游戏引擎 我只想提供一些标头而不是提供整个源代码 并且需要这些标头来创建新的游戏实例 提供脚本类 提供游戏对象类和组件 数学等 是的 显然我想为我的游戏引擎提供 SDK 但是如何做到这一点 如何仅提供一些公共标头并
  • 输入流上基于范围的循环

    为了迭代输入流 我们通常会使用std istream iterator像这样 typedef std istream iterator

随机推荐