#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