Почему Redis с Protobuf сохраняет пустые массивы как ноль? - PullRequest
2 голосов
/ 21 октября 2019

Я поддерживаю приложение, используя 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 голос
/ 21 октября 2019

Реальная проблема здесь в том, что Foo[0] - это null? Если так:

  • protobuf не имеет понятия null;он не может представлять и хранить ноль, и поэтому по умолчанию protobuf-net пропускает нулевые значения по умолчанию, делая этот по существу пустой массив
  • с небольшим предупреждением "пустые упакованные примитивы ", protobuf не имеет понятия" пустой "последовательности;в терминах .proto, вы говорите о repeated поле, которое имеет ноль элементов, что означает: оно просто не существует в полезной нагрузке вообще
  • , и если оно нев полезной нагрузке не существует, она никогда десериализована ни к чему - потому что в полезной нагрузке никогда ничего нет, чтобы сказать ей десериализовать

так:

  • избегайте null, если только вы не подразумеваете дополнительный подэлемент;определенно избегайте null в списках / массивах / etc
  • не предполагайте, что пустые списки / массивы / etc будут инициализированы в ненулевые значения библиотекой

ИМО, для второго пункта было бы разумно и прагматично:

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

(что исключает проблему инициализации как null)

...