2014-01-28 158 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为更简单的方法。 –