The equal in the .net framework.

      先从所有类型的基类object说起。object类有两个equal方法,一个是静态的方法,一个是实例方法。那么这两个方法有什么联系吗?用Reflector查看便知。

View Code
1 public static bool Equals(object objA, object objB)
2 {
3 return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB)));
4 }
5
6

      从上面的代码可以看出,静态的方法是(两个对象引用相等)||(都不为空的情况下,调用实例equal方法)。这样的恰好说明,在两个引用对象相等的情况下,肯定返回true,在引用不相等的情况下,且都不为空的情况下,再根据实例的equal方法。当然其中一个为空也是返回false。那么实例的equal方法里面是什么呢?用反编译器查看可以得知,实例的equal方法调用了一个在CLR内部实现的方法InternalEquals。这个方法实际也是同于"=="运算符。问题来了,最后不都是用到了"=="运算符,那么为什么在objA==objB后面huo呢?

      在编写某些类的时候,我们需要实现业务逻辑上的判断相等,比如一个Person类,当其姓名,年龄相等时我们就认为他们相等。这时就需要重写object的实例equal,实现我们自己的判断相等的逻辑。

View Code
 1 public class Person
2 {
3 public string Name { get; set; }
4 public int Age { get; set; }
5
6 public override bool Equals(object obj)
7 {
8 Person p = obj as Person;
9 if (p == null)
10 return false;
11 return this.Age == p.Age && this.Name==p.Name;
12
13 }
14 }

      实例虚方法是为了在子类重写实现新的判等逻辑。而静态的equal方法是为了在有null对象的情况下不会空引用异常。接下来的问题就是重写equal方法需要注意哪些问题。MSDN建议重写equal方法时最好也重写GetHashCode。在上面的重写equal方法时,我们有一个obj到Person类的转换。当Person在IList<T>这样的泛型方法中,多次的类型转换会带来性能上面的缺失。因此为了弥补这个不足,在.NET2.0引入了IEquatable<T>泛型接口。使用Person类继承IEquatable接口,然后再实现equal方法。

View Code
 public class Person:IEquatable<Person>
{
public string Name { get; set; }
public int Age { get; set; }

//实现IEquatable接口的方法
public bool Equals(Person other)
{
if (other == null)
return false;
return this.Age == other.Age && this.Name == other.Name;
}

//重写object的方法
public override bool Equals(object obj)
{
Person p = obj as Person;
if (p == null)
return false;
return this.Age == p.Age && this.Name==p.Name;
}
}

      这里如果我们运行Person.Equals(p1, p2)或者p1.Equals(p2)用断点调式会发现调用的方法是实现了IEquatable接口的方法,而不是调用重写了Object基类的Equals方法。如果我们用Object obj=(obj) p2; p1.Equals(p2);这两段代码,这时会发现调用的是重写了Object的Equals方法。因此这就需要注意一点:当我们继承实现了IEquatable接口后,没有重写object基类的equal方法,使用上述的调用方式将不能得到我们期待的结果。因此建议在使用IEquatable接口的同时也重写Object类的Equals方法。

View Code
public class Test
{
public void TestPersonEqual()
{
Person p1 = new Person {Name="Raymond",Age=24};
Person p2 = new Person { Name="Raymond",Age=24};
object objPerson = (object)p2;
//调用实现IEquatable的方法,true
Console.WriteLine(Person.Equals(p1, p2));
//调用实现IEquatable的方法,true
Console.WriteLine(p1.Equals(p2));
//将调用重写Object Equals 输出true,如果没有重写Object类的方法将输出false
Console.WriteLine(p1.Equals(objPerson));
}
}


参考文章:http://www.codeproject.com/KB/dotnet/IEquatable.aspx

 

 

 




posted @ 2011-12-22 23:19  雁北飞  阅读(221)  评论(0编辑  收藏  举报