类似于IComparer<T> VS IComparable<T>.
public interface IComparable<in T>
{ // Methods
int CompareTo(T other);
}
public interface IComparer<in T>
{ // Methods
int Compare(T x, T y);
}
public interface IEquatable<T>
{ // Methods
bool Equals(T other);
}
public interface IEqualityComparer<in T>
{ // Methods
bool Equals(T x, T y);
int GetHashCode(T obj);
}
IEqualityComparer<T>是用于custom 比较是否相等的,而System.IEquatable<T>是用于default 比较的。即某个class 会实现 IEquatable<T>来定义相等操作,而 IEqualityComparer<T> 则用于自定义判断。例如用在LinkedList.Find(T value)方法中。
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
以string 类为例来说明:
public sealed class String : IComparable, ICloneable, IConvertible, IComparable<string>, IEnumerable<char>, IEnumerable, IEquatable<string>
例如Dictionary<TKey, TValue>的key 不可以重复,当调用Add方法时就会判断是否相等。
对比Container类的构造函数:
public Dictionary(int capacity, IEqualityComparer<TKey> comparer); //Dictionary需要对key进行判断是否相等的操作所以需要实现IEqualityComparer接口的对象
public LinkList(); //不需要sort,也不需要判断添加的对象是否相等所以不需要comparer
public List(); 动态数组. 仅在sort方法中需要提供一个comparer对象,如果没有则使用集合中存储对象默认的比较方法即要求被存储类必须实现IComparable接口
public BinarySearchTree(IComparer<T> comparer); 二叉树需要对添加的元素进行比较。 this.comparer = Comparer<T>.Default;
public SortSet(IComparer<T> comparer); 红黑树也需要对添加的元素进行比较
using System;
using System.Collections.Generic;
class Program
{
static Dictionary<Box, String> boxes;
static void Main(string[] args)
{
BoxSameDimensions boxDim = new BoxSameDimensions();
boxes = new Dictionary<Box, string>(boxDim);
Console.WriteLine("Boxes equality by dimensions:");
Box redBox = new Box(8, 4, 8);
Box greenBox = new Box(8, 6, 8);
Box blueBox = new Box(8, 4, 8);
Box yellowBox = new Box(8, 8, 8);
AddBox(redBox, "red");
AddBox(greenBox, "green");
AddBox(blueBox, "blue");
AddBox(yellowBox, "yellow");
Console.WriteLine();
Console.WriteLine("Boxes equality by volume:");
BoxSameVolume boxVolume = new BoxSameVolume();
boxes = new Dictionary<Box, string>(boxVolume);
Box pinkBox = new Box(8, 4, 8);
Box orangeBox = new Box(8, 6, 8);
Box purpleBox = new Box(4, 8, 8);
Box brownBox = new Box(8, 8, 4);
AddBox(pinkBox, "pink");
AddBox(orangeBox, "orange");
AddBox(purpleBox, "purple");
AddBox(brownBox, "brown");
}
public static void AddBox(Box bx, string name)
{
try
{
boxes.Add(bx, name);
Console.WriteLine("Added {0}, Count = {1}, HashCode = {2}",
name, boxes.Count.ToString(), bx.GetHashCode());
}
catch (ArgumentException)
{
Console.WriteLine("A box equal to {0} is already in the collection.", name);
}
}
}
public class Box
{
public Box(int h, int l, int w)
{
this.Height = h;
this.Length = l;
this.Width = w;
}
public int Height { get; set; }
public int Length { get; set; }
public int Width { get; set; }
}
class BoxSameDimensions : EqualityComparer<Box>
{
public override bool Equals(Box b1, Box b2)
{
if (b1.Height == b2.Height & b1.Length == b2.Length
& b1.Width == b2.Width)
{
return true;
}
else
{
return false;
}
}
public override int GetHashCode(Box bx)
{
int hCode = bx.Height ^ bx.Length ^ bx.Width;
return hCode.GetHashCode();
}
}
class BoxSameVolume : EqualityComparer<Box>
{
public override bool Equals(Box b1, Box b2)
{
if (b1.Height * b1.Width * b1.Length ==
b2.Height * b2.Width * b2.Length)
{
return true;
}
else
{
return false;
}
}
public override int GetHashCode(Box bx)
{
int hCode = bx.Height ^ bx.Length ^ bx.Width;
return hCode.GetHashCode();
}
}
/* This example produces the following output:
*
Boxes equality by dimensions:
Added red, Count = 1, HashCode = 46104728
Added green, Count = 2, HashCode = 12289376
A box equal to blue is already in the collection.
Added yellow, Count = 3, HashCode = 55530882
Boxes equality by volume:
Added pink, Count = 1, HashCode = 30015890
Added orange, Count = 2, HashCode = 1707556
A box equal to purple is already in the collection.
A box equal to brown is already in the collection.
*
*/