首页 > 解决方案 > 为什么带有protobuf的redis将空数组保存为null?

问题描述

我正在使用 StackExchange.Redis 1.2.6 在 redis 服务器 2.8.2103 上使用 protobuf- net 2.3.3维护应用程序

对于像这样的对象:

[ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
public class Cachable { Foo[] Foos { get; set; } }

当我使用简单的保存时:

using (var memoryStream = new MemoryStream())
{
    Serializer.Serialize(memoryStream, cachable);
    database.HashSetAsync("category", "key", memoryStream.ToArray());
}

然后检索:

var response = database.HashGet("category", "key");
if (!response.HasValue) return null;
using (var memoryStream = new MemoryStream(response, false))
{
    return Serializer.Deserialize<Cachable>(memoryStream);
}

如果缓存数组Foos有一个空实例,如new Foo[0],一旦Cachable反序列化,数组变为null。这会改变应用程序某些部分的行为并产生错误。
这种行为是预期的吗?有没有办法改变它?

标签: c#redisprotobuf-netstackexchange.redis

解决方案


Foo[0]真正的问题是事实null吗?如果是这样:

  • protobuf没有null;的概念 它不能表示和存储 null,因此默认情况下 protobuf-net 会跳过null 值,使其本质上是一个空数组
  • 带有“空包装原语”的轻微警告,protobuf 没有“空”序列的概念;在 .proto 术语中,您正在谈论一个repeated具有零元素的字段,这意味着:它根本不存在于有效负载
  • 如果它在有效载荷中不存在,它永远不会反序列化为任何东西 - 因为有效载荷中永远没有任何东西告诉它反序列化

所以:

  • 避免null,除非您指的是可选的子元素;绝对避免null在列表/数组/等中
  • 不要假设空列表/数组/等将被库初始化为非空值

IMO,对于第二点,以下内容将是合理和务实的:

Foo[] Foos { get; set; } = Array.Empty<Foo>();

(这避免了它初始化为的问题null


推荐阅读