2010-11-07 29 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