如果有个类对象的集合,要判断一个对象是不是存在这个集合中,可以用Contains方法判断。但我们都知道这判断是引用。假设这个集合里面存在和这个对象所有的值成员的值都相等的元素,我们就认为这个对象存在于这个集合中,那么我们该如果做? 我能想到就是重写Object基类中的Equals方法,然后为这个集合添加一个扩展方法。如下:
public class Racer
{
public Racer(string firstName, string lastName, string country = "", int wins = 0)
{
this.FirstName = firstName;
this.LastName = lastName;
this.Country = country;
this.Wins = wins;
}
public string FirstName { get; private set; }
public string LastName { get; private set; }
public string Country { get; private set; }
public int Wins { get; private set; }
public override bool Equals(object obj)
{
Racer other = obj as Racer;
if (other == null)
return false;
return FirstName == other.FirstName
&& LastName == other.LastName
&& Country == other.Country
&& Wins == other.Wins;
}
}
List<Racer>的扩展方式:
public static bool HasItem(this List<Racer> listR, Racer racer)
{
return listR.Any(x => x.Equals(racer));
}
然后我们就可以调用HasItem判断,测试一下:
List<Racer> listRacer = new List<Racer>();
listRacer.Add(new Racer("xixiao", "meng","china"));
listRacer.Add(new Racer("zhstar", "zhou","china"));
Racer racer = new Racer("zhstar", "zhou","china");
Console.WriteLine("listRacer HasItem racer:{0}", listRacer.HasItem(racer));
Console.WriteLine("listRacer Contains racer:{0}", listRacer.Contains(racer));
运行代码代码我们发现HasItem方法和Contains方法都返回了True。这是为什么呢?跟踪调试发现,原来Contains方法也是通过我们重写的Equals方法来判断的。原来如此,于是我们可以删掉扩展方法直接使用系统的Contains方法了。那是不是Contains的判断一定就是调用基类中Equals方法呢?
我们修改一下Racer类,让它集成IEquatable接口,实现Equals方法,让它返回引用比较的结果:
View Code
public class Racer :IEquatable<Racer>
{
public Racer(string firstName, string lastName, string country = "", int wins = 0)
{
this.FirstName = firstName;
this.LastName = lastName;
this.Country = country;
this.Wins = wins;
}
public string FirstName { get; private set; }
public string LastName { get; private set; }
public string Country { get; private set; }
public int Wins { get; private set; }
public override bool Equals(object obj)
{
Racer other = obj as Racer;
if (other == null)
return false;
return FirstName == other.FirstName
&& LastName == other.LastName
&& Country == other.Country
&& Wins == other.Wins;
}
public bool Equals(Racer other)
{
return object.ReferenceEquals(this, other);
}
}
在按照前面那样测试一下Contains和HasItem方法,我们会发现返回的结果都是false。这是不是说明了对于Equals方法,如果实现了IEquatable接口,那么会首先使用这个接口的Equals方法,如果没有实现这个接口就会使用基类的或者重写基类的Equals方法呢?
我们再修改一下Racer类,把IEquatable接口去掉,但保留Equals方法:
View Code
public class Racer
{
public Racer(string firstName, string lastName, string country = "", int wins = 0)
{
this.FirstName = firstName;
this.LastName = lastName;
this.Country = country;
this.Wins = wins;
}
public string FirstName { get; private set; }
public string LastName { get; private set; }
public string Country { get; private set; }
public int Wins { get; private set; }
public override bool Equals(object obj)
{
Racer other = obj as Racer;
if (other == null)
return false;
return FirstName == other.FirstName
&& LastName == other.LastName
&& Country == other.Country
&& Wins == other.Wins;
}
public bool Equals(Racer other)
{
return object.ReferenceEquals(this, other);
}
}
再运行一下,会发现HasItem方法返回了false,但Contains方法却返回True。
到这里,其实就很明白,对集合来说,它是一个泛型的类,无法知道每个类型具体的成员,在判断一个元素或者查找一个元素的时候,首先依赖的是IEquatable接口的Equals方法,如果没有继承这个接口那么就使用基类中的Equals方法。但我们在调用对象实例里面的方法,它就会找到那个最适合被调用的方法。比如上面的例子中如果我们把扩展方法的第二个参数该成object类型,就会调用我们重写的基类的Equals方法。