我有一些用protobuf.net序列化的数据。数据是一个映射,包含一些重复项(因为我的键没有实现IEquatable)
我希望将数据反序列化为字典,并忽略重复的数据。这似乎有一个属性,即[ProtoMap(DisableMap=false)]
,文档中说:
禁用"map“处理;字典将使用.Add( key,value)而不是key= value。..。
基本上,我希望行为是[key] = value
,但是显然,这个属性被忽略了。
我做错什么了吗?是否有任何方法可以达到所期望的(并记录在案的)忽略重复的行为?
示例代码: 1.生成具有重复项的数据:
// ------------- ------------- ------------- ------------- ------------- ------------- -------------
// The following part generated the bytes, which requires the key NOT to implement IEquatable
// ------------- ------------- ------------- ------------- ------------- ------------- -------------
var cache = new MyTestClass() { Dictionary = new Dictionary<MyTestKey, string>() };
cache.Dictionary[new MyTestKey { Value = "X" }] = "A";
cache.Dictionary[new MyTestKey { Value = "X" }] = "B";
var bytes = cache.Serialize();
var bytesStr = string.Join(",", bytes); // "10,8,10,3,10,1,88,18,1,65,10,8,10,3,10,1,88,18,1,66";
//..
[DataContract]
public class MyTestKey
{
[DataMember(Order = 1)]
public string Value { get; set; }
}
[DataContract]
public class MyTestClass
{
[DataMember(Order = 1)]
[ProtoMap(DisableMap = false)]
public Dictionary<MyTestKey, string> Dictionary { get; set; }
}
´´´
2. Try deserialize the data, with property IEquatable, which fails..:
[DataContract]
public class MyTestKey : IEquatable<MyTestKey>
{
[DataMember(Order = 1)]
public string Value { get; set; }
public bool Equals(MyTestKey other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Value == other.Value;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((MyTestKey) obj);
}
public override int GetHashCode()
{
return (Value != null ? Value.GetHashCode() : 0);
}
}
//..
var bytesStr2 = "10,8,10,3,10,1,88,18,1,65,10,8,10,3,10,1,88,18,1,66";
var bytes2 = bytesStr2.Split(',').Select(byte.Parse).ToArray();
var cache = bytes2.DeserializeTo<MyTestClass>();
“”
异常--已经添加了具有相同键的项。
public static class SerializationExtensions
{
public static T DeserializeTo<T>(this byte[] bytes)
{
if (bytes == null)
return default(T);
using (var ms = new MemoryStream(bytes))
{
return Serializer.Deserialize<T>(ms);
}
}
public static byte[] Serialize<T>(this T setup)
{
using (var ms = new MemoryStream())
{
Serializer.Serialize(ms, setup);
return ms.ToArray();
}
}
发布于 2020-01-14 08:18:44
这里有几种不同的情况;"map“模式实际上是您想要的模式--所以不是您试图禁用map,而是实际上您试图强制它(在大多数常见的字典场景中,它现在是默认的)。
有一些复杂的情况:
库只在处理[ProtoContract(...)]
[ProtoMember(...)]
时处理[ProtoMap(...)]
,然后它只处理作为proto specification
[ProtoMap(...)]
,可以手动打开它(不是通过属性),但在v2.*中,它在运行时强制执行与#2相同的检查,这意味着它将失败。
#3中的手动启用在v3.* (当前在alpha中)中的工作:
RuntimeTypeModel.Default[typeof(MyTestClass)][1].IsMap = true;
然而,这显然是不优雅的,今天需要使用alpha构建(我们已经在Stack Overflow的生产中使用它了很长一段时间;我只需要一起获得一个版本- docs等等)。
考虑到它有效,我建议我们应该软化v3.*中的#2,这样,虽然默认行为保持不变,但它仍然会检查自定义类型的[ProtoMap(...)]
,并启用该模式。我在犹豫是否要软化第一。
我会对你对这些事情的想法感兴趣!
但要确认:在v3.*中,以下内容可以正常工作,并输出"B"
(对代码的次要解释:在protobuf中,根对象的append===merge,因此一个接一个地序列化两个有效负载,与使用合并的内容序列化字典具有相同的效果,因此两个Serialize
调用使用两个相同的键欺骗一个有效负载):
static class P
{
static void Main()
{
using var ms = new MemoryStream();
var key = new MyTestKey { Value = "X" };
RuntimeTypeModel.Default[typeof(MyTestClass)][1].IsMap = true;
Serializer.Serialize(ms, new MyTestClass() { Dictionary =
new Dictionary<MyTestKey, string> { { key, "A" } } });
Serializer.Serialize(ms, new MyTestClass() { Dictionary =
new Dictionary<MyTestKey, string> { { key, "B" } } });
ms.Position = 0;
var val = Serializer.Deserialize<MyTestClass>(ms).Dictionary[key];
Console.WriteLine(val); // B
}
}
我想我想要的是,在v3.*中,如果没有IsMap = true
行,它可以工作,并且:
[ProtoContract]
public class MyTestClass
{
[ProtoMember(1)]
[ProtoMap] // explicit enable here, because not a normal map type
public Dictionary<MyTestKey, string> Dictionary { get; set; }
}
https://stackoverflow.com/questions/59729148
复制相似问题