C#中对象的相等性

对象相等的机制有所不同,这取决于比较的是引用类型还是值类型。下面介绍分别介绍引用类型和值类型的相等性。

一、引用类型的比较有 4 个方法,分别是: ReferenceEquals(),Equals(),静态 Equals(),比较运算符(==)

1、ReferenceEquals()

该方法是 object 类的静态方法,参数是两个 object 类型(可以用任意的子类型替代)的变量,用来比较两个引用是否指向同一个类的对象,也就是两个引用是否存放了相同的地址。是返回  true,否则返回 false。

注意:该方法在比较时,认为 null 等于 null。

EE a = new EE();
EE a1 = new EE();
// a 与 a1 虽然都是 EE 类型的对象且使用了相同的构造函数初始化,但是他们是两个对象,存放在堆内存的不同地方。
bool isEqual = ReferenceEquals(a,a1);// false
// 该方法认为 null 与 null 相等
bool isEqual1 = ReferenceEquals(null,null);// true
2、Equals()

Equals()是 object 类的虚方法,通过对象调用,参数是一个 object 类型的变量,该方法与 ReferenceEquals()方法一样用来比较两个引用是否指向同一个类的实例,子类可以重写该方法,实现自定义比较。

注意:

(1)、因为该方法是实例方法,所以不能用来比较空引用(null),这点与 ReferenceEqual()方法不同。

(2)、因为该方法是虚方法,子类可重写来定义自己的比较方式(比如用对象的某个字段来判断两个对象是否相同,用法比较灵活。

下面给出重写后的 Equals()方法,该方法通过比较字段 a 的值来判断两个对象是否相同。

public class EE
{
	public int a = 1;
	// 自定义了构造函数之后,默认构造会被隐藏,需要使用必须显示给出。
	public EE()
	{
	}
	public EE(int a)
	{
		this.a = a;
	}
	// 子类重写父类的方法:1、方法名相同 2、参数列表相同(参数名可以不同) 3、返回值相同
	public override bool Equals(object obj)
	{	EE temp = obj as EE;
		return (temp != null ?temp.a == this.a:false);
	}
}
C#中常用运算符的介绍和使用: 点击打开链接

下面给出调用的示例:

EE a = new EE();
EE a1 = new EE();
EE a2 = new EE(2);
EE a3 = new EE(3);
// 因为在 EE 类中重写了 Equals()方法,只是比较他们的字段的值是否相同,因为:a.a == a1.a,所以比较结果为 true
bool isEqual1 = a.Equals(a1);// true
// 因为 a2.a = 2,a3.a = 3,所以结果为 false
bool isEqual2 = a.Equals(a1);// false
3、静态 Equals()方法

该方法是 object 类的静态方法,直接调用,参数是两个 object 类型的变量,也是用来比较两个引用是否指向同一个对象。

注意:

(1)、该方法与 ReferenceEquals()方法一样可以比较 空引用(null),一个为空,结果为 false,两个都为空,结果为 true。

(2)、该方法在比较非空的对象时,实际上调用的是同名的实例方法(子类重写会调用重写后的方法),所以修改实例方法会影响到该方法。

下面给出示例:

EE a = new EE(2);
EE a1 = new EE(2);
// 注意:静态Equals()在比较 非空 的对象时实际上是调用了实例的 Equals()方法。
// 重写的特点是:父类的引用指向子类的对象时,调用的方法是子类重写的方法。
// 这里调用了 EE 的 Equals() 方法,因为:a.a = a1.a ,所以结果为 true
bool isEqual1 = Equals(a,a1);// true
bool isEqual2 = Equals(null,a1);// false
bool isEqual3 = Equals(null,null);// true
4、比较运算符(==)

比较运算符在比较引用类型时大多数情况下是比较引用,而如果把一些类看作值,比较会更直观,可以重写比较运算符来比较值是否相等。

注意:比较运算符在比较 string 类型的对象时比较的是值而不是引用,实际上上述四种比较方式在比较 string 类型时都做了处理,用来比较值而不是引用。

下面给出示例:

EE a = new EE(2);
EE a1 = new EE(2);
// 比较引用
bool isEqual = a == a1;// false
string  b = "123"; 
string  b1 = "123";
// 对于 string 类型来说,以下四种方法都是比较值是否相等。
bool isEqual1 = ReferenceEquals(b,b1); // true
bool isEqual2 = b.Equals(b1); // true
bool isEqual3 = Equals(b,b1); // true
bool isEqual4 = b == b1; // true
二、值类型的比较,值类型直接继承自 System.ValueType,该类重写了父类(object)的 Equals()方法,大多数值类型自己也重写了改方法,用于比较值是否相同。 

注意:

1、值类型的比较一般是使用比较运算符(==),可以进行两个类型相同(隐式转换或显示转换成相同类型都行)的变量进行 值 的比较,如果相同返回 true,否则返回 false。

2、ReferenceEquals()是用于比较引用类型的,比较值类型时总是返回 false(有装箱操作),所以使用该方法没有意义。

3、结构体比较特殊,他不能使用比较运算符(==),使用 Equals ()方法进行比较时,当两个结构体对象的所有字段的值都相等时返回 true,否则返回 false。

int a = 1;
int? a1 = 1;
string a2 = "1";
// int 重写了 Equals() 方法,用于比较值是否相同
bool isEqual1 = a.Equals(a1); // true
bool isEqual2 = Equals(a,a1); // true
// int 可以隐式转换成 int?
bool isEqual3 = a == a1; //true 
// int 与 string 不能直接用 == 比较,需要进行显示转换或其他操作变成相应的类型
bool isEqual4 = a.ToString() == a2; // true

// FF是一个结构体
FF b = new FF(2);
FF b1 = new FF(2);
// 值类型直接继承自 System.ValueType,该类重写了 Equals() 方法,
// 因为 b 和 b1 两个对象的所有字段的值相同,所以结果为 true
bool isEqual5 = Equals(b,b1); // true
C#中的类型转换介绍: 点击打开链接
结构体与类的区分: 点击打开链接




你可能感兴趣的:(C#,c#,Equals,相等比较)