C# ProtoBuf网络字典重复密钥处理(Map)

C# ProtoBuf网络字典重复密钥处理(Map),c#,dictionary,duplicates,protobuf-net,C#,Dictionary,Duplicates,Protobuf Net,我用protobuf.net序列化了一些数据。数据是一个映射,包含一些重复项(这是因为我的密钥没有实现IEquatable) 我想将数据反序列化到字典中并忽略重复项。 这似乎有一个属性,即[ProtoMap(DisableMap=false)],文档中说: 禁用“地图”处理;字典将使用。改为添加(键、值) of[键]=值 基本上,我希望行为是[key]=value,但显然,该属性被忽略了 我做错什么了吗?是否有任何方法可以实现所需的(并记录在案的)忽略重复项的行为 示例代码: 1.生成具有重复项

我用protobuf.net序列化了一些数据。数据是一个映射,包含一些重复项(这是因为我的密钥没有实现IEquatable)

我想将数据反序列化到字典中并忽略重复项。 这似乎有一个属性,即
[ProtoMap(DisableMap=false)]
,文档中说:

禁用“地图”处理;字典将使用。改为添加(键、值) of[键]=值

基本上,我希望行为是
[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..:

/------------------------------------------
//以下部分生成了字节,这需要密钥不实现IEquatable
// ------------- ------------- ------------- ------------- ------------- ------------- -------------
var cache=new MyTestClass(){Dictionary=new Dictionary()};
cache.Dictionary[newmytestkey{Value=“X”}]=“A”;
cache.Dictionary[newmytestkey{Value=“X”}]=“B”;
var bytes=cache.Serialize();
var bytesStr=string.Join(“,”字节);//"10,8,10,3,10,1,88,18,1,65,10,8,10,3,10,1,88,18,1,66";
//..
[数据合同]
公共类MyTestKey
{
[数据成员(顺序=1)]
公共字符串值{get;set;}
}
[数据合同]
公共类MyTestClass
{
[数据成员(顺序=1)]
[ProtoMap(DisableMap=false)]
公共字典{get;set;}
}
´´´
2.尝试使用属性IEquatable反序列化数据,但失败..:
[DataContract]
公共类MyTestKey:IEquatable
{
[数据成员(顺序=1)]
公共字符串值{get;set;}
公共布尔等于(MyTestKey其他)
{
if(ReferenceEquals(null,other))返回false;
if(ReferenceEquals(this,other))返回true;
返回值==其他.Value;
}
公共覆盖布尔等于(对象对象对象)
{
if(ReferenceEquals(null,obj))返回false;
if(ReferenceEquals(this,obj))返回true;
if(obj.GetType()!=this.GetType())返回false;
返回等于((MyTestKey)obj);
}
公共覆盖int GetHashCode()
{
返回值(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();
'

例外情况:已添加具有相同密钥的项

公共静态类序列化扩展
{
公共静态T反序列化(此字节[]字节)
{
如果(字节==null)
返回默认值(T);
使用(var ms=新内存流(字节))
{
返回序列化程序。反序列化(ms);
}
}
公共静态字节[]序列化(此T设置)
{
使用(var ms=new MemoryStream())
{
序列化器。序列化(ms,设置);
返回ToArray女士();
}
}

这里发生了一些不同的事情;“map”模式实际上是您想要的模式-因此,您不是试图禁用map,而是试图强制启用它(在大多数常见的字典场景中,它现在默认为启用)

有一些复杂情况:

  • 当处理
    [ProtoContract(…)]
    [ProtoMember(…)]
    时,库仅处理
    [ProtoMap(…)]
  • 即使如此,它也只处理在proto规范中作为“map”键有效的键类型的
    [ProtoMap(…)]
  • 您可以手动打开它(不是通过属性),但在v2.*它在运行时强制执行与#2相同的检查,这意味着它将失败
  • 从#3手动启用在v3.*中起作用(当前为alpha):

    RuntimeTypeModel.Default[typeof(MyTestClass)][1].IsMap=true;
    
    然而,这显然是不雅观的,今天需要使用alpha构建(我们在Stack Overflow的生产中已经使用了很长一段时间;我只需要一起发布一个版本——文档等等)

    考虑到它的工作原理,我很想建议我们应该在v3.*中软化#2,这样在默认行为保持不变的情况下,它仍然会检查自定义类型的
    [ProtoMap(…)]
    ,并启用该模式。我对是否软化#1犹豫不决

    我对你对这些事情的想法很感兴趣

    但需要确认的是:以下代码在v3*中运行良好,并输出
    “B”
    (代码的次要解释:在protobuf中,append===merge for root对象,因此依次序列化两个有效负载与使用组合内容序列化字典具有相同的效果,因此这两个
    Serialize
    调用具有两个相同键的欺骗有效负载):

    静态类P
    {
    静态void Main()
    {
    使用var ms=new MemoryStream();
    var key=newmytestkey{Value=“X”};
    RuntimeTypeModel.Default[typeof(MyTestClass)][1].IsMap=true;
    Serializer.Serialize(ms,新的MyTestClass(){Dictionary=
    新字典{{key,“A”}});
    Serializer.Serialize(ms,新的MyTestClass(){Dictionary=
    新字典{{key,“B”}});
    ms.Position=0;
    var val=Serializer.Deserialize(ms.Dictionary[key];
    Console.WriteLine(val);//B
    }
    }
    
    我想我希望的是,在v3.*中,它在没有
    IsMap=true
    行的情况下工作,并且:

    [协议]
    公共类MyTestClass
    {
    [原成员(1)]
    [ProtoMap]//此处显式启用,b
    
    [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();
            }
        }