IEqualityComparer not working as intended

╄→尐↘猪︶ㄣ 提交于 2019-12-01 03:18:57
Piotr Zierhoffer

Change your GetHashCode to work on the compared value. I.e. for your size comparer:

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

And for the other:

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

According to this answer - What's the role of GetHashCode in the IEqualityComparer<T> in .NET?, the hash code is evaluated first. Equals is called in case of collision.

Obviously it would be sensible to work on FileInfos, not on strings.

So maybe:

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

Of course, then you have to change your comparers to work on the correct type.

Your GetHashCode must return the same value for any objects that are of equal value:

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

But this is a much easier way for the whole problem without the extra classes:

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

The hash code is used before Equals is ever called. Since your code gives different hash codes for items that are equal, you're not getting the desired result. Instead, you have to make sure the hash code returned is equal when the items are equal, so for example:

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

However, as Piotr pointed out, this isn't exactly a good way to go about your goal, since you're going to be doing a lot of Path.GetFileName and new FileInfo respectively, which is a going to be a significant performance hit, especially since you're dealing with the file system, which is not exactly known for its speed of response.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!