IDictionary的问题<complex key,=“”complex =“”value =“”> .Remove()实现</complex>

时间:2010-11-07 21:51:58

标签: c#

您好我不明白为什么这段代码不起作用 - 它不会删除密钥;我的输出仍然是“2”。

Bencode.BencodeDict d = new myTorrent.Bencode.BencodeDict();
d.Dict.Add(new Bencode.BencodeString("info"), new Bencode.BencodeString("1"));
d.Dict.Add(new Bencode.BencodeString("info2"), new Bencode.BencodeString("2"));
d.Dict.Add(new Bencode.BencodeString("info3"), new Bencode.BencodeString("3"));

d.Remove(new Bencode.BencodeString("info2"));
Bencode.BencodeVariable s1;
s1 = d[new Bencode.BencodeString("info2")];
if (s1 != null)
   Console.WriteLine(System.Text.UTF8Encoding.UTF8.GetString(s1.Encode()));

我的BencodeDict和BencodeString

namespace myTorrent.Bencode
{
   class BencodeDict : BencodeVariable, IDictionary<BencodeString, BencodeVariable>
   {
      private Dictionary<BencodeString, BencodeVariable> dict;

      public BencodeDict() {
         this.dict = new Dictionary<BencodeString,BencodeVariable>();
      }

      protected override void InternalDecode(BinaryReader data) { /*...*/ }
      public override long ByteLength() { /*...*/ }    
      public override byte[] Encode() { /*...*/ }

      //#region Overridden Methods
        public override bool Equals(object ob)
        {
            if (ob == null)
               return false;

            BencodeDict y = ob as BencodeDict;
            if (this.dict.Count != y.dict.Count)
                return false;

            BencodeVariable val;
            foreach (KeyValuePair<BencodeString, BencodeVariable> keypair in this.dict)
            {
                if (!y.TryGetValue(keypair.Key, out val))
                    return false;

                if (!keypair.Value.Equals(val))
                    return false;
            }

            return true;
        }

        public override int GetHashCode()
        {
            int result = 0;
            foreach (KeyValuePair<BencodeString, BencodeVariable> keypair in this.dict)
            {
                result ^= keypair.Key.GetHashCode();
                result ^= keypair.Value.GetHashCode();
            }
            return result;
        }

        #region IDictionary and IList methods
        public void Add(BencodeString key, BencodeVariable value)
        {
            this.dict.Add(key, value);
        }

        public void Add(KeyValuePair<BencodeString, BencodeVariable> item)
        {
            this.dict.Add(item.Key, item.Value);
        }
        public void Clear()
        {
            this.dict.Clear();
        }

        public bool Contains(KeyValuePair<BencodeString, BencodeVariable> item)
        {  
            if (!this.dict.ContainsKey(item.Key))
                return false;

            return this.dict[item.Key].Equals(item.Value);
        }

        public bool ContainsKey(BencodeString key)
        {
            foreach(KeyValuePair<BencodeString, BencodeVariable> pair in this.dict) {
               if (pair.Key.Equals(key))
                  return true;
            }
            return false;
        }

        public void CopyTo(KeyValuePair<BencodeString, BencodeVariable>[] array, int arrayIndex) { /*...*/ }
        public int Count
        {
            get { return this.dict.Count; }
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public bool Remove(BencodeString key)
        {

            return this.dict.Remove(key);
        }

        public bool Remove(KeyValuePair<BencodeString, BencodeVariable> item)
        {
            return this.dict.Remove(item.Key);
        }

        public bool TryGetValue(BencodeString key, out BencodeVariable value)
        {
           foreach(KeyValuePair<BencodeString, BencodeVariable> pair in this.dict)
              if ( pair.Key.Equals(key) ) {
                 value = pair.Value;
                 return true;
              }
           value = null;
           return false;
        }

        public BencodeVariable this[BencodeString key]
        {  
            get {
                foreach(KeyValuePair<BencodeString, BencodeVariable> pair in this.dict)
                     if ( pair.Key.Equals(key) )
                     return pair.Value;
                return null;
            }
            set { this.dict[key] = value; }
        }

        public ICollection<BencodeString> Keys
        {
            get { return this.dict.Keys; }
        }

        public ICollection<BencodeVariable> Values
        {
            get { return this.dict.Values; }
        }

        public IEnumerator<KeyValuePair<BencodeString, BencodeVariable>> GetEnumerator()
        {
            return this.dict.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.dict.GetEnumerator();
        }
        #endregion
   }
}


   class BencodeString : BencodeVariable
      {
         private byte[] str;

         public BencodeString() {
            this.str = null;
         }

         public BencodeString(string str) {
            this.str = encoding.GetBytes(str);
         }

         public override bool Equals(object ob)
         {
            if (ob == null)
               return false;

            BencodeString y = ob as BencodeString;

            return (encoding.GetString(this.str) == encoding.GetString(y.str));
         }

         public override int GetHashCode()
         {

            return this.str.GetHashCode();
         }
      }

2 个答案:

答案 0 :(得分:2)

你依靠byte[].GetHashCode()做一些可取的事情。它不会。数组不实现相等或散列操作 - 您将获得默认(标识)行为。

重写您的GetHashCode方法,如下所示:

public override int GetHashCode()
{
    int result = 17;
    foreach (byte b in str)
    {
        result = result * 31 + b;
    }
    return result;
}

(也不清楚encoding是什么,但这是另一回事。)

请注意,如果Equals是非空引用,则NullReferenceException覆盖也会引发ob,但不会BencodeString

编辑:假设您实际上想要检查字节数组是否相同,我不会在您的等式检查中调用Encoding.GetString。毫无意义。只需直接检查字节数组内容即可。像这样的东西是一个合理的字节数组相等性检查 - 虽然我通常更喜欢写一个通用的等价物:

private static bool ArraysEqual(byte[] x, byte[] y)
{
    if (x == y)
    {
        return true;
    }
    if (x == null || y == null)
    {
        return false;
    }
    if (x.Length != y.Length)
    {
        return false;
    }
    for (int i = 0; i < x.Length; i++)
    {
        if (x[i] != y[i])
        {
            return false;
        }
    }
    return true;
}

如果你想要检查两个字节数组是否被解码为相等的字符串,那么你应该在两个地方使用Encoding.GetString ......但这很少是适当的做,IMO。

请注意,不清楚为什么你有自己的类字符串类开始。这里存在各种潜在问题......不均等编码,空引用等。

答案 1 :(得分:1)

Equal的值也产生相同的哈希码非常重要。这是一个明显(但不一定有效)的解决方法:

     public override int GetHashCode()
     {
         return encoding.GetString(this.str).GetHashCode();
     }

使字符串在内部不像Unicode字符串那样是一种代码味道,但在这里可能是故意的。它通常应用于外部接口。您的实现将允许在读取字符串后更改编码。但是一个非常严重的问题是字典在发生时不再有效。你将无法找到钥匙。