我有一个.Net Standard 2.0类库,该库使用Protobuf-net.grpc的代码优先方法来定义gRPC服务。在这个定义中,我有一些类定义了不同的数据结构,我们将使用这些结构来记录传感器数据并使用protobuf-net将其序列化。我的程序正在摄取数十万个大型对象/秒(很快将扩展到数百万个),并且打算在嵌入式环境中使用。
在下面的课堂上,我希望将System.Numerics.Quaterion作为成员包括在内。我似乎无法将此序列化。使用静态构造函数,由于在执行静态构造函数时已经以某种方式创建了Quaternion模型,因此RuntimeTypeModel引发了异常。因为这是一个类库,所以我非常希望避免使用gRPC服务在每个不同的程序中调用RuntimeTypeModel。我希望找到一种方法来序列化System.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
}
我甚至想做些什么,还是应该简单地创建自己的Quaternion类并定义隐式运算符? (我宁愿避免这种情况,因为处理数十亿个对象需要足够长的时间)
答案 0 :(得分: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 { }
}
如果这不是一种选择,则只需将模型配置代码放在应用程序中更早的位置-理想情况下是在启动过程中,这样就可以在 long 前发生序列化程序尝试开始构建模型。