2014-01-28 69 views
10

我有一個List存儲在我的電腦上的文件路徑。我的目標是首先篩選出具有相同名稱的文件,然後篩選出具有相同大小的文件。
爲此,我做了兩類實施IEqualityComparer<string>,並實施了EqualsGetHashCode的方法。IEqualityComparer不按預期工作

var query = FilesList.Distinct(new CustomTextComparer()) 
        .Distinct(new CustomSizeComparer()); 

兩個類的代碼如下: -

public class CustomTextComparer : IEqualityComparer<string> 
{ 
    public bool Equals(string x, string y) 
    { 
     if (Path.GetFileName(x) == Path.GetFileName(y)) 
     { 
      return true; 
     } 
     return false; 
    } 
    public int GetHashCode(string obj) 
    { 
     return obj.GetHashCode(); 
    } 
} 
public class CustomSizeComparer : IEqualityComparer<string> 
{ 
    public bool Equals(string x, string y) 
    { 
     if (new FileInfo(x).Length == new FileInfo(y).Length) 
     { 
      return true; 
     } 
     else 
     { 
      return false; 
     } 
    } 
    public int GetHashCode(string obj) 
    { 
     return obj.GetHashCode(); 
    } 
} 

但代碼不能正常工作。

它不會拋出任何異常,也沒有任何編譯器錯誤,但問題是代碼不起作用(不排除重複的文件)。

那麼,我該如何糾正這個問題呢?有什麼我可以做的,使代碼正常工作。

+0

你標題並不反映問題的內容。請閱讀[我如何寫一個好的標題?](http://meta.stackexchange。com/questions/10647/how-do-i-write-a-good-title) –

回答

16

更改您的GetHashCode以處理比較值。即爲你的尺寸比較器:

public int GetHashCode(string obj) 
{ 
    return FileInfo(x).Length.GetHashCode(); 
} 

而對於其他:

public int GetHashCode(string obj) 
{ 
    return Path.GetFileName(obj).GetHashCode(); 
} 

根據這個答案 - What's the role of GetHashCode in the IEqualityComparer<T> in .NET?,哈希碼首先計算。在發生碰撞時調用Equals

很明顯,在FileInfo上工作,而不是在字符串上工作。

所以也許:

FileList.Select(x => new FileInfo(x)) 
     .Distinct(new CustomTextComparer()) 
     .Distinct(new CustomSizeComparer()); 

當然,你必須改變你的comparers對正確類型的工作。

+2

+1:只要實例相同,它們的散列碼也必須相等,但如果散列碼相等,則不一定意味着實例是平等的。 –

4

散列碼在Equals被調用之前使用。由於您的代碼爲相同的項目提供了不同的哈希代碼,因此您沒有得到期望的結果。相反,你必須確保返回的哈希碼等於當項目是相等的,因此,例如:

public class CustomTextComparer : IEqualityComparer<string> 
{ 
    public bool Equals(string x, string y) 
    { 
     if (Path.GetFileName(x) == Path.GetFileName(y)) 
     { 
      return true; 
     } 
     return false; 
    } 
    public int GetHashCode(string obj) 
    { 
     return Path.GetFileName(obj).GetHashCode(); 
    } 
} 

然而,正如彼得指出,這不正是去了解你的目標的好方法,因爲你將要分別做批次Path.GetFileNamenew FileInfo,這將會是一個重大的性能問題,特別是在你處理文件系統時,它並不完全知道它的速度響應。

7

你的GetHashCode必須返回相同的值是同等價值的任何對象:

// Try this 
public int GetHashCode(string obj) 
{ 
    return Path.GetFileName(x).GetHashCode(); 
} 

// And this 
public int GetHashCode(string obj) 
{ 
    return new FileInfo(x).Length.GetHashCode(); 
} 

但是,這是整個問題沒有額外的類更簡單的方法:

var query = FilesList 
       .GroupBy(f => Path.GetFileName(f)).Select(g => g.First()) 
       .GroupBy(f => new FileInfo(f).Length).Select(g => g.First()) 
       .ToList(); 
+0

+1爲更簡單的方法。 –