What are the roles of IEqualityComparer and IEquatable in the Enumerable.SequenceEqual method

做~自己de王妃 提交于 2020-01-05 03:55:14

问题


On this page on MSDN they describe the SequenceEqual method of the Enumerable class.

Halfway down the page it states:

If you want to compare the actual data of the objects in the sequences instead of just comparing their references, you have to implement the IEqualityComparer generic interface in your class. The following code example shows how to implement this interface in a custom data type and provide GetHashCode and Equals methods.

Then they show an example where they do not implement the IEqualityComparer<T> interface at all but instead implement IEquatable<T>. I've done the test myself without implementing either IEqualityComparer or IEquatable and simply overriding Object's Equals and I find it does the trick. Here is the sample:

class AlwaysEquals
{
    override public bool Equals(Object o)
    {
        return true;
    }
    public override int GetHashCode()
    {
        return 1;
    }
}

Note here that my class AlwaysEquals implements nothing, no IEquatable, no IEqualityComparer, nothing. However when I run this code:

AlwaysEquals ae1 = new AlwaysEquals();
AlwaysEquals ae2 = new AlwaysEquals();
AlwaysEquals ae3 = new AlwaysEquals();
AlwaysEquals[] Ae1 = new AlwaysEquals[] {ae3, ae2, ae3};
AlwaysEquals[] Ae2 = new AlwaysEquals[] {ae1, ae1, ae1};
Console.WriteLine(Ae1.SequenceEqual(Ae2));

.. I get True and not False as I would expect from reading the documentation. How does this actually work?


回答1:


IEquatable is used by the generic collections like Dictionary to determine if two objects are equal. If the object doesn't implement IEquatable, Object.Equals method is used.

Why should you implement IEquatable? It has better performance than Object.Equals because the object doesn't need to be casted.

When to not implement IEquatable? Some developers believe that you should only implement it on sealed classes.

If IEqualityComparer is specified in SequenceEquals, it is the one used to check the equality of two objects instead of Object.Equal and it's IEquatable implementation. The example for using it in SequenceEqual is in here http://msdn.microsoft.com/en-us/library/bb342073%28v=vs.110%29.aspx. Note that the method signature accepts an IEqualityComparer.

Many collections like Dictionary also accepts IEqualityComparer in it's constructor

Answering your question

If you didn't provide an IEqualityComparer to SequenceEquals, it will use EqualityComparer.Default.

Decompiled code:

public static bool SequenceEqual<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
{
  return Enumerable.SequenceEqual<TSource>(first, second, (IEqualityComparer<TSource>) null);
}

public static bool SequenceEqual<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
{
  if (comparer == null)
    comparer = (IEqualityComparer<TSource>) EqualityComparer<TSource>.Default;
...

EqualityComparer.Default checks whether type T implements the System.IEquatable interface and, if so, returns an EqualityComparer that uses that implementation. Otherwise, it returns an EqualityComparer that uses the overrides of Object.Equals and Object.GetHashCode provided by T. This is why your Object.Equals is called.



来源:https://stackoverflow.com/questions/19671668/what-are-the-roles-of-iequalitycomparer-and-iequatable-in-the-enumerable-sequenc

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