Пытаюсь сериализовать System. Numerics . Quaternion.Numerics.Quaternion с использованием protobuf-net

#c# #.net-core #protobuf-net #.net-standard

#c# #.net-ядро #protobuf-net #.net-стандартный

Вопрос:

Справочная информация

У меня есть библиотека классов .Net Standard 2.0, которая использует подход Protobuf-net.grpc code first для определения службы gRPC. В этом определении у меня есть классы, определяющие различные структуры данных, которые мы используем для записи данных датчиков и сериализации их с помощью protobuf-net. Мои программы поглощают серверные сотни тысяч больших объектов / с (которые скоро будут масштабироваться до миллионов) и предназначены для использования во встроенных средах.

Проблема

В моем классе ниже я хотел бы включить в качестве члена систему.Numerics.Quaterion. Кажется, я не могу получить эту сериализацию. Используя статические конструкторы, RuntimeTypeModel генерирует исключения, поскольку модель кватерниона каким-то образом уже создана к моменту выполнения статического конструктора. Поскольку это библиотека классов, и я отчаянно хочу избежать вызова RuntimeTypeModel в каждой отдельной программе, использующей службу gRPC. Я надеюсь найти способ сериализации системы.Numerics.Quaternion.

Я попытался поместить это определение времени выполнения статического конструктора на самый высокий уровень иерархии классов, но безрезультатно. Исключения все еще генерируются.

 [ProtoContract]
    public class IMUData : SensorData, ISensorData
    {
        static IMUData()
        {
            RuntimeTypeModel.Default.Add(typeof(Quaternion), false)
                .Add("W")
                .Add("X")
                .Add("Y")
                .Add("Z");
        }

        ... //Other members

        [ProtoMember(8)]
        public Quaternion Orientation
        {
            get; set;
        }

        ... //Other methods and members
    }
  

Вопрос

Возможно ли то, что я хотел бы сделать, или я должен просто создать свой собственный класс кватернионов и определить неявные операторы? (Я бы предпочел избежать этого, поскольку обработка миллиардов этих объектов занимает достаточно много времени)

Комментарии:

1. в качестве второстепенного отступа: IMO, правильный порядок здесь X , Y , Z , W — как определено Quaternion(float x, float y, float z, float w) конструктором — так что, если бы это был я, я бы заказал их X = 1, Y = 2, Z = 3, W = 4; Я говорю это, потому что этот тип на самом деле мучительно близок квстроенный шаблон «типа, подобного кортежу», который библиотека распознала бы и использовала автоматически — где, если у типа (без подходящих аннотаций) есть конструктор, который соответствует всем элементам (кроме обсадной колонны в имени параметра), он сделает вывод, что это означает «порядок параметров конструктора определяет полечисла»

Ответ №1:

В конечном счете, это проблема времени — когда сериализатор пытается подумать о SensorData подготовке сериализатора, статический конструктор в IMUData еще не выполнен, поэтому он подготавливает сериализатор с неполной информацией, а затем позже статический конструктор пытается перенастроить модель — слишком поздно.

Если вы используете C # 9.0, вы можете исправить это, используя инициализатор модуля вместо статического конструктора (если мы предполагаем, что SensorData и IMUData находятся в одном модуле, что, вероятно, является безопасным предположением). Например, следующее работает нормально:

 [ProtoContract]
public class IMUData : SensorData //, ISensorData
{
    [ModuleInitializer]
    internal static void Init()
    {
        RuntimeTypeModel.Default.Add(typeof(Quaternion), false)
            .Add("W")
            .Add("X")
            .Add("Y")
            .Add("Z");
    }
  

Обратите внимание, что если вы не используете .NET 5 (предварительный просмотр, в настоящее время), вы можете определить необходимый атрибут самостоятельно:

 namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    internal sealed class ModuleInitializerAttribute : Attribute { }
}
  

Если это не вариант, вы можете просто поместить код конфигурации модели намного раньше в свое приложение — в идеале во время запуска, чтобы это произошло задолго до того, как сериализатор попытается начать построение моделей.

Комментарии:

1. Спасибо, Марк! Извините, я не наткнулся на инициализатор модуля. Спасибо за ваше время и за ответ на вопрос, который не был напрямую связан с protobuf-net!

2. @craig они новые в c # 9, который еще не выпущен iirc, но вы можете использовать его, если у вас есть .net 5 sdk