我的计算机上存有List
个文件路径。我的目的是首先筛选出具有相同名称的文件,然后筛选出具有相同大小的文件
为此,我创建了两个实现IEqualityComparer<string>
的类,并实现了Equals
和GetHashCode
方法。
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 :(得分: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
s而不是字符串是明智的。
所以也许:
FileList.Select(x => new FileInfo(x))
.Distinct(new CustomTextComparer())
.Distinct(new CustomSizeComparer());
当然,您必须更改比较器才能使用正确的类型。
答案 1 :(得分: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();
答案 2 :(得分:5)
在调用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();
}
}
然而,正如Piotr指出的那样,这不是一个很好的方法来实现你的目标,因为你将要做Path.GetFileName
和{{批次 1}},这将是一个重大的性能损失,特别是因为你正在处理文件系统,而这个文件系统的响应速度并不完全清楚。