如何序列化数组中的空值?

Posted

技术标签:

【中文标题】如何序列化数组中的空值?【英文标题】:How to serialize null values in array? 【发布时间】:2021-12-18 13:51:12 【问题描述】:

我在 Windows 平台上使用 protobuf-net v3.0.101 并在使用 grpc protobuf-net 对其进行序列化时获取以下字符串数组中的空值异常:

我已经这样定义了我的 DataContract:

[DataContract]
public class StringArray

    [DataMember(Order = 1)]
    public string[] StrArray;

这是我尝试序列化的实际消息:

var stringArray = new StringArray()  StrArray = new string[]  "1", "2", null, "3"  ;

而且,这就是我调用 Serializer 的方式:

method.RequestMarshaller.ContextualSerializer(request, transmitPayload);

这是一个例外:

FAIL: Error: Unhandled exception in required test method. An element of type System.String was null; this might be as contents in a list/array. (System.NullReferenceException: An element of type System.String was null; this might be as contents in a list/array
   at ProtoBuf.Internal.ThrowHelper.ThrowNullRepeatedContents[T]()
   at ProtoBuf.Serializers.RepeatedSerializer`2.Write[TEnumerator](State& state, Int32 fieldNumber, SerializerFeatures category, WireType wireType, TEnumerator& values, ISerializer`1 serializer)
   at ProtoBuf.Serializers.VectorSerializer`1.Write(State& state, Int32 fieldNumber, SerializerFeatures category, WireType wireType, T[] values, ISerializer`1 serializer)
   at ProtoBuf.Serializers.RepeatedSerializer`2.WriteRepeated(State& state, Int32 fieldNumber, SerializerFeatures features, TCollection values, ISerializer`1 serializer)
   at proto_29(State& , StringArray )
   at ProtoBuf.ProtoWriter.State.SerializeRoot[T](T value, ISerializer`1 serializer)
   at ProtoBuf.MeasureState`1..ctor(TypeModel model, T& value, Object userState, Int64 abortAfter)
   at ProtoBuf.Meta.TypeModel.Measure[T](T value, Object userState, Int64 abortAfter)
   at ProtoBuf.Meta.TypeModel.ProtoBuf.IMeasuredProtoOutput<System.Buffers.IBufferWriter<System.Byte>>.Measure[T](T value, Object userState)
   at ProtoBuf.Grpc.Configuration.ProtoBufMarshallerFactory.ContextualSerialize[T](T value, SerializationContext context)

【问题讨论】:

呃.. 异常说“你的字符串数组中有一个空值”,而你的字符串数组的第三个位置有一个空值 【参考方案1】:

这里的问题是:底层的protobuf格式没有null的概念。我根本无法以明显的方式将其编码到数组中。

在 V2 中,我们做了一些事情,将所有数组元素(启用此功能)包装在一个额外的层中,以允许我们解释空值,但这会占用更多的网络空间,不是就地静默替换,并且解释起来并不明显。我还没有在 V3 中重新添加它,但是如果非常需要它,我们可以这样做。但是,今天这样做的一种懒惰方法是序列化 Foo[] 其中 Foo 是一个类型,具有 string 作为唯一成员,字段 1。它可能是一个值-类型 - 甚至可能是带有单个字段的 readonly struct record

【讨论】:

1) 哪个解决方案的性能更高,将其序列化为 Foo[] 或 V3 的“某事”解决方案? 2) 如果固定在 V3 上会很高效,那么需要付出多少努力?什么时候可以发布? 3) 任何实现细节如何为 V2 完成,将帮助我理解它的复杂性。谢谢。 @Priyanshu 线上的字节是相同的;它将节省的是调用方的额外代码和分配(即您的代码)。空跟踪的实现增量基本上是一些额外的代码来欺骗额外的层 - 可能不是很大,可能需要半天到一天的努力;已经考虑了边缘情况(感谢 V2),所以没有很多悬而未决的问题 - 只是:找时间去做(最终,如果我的个人家庭时间等) 我已经通过定义readonly struct record 解决了这个问题,就像你提到的那样。但是这个解决方案没有太大的可扩展性,我们有很多包含数组的 dto 或另一个再次包含数组的对象。另一个问题是,我无法区分接收端的空数组或空数组,两者都被反序列化为空。 IEnumerable 的问题也是如此,我们无法发送空值,也无法区分黑白空列表和空列表。解决这些问题对我们来说是必须的。你能指导我如何在开源回购中修复它。谢谢。 @Priyanshu 我要花很长时间来解释如何修复它 - 与我实际修复它所需的时间在同一区域;这是专业/公司工作吗?冒着听起来粗鲁的风险:如果这是“必须”,那么赞助变革是否是一个可行的选择? 这个问题是为了我的理解。所以你要做的解决方案是启用 'SupportNull' 属性,该属性可用于覆盖运行时类型模型,如 RuntimeTypeModel.Default[typeof(SomeObject)] [1].SupportNull = true; ?然后在我的最后,我需要创建新的 RuntimeTypeModel 并将这个属性设置为 true 用于 dto 中的所有数组?

以上是关于如何序列化数组中的空值?的主要内容,如果未能解决你的问题,请参考以下文章

php array_slice 取出数组中的一段序列实例

如何删除 BigQuery 数组中的空值?

IOS,如何在数组中的 dic 中循环 dic 以替换空字符串的空值

EXCEL函数去除数组中的0值和空值

sqlite - 忽略 lag/lad 中的空值

js中怎么去掉数组的空值,不知道是第几个,只要是空值就删除