为什么带有 protobuf 的 redis 将空数组保存为 null?

Why redis with protobuf is saving empty arrays as null?

我正在使用 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。 这正在改变应用程序某些部分的行为并产生错误。
这种行为是预期的吗?有什么办法可以改变吗?

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

  • protobuf 没有null的概念;它不能表示和存储 null,因此默认情况下 protobuf-net skips null 值,使这个 essentially 成为一个空数组
  • 稍微注意 "empty packed primitives",protobuf 没有 "empty" 序列的概念;在 .proto 术语中,你谈论的是一个 repeated 字段,它有零个元素,这意味着:它根本不存在于有效负载中 根本
  • 如果有效载荷中不存在它,它永远不会反序列化任何东西——因为有效载荷中从来没有任何东西可以告诉它 反序列化

所以:

  • 避免 null 除非你的意思是一个可选的子元素;绝对避免在列表/数组/等中使用 null
  • 不要假设空 lists/arrays/etc 将被库初始化为非空值

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

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

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