2010-11-07 30 views
1

嗨,我不明白为什么这段代码不起作用 - 它不会删除键;输出仍然是“2”。IDictionary问题<复杂键,复杂值> .Remove()实现

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(); 
     } 
     } 
+0

那里有一些复杂的.Equals逻辑,为什么不在该方法的顶部设置一个断点并查看出错的地方? – 2010-11-07 21:58:29

回答

1

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

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

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

+0

+1,因为在仍然解码为相同字符串的不相等字节数组(例如,通过将解码为“?”的无效字节序列)应该以相同方式处理的情况下,这是正确的方法。如果字节数组真的应该相等,那么最好检查数组本身是否相等(按照我的编辑)。 – 2010-11-07 22:19:34

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。

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

+0

这是不正确的。在应用编码之后,其中两个字符串可能相等。但不会与您的算法生成相同的哈希码。 – 2010-11-07 22:10:45

+0

非常感谢。我想知道这件事,但没有检查-_- – Steve 2010-11-07 22:13:32

+0

@Hans:是的,我会为此编辑。 – 2010-11-07 22:16:34