在 .NET 中序列化复杂对象层以进行缓存的最简单方法是啥?

Posted

技术标签:

【中文标题】在 .NET 中序列化复杂对象层以进行缓存的最简单方法是啥?【英文标题】:What is the simplest way to serialize a complex object layer in .NET for caching?在 .NET 中序列化复杂对象层以进行缓存的最简单方法是什么? 【发布时间】:2012-11-25 14:44:27 【问题描述】:

尝试将缓存/状态持久性引入应用程序的中间层,该应用程序具有在 IIS 下运行的复杂对象层(和 WCF 服务层,这里不是重点)。已选择 memcached/enyim 作为缓存架构,现在需要为它高效地序列化这些对象(速度和空间)。

对象层有很多指针和对象之间的相互依赖关系,大致如下:

internal class SomeObj

    private string attr1;
    private int attr2;
    private OtherObj otherObj;
    private List<OtherOtherObj> otherObjs;


internal class OtherObj

    //...more attributes


internal class OtherOtherObj

    // you get the idea

请注意,所有字段都是私有的。另外值得注意的是,大多数对象都是内部的,许多属性要么是只读的(没有设置),要么从用户角度使用设置(即使对象“脏”),因此不能用于补液。我有几十种需要缓存的类型。

我喜欢 protobuf-net 和 msgpack 的外观,但我需要尽可能快地完成序列化,尽可能少地改变现有架构(目前运行良好),看起来像这两者都对对象层次结构的支持有限。我很了解 DTO 类型的序列化,但是对于规划正确的方法来为缓存序列化对象是新手。这些工具之一可以为我工作吗?我是否坚持使用内置的 .NET 二进制文件来使用构造函数,并根据自己的条件重新填充属性和对象?

编辑:只是为了澄清最后一个问题——如果它显示“我是否坚持使用内置的 .NET 二进制文件以便我可以控制构造函数并重新填充属性和以我自己的方式对象?

【问题讨论】:

【参考方案1】:

我无法对 msgpack 发表评论,但是可以:protobuf-net 可以完成您提到的所有事情,包括:

序列化非公共类型 序列化私有字段 序列化树 构造函数跳过或用户提供的工厂(或只是无参数构造函数) 序列化完整/循环图(通过将受影响的显式标记为引用) 完全不更改 DTO 的属性使用或运行时配置(坦率地说,属性通常更容易) 快速紧凑的输出 继承支持

在给出的示例中,最简单的“是否有效”测试是使用 [ProtoContract] 创建类型(该属性中有一个可选设置用于跳过构造函数),并将字段标记为 [ ProtoMember(n)],例如n=1,2,3,...(每个类型唯一,但类型之间不需要唯一)

除了我们使用 Redis+BookSleeve 而不是 memcached+enyim 之外,这正是我们在 Stack Exchange 为对象缓存所做的事情。好吧,我们还对大型对象进行了推测性 gzip - 如果有大量字符串数据,gzip 可以帮助减少一些额外的字节。

【讨论】:

谢谢,我也读了很多关于 Redis 的文章,我觉得 Windows 服务并不简单。我还查看了一些简单的(r)protobuf-net 示例,它看起来非常类似于 WCF,我对此很满意,但只是作为 DTO/POCO 对象“构建器”,这似乎有所不同。只是为了确保我理解:在这种情况下最好使用 protobuf-net 来序列化字段而不是属性?然后就像在序列化/反序列化方法中包装添加/获取到/从缓存中的调用一样简单? @downwitch 它将使用五个字段或属性。通常我使用道具,但你提到不想这样做是因为“脏”检查等。但是:是的,就这么简单 @downwitch protobuf-net 可以与 WCF 一起使用,但这只是一种情况 - 大多数时候我希望它单独使用 抱歉,再问一次,我的问题并不清楚......使用 DataContract,每个 DataMember 都必须具有 get 和 set 访问器,并且在重新水化过程中,set 访问器都会被调用。那么我假设 ProtoContract 遵循相同的逻辑?例如如果封装字段的属性是只读的,则基础字段未设置为补液并保持其默认值?然后我假设你已经使用了一些其他的魔法来让私有字段作为 ProtoMembers 工作,所以正如你指出的那样,无论如何在我的情况下可能会更干净。 @downwitch 如果您将该字段标记为 [ProtoMember],则它直接访问该字段。如果您标记该属性,它确实使用了 get 和 set 访问器(请注意,并不总是需要一个集合,例如一个列表)。不要担心readonly - 它绕过了 - 这主要是针对编译器的。对于信息,我所说的一切同样适用于 DataContract,顺便说一句 - DataContractSerializer 可以访问私有字段,忽略 readonly,并绕过构造函数。

以上是关于在 .NET 中序列化复杂对象层以进行缓存的最简单方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何重塑我的输入以将其输入一维卷积层以进行序列分类?

Json.NET 是不是缓存类型的序列化信息?

在 .NET 中确定复杂对象大小的方法?

在 MATLAB 中序列化多维数组以进行数据库插入的最简单方法?

如何在 C# .NET 中反序列化复杂的 JSON 对象?

通过 Javascript 迭代复杂 JSON 对象的最简单方法