【问题标题】:IEqualityComparer not working as intendedIEqualityComparer 未按预期工作
【发布时间】:2014-01-28 18:20:30
【问题描述】:

我有一个List 存储在我的计算机上的文件路径。我的目标是先过滤掉同名的文件,再过滤掉大小相同的文件。
为此,我创建了两个实现IEqualityComparer<string> 的类,并实现了EqualsGetHashCode 方法。

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

但是代码不起作用。

它没有抛出任何异常,也没有任何编译器错误,但问题是代码不起作用(不排除重复文件)。

那么,我该如何解决这个问题呢?我可以做些什么来使代码正常工作。

【问题讨论】:

标签: c# .net linq iequalitycomparer


【解决方案1】:

更改您的 GetHashCode 以处理比较值。 IE。对于您的尺寸比较器:

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

显然,在FileInfos 上工作是明智的,而不是在字符串上。

所以也许:

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

当然,那么您必须更改比较器才能使用正确的类型。

【讨论】:

  • +1:只要实例相等,它们的哈希码也必须相等,但如果哈希码相等,并不一定意味着实例相等。
【解决方案2】:

您的 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();

【讨论】:

    【解决方案3】:

    在调用 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.GetFileNamenew FileInfo ,这将对性能产生重大影响,尤其是因为您正在处理文件系统,而文件系统的响应速度并不完全为人所知。

    【讨论】:

      猜你喜欢
      • 2021-06-04
      • 2022-01-24
      • 2015-05-11
      • 2020-05-15
      • 2014-10-31
      • 2018-02-12
      • 2014-01-20
      • 2015-01-13
      • 2013-08-01
      相关资源
      最近更新 更多