为什么 Redis 结合 protobuf 会将空数组保存为 null?

3

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

对于这样的对象:

[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。 这会改变应用程序的某些部分的行为并生成错误。 这种行为是否是预期的?是否有任何方法可以更改它?
1个回答

1

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

  • protobuf 没有 null 的概念;它不能表示和存储 null,因此默认情况下 protobuf-net 跳过 null 值,使其成为 空数组
  • 稍微注意一下 "空的打包原语",protobuf 没有 "空" 序列的概念;在 .proto 术语中,你说的是一个具有零元素的 repeated 字段,这意味着:它在有效负载中根本不存在
  • 如果它在有效负载中不存在,它就永远不会被反序列化为任何东西 - 因为有效负载中从来没有任何内容来告诉它进行反序列化

所以:

  • 除非你想要一个可选的子元素,否则避免使用 null;绝对避免在列表/数组等中使用 null
  • 不要假设空列表/数组等将由库初始化为非空值

在我看来,以下内容对于第二点是合理且实用的:

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

(这避免了它作为null进行初始化的问题)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接