# IEqualityComparer和IEquatable在Enumerable.SequenceEqual方法中的作用是什么？[英] What are the roles of IEqualityComparer and IEquatable in the Enumerable.SequenceEqual method

### 问题描述

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

```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));
```

..我得到True，而不是False，正如阅读文档所期望的那样.这实际上是如何工作的?

## 推荐答案

i Equabalable 使用词典等通用集合来确定两个对象是否相等.如果对象无法实现Iquatable，则使用对象.

```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检查t类型是否实现了 system.iequatable 接口，如果是的，则返回使用该实现的EqualityComparer.否则，它将返回一个使用 object.quals.equals 和 object.gethashcode 的EqualityComparer.

### 问题描述

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?

## 推荐答案

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

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.