gpt4 book ai didi

当集合是另一种类型的属性时,Protobuf-net将空集合反序列化为null

转载 作者:行者123 更新时间:2023-12-04 06:38:16 27 4
gpt4 key购买 nike

我遇到了protobuf-net的问题,希望这是用户错误,而不是protobuf-net的错误。

我可以序列化一个空集合(例如IDictionary<string, string>()),然后反序列化该集合。反序列化导致一个非null的对象(正是我序列化的对象)。

但是,如果该集合属于另一种类型,事情就会变得很奇怪。使用非空的空集合序列化自定义类型会导致反序列化,其中集合为null。

下面是我正在研究的示例以及说明该问题的单元测试。

测试Test_Protobuf_EmptyDictionary_SerializeDeserialize通过。
测试Test_Protobuf_EmptyCollectionAndPopulatedCollection_SerializeDeserialize失败。

[ProtoContract]
[ProtoInclude(100, typeof(ConcreteA))]
public abstract class AbstractClass
{
[ProtoMember(1)]
public string Name { get; set; }

[ProtoMember(2)]
public IDictionary<string, string> FieldsA { get; set; }

[ProtoMember(3)]
public IDictionary<string, string> FieldsB { get; set; }

[ProtoMember(4)]
public ICollection<string> FieldsC { get; set; }

[ProtoMember(5)]
public ICollection<string> FieldsD { get; set; }
}

[ProtoContract]
[ProtoInclude(110, typeof(ConcreteB))]
public class ConcreteA : AbstractClass
{
public ConcreteA() {}
}

[ProtoContract]
[ProtoInclude(120, typeof(ConcreteC))]
public class ConcreteB : ConcreteA
{
[ProtoMember(1)]
public int Age { get; set; }

public ConcreteB() {}
}

[ProtoContract]
public class ConcreteC : ConcreteB
{
[ProtoMember(1)]
public string HairColor { get; set; }
}

[TestFixture]
public class ProtobufTests
{
[Test]
public void Test_Protobuf_EmptyDictionary_SerializeDeserialize()
{
IDictionary<string,string> dictionary = new Dictionary<string, string>();
ICollection<string> collection = new List<string>();

Assert.IsNotNull(dictionary);
Assert.IsNotNull(collection);
Assert.AreEqual(0, dictionary.Keys.Count);
Assert.AreEqual(0, collection.Count);

using (MemoryStream ms = new MemoryStream())
{
Serializer.Serialize(ms, dictionary);
ms.Position = 0;
var deserialized = Serializer.Deserialize<IDictionary<string, string>>(ms);

Assert.IsNotNull(deserialized);
Assert.AreEqual(0, deserialized.Keys.Count);
}

using (MemoryStream ms = new MemoryStream())
{
Serializer.Serialize(ms, collection);
ms.Position = 0;
var deserialized = Serializer.Deserialize<ICollection<string>>(ms);

Assert.IsNotNull(deserialized);
Assert.AreEqual(0, deserialized.Count);
}
}

[Test]
public void Test_Protobuf_EmptyCollectionAndPopulatedCollection_SerializeDeserialize()
{
ConcreteC c = new ConcreteC {
FieldsA = new Dictionary<string, string>(),
FieldsB = new Dictionary<string, string> {{"john", "elway"}},
FieldsC = new List<string>(),
FieldsD = new List<string>{"james", "jones"}
};
Assert.IsNotNull(c);
Assert.IsNotNull(c.FieldsA);
Assert.IsNotNull(c.FieldsB);
Assert.IsNotNull(c.FieldsC);
Assert.IsNotNull(c.FieldsD);
Assert.AreEqual(0, c.FieldsA.Keys.Count);
Assert.AreEqual(1, c.FieldsB.Keys.Count);
Assert.AreEqual(0, c.FieldsC.Count);
Assert.AreEqual(2, c.FieldsD.Count);

using (MemoryStream ms = new MemoryStream())
{
Serializer.Serialize(ms, c);
ms.Position = 0;
var deserialized = Serializer.Deserialize<ConcreteC>(ms);

Assert.IsNotNull(deserialized);
Assert.IsNotNull(deserialized.FieldsA); // first failing test
Assert.IsNotNull(deserialized.FieldsB);
Assert.IsNotNull(deserialized.FieldsC);
Assert.IsNotNull(deserialized.FieldsD);
Assert.AreEqual(0, deserialized.FieldsA.Keys.Count);
Assert.AreEqual(1, deserialized.FieldsB.Keys.Count);
Assert.AreEqual(0, deserialized.FieldsC.Count);
Assert.AreEqual(1, deserialized.FieldsD.Count);
}
}
}

最佳答案

最终,这归结为以下事实:protobuf规范没有null的概念,也没有表达null的方法。集合实际上只是一个repeated块(来自.proto规范);零个项目的repeated块什么也没有;没有字节;没有什么。由于集合成员本身在protobuf中并未出现,因此无处可说那东西是null还是not-null。

用xml术语来说,if就像使用[XmlElement]将子项嵌入父项(而不是[XmlArray]/[XmlArrayItem]-即

<Foo>
<Name>abc</Name>
<Item>x</Item>
<Item>y</Item>
<Item>z</Item>
</Foo>

在这里,带有0 FooItem将是:
<Foo>
<Name>abc</Name>
</Foo>

从中,无法说出集合本身是 null还是空的。显然protobuf实际上不是xml,但是以上内容仅是一个说明性示例。

因此:protobuf无法表达这种情况,因此protobuf-net也无法表达。

在另一种情况下,您表示:空列表(作为根元素)的序列化表示是:零字节。反序列化时,如果发现流为空,它将始终返回非null值作为根对象,这是您想要的内容的最有可能的版本。

关于当集合是另一种类型的属性时,Protobuf-net将空集合反序列化为null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21631428/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com