c# Equal函数 and 运算符'==' (原发布 csdn 2017年10月15日 20:39:26)
程序员文章站
2022-06-19 20:12:19
1、==、!=、、= 运算符为比较运算符(comparison operator)。C 语言规范5.0中文版中比较运算符的描述如下: 2、通用类型系统 3、值类型Equal函数 and 运算符'==' 3.1、常见类型 int、float、double、decimal等虽然继承自ValueType, ......
1、==、!=、<、>、<= 和>= 运算符为比较运算符(comparison operator)。c#语言规范5.0中文版中比较运算符的描述如下:
2、通用类型系统
3、值类型equal函数 and 运算符'=='
3.1、常见类型 int、float、double、decimal等虽然继承自valuetype,但其结构体内部重写了equal。
3.1.1、 int,float,double,decimal内部的equal函数和 '=='重载符函数。
int32 { public override bool equals(object obj) { if (!(obj is int32)) { return false; } return m_value == ((int32)obj).m_value; } [system.runtime.versioning.nonversionable] public bool equals(int32 obj) { return m_value == obj; } } double { // true if obj is another double with the same value as the current instance. this is // a method of object equality, that only returns true if obj is also a double. public override bool equals(object obj) { if (!(obj is double)) { return false; } double temp = ((double)obj).m_value; // this code below is written this way for performance reasons i.e the != and == check is intentional. if (temp == m_value) { return true; } return isnan(temp) && isnan(m_value); } public bool equals(double obj) { if (obj == m_value) { return true; } return isnan(obj) && isnan(m_value); } [system.runtime.versioning.nonversionable] public static bool operator ==(double left, double right) { return left == right; } } single { public override bool equals(object obj) { if (!(obj is single)) { return false; } float temp = ((single)obj).m_value; if (temp == m_value) { return true; } return isnan(temp) && isnan(m_value); } public bool equals(single obj) { if (obj == m_value) { return true; } return isnan(obj) && isnan(m_value); } [system.runtime.versioning.nonversionable] public static bool operator ==(single left, single right) { return left == right; } } decimal { // checks if this decimal is equal to a given object. returns true // if the given object is a boxed decimal and its value is equal to the // value of this decimal. returns false otherwise. // [system.security.securitysafecritical] // auto-generated public override bool equals(object value) { if (value is decimal) { decimal other = (decimal)value; return fcallcompare(ref this, ref other) == 0; } return false; } [system.security.securitysafecritical] // auto-generated public bool equals(decimal value) { return fcallcompare(ref this, ref value) == 0; } [system.security.securitysafecritical] // auto-generated public static bool operator ==(decimal d1, decimal d2) { return fcallcompare(ref d1, ref d2) == 0; } //暂时不知道此函数内部代码,如有知道还望告知。 //根据测试结果,推测如果两个decimal数相等,返回0 [system.security.securitycritical] // auto-generated [resourceexposure(resourcescope.none)] [methodimplattribute(methodimploptions.internalcall)] [reliabilitycontract(consistency.willnotcorruptstate, cer.success)] private static extern int fcallcompare(ref decimal d1, ref decimal d2); }
3.1.2、感兴趣的可去reference source查看全部代码。
3.1.3、测试代码:
//t is int 、float、double、decimal、byte、char t a = 1234567890;//0.1234567890f、0.123456789、1234567890m、(byte)11、'a' t b = 1234567890;//0.1234567890f、0.123456789、1234567890m、(byte)11、'a' console.writeline(a == b);//返回true console.writeline(a.equals(b));//返回true console.writeline(a.equals((object)b));//返回true /* console.writeline((object)a == b);//编译错误:运算符‘==’无法应用与‘object’和‘t’类型操作数 console.writeline(a == (object)b);//编译错误:运算符‘==’无法应用与‘object’和‘t’类型操作数 //console.writeline((object)a == (object)b);//返回false,下面解释为什么是false。这个是引用类型'==',放到下文介绍 */
3.1.4、结论:对于简单常见值类型 int、float、double、decimal等,equal函数 and 运算符'==',如果其值相等,返回true;否则,返回false。
3.2、 结构体struct
3.2.1、 valuetype内部的equals函数
valuetype { [system.security.securitysafecritical] public override bool equals (object obj) { bcldebug.perf(false, "valuetype::equals is not fast. "+this.gettype().fullname+" should override equals(object)"); if (null==obj) { return false; } runtimetype thistype = (runtimetype)this.gettype(); runtimetype thattype = (runtimetype)obj.gettype(); if (thattype!=thistype) { return false; } object thisobj = (object)this; object thisresult, thatresult; // if there are no gc references in this object we can avoid reflection // and do a fast memcmp if (cancomparebits(this)) return fastequalscheck(thisobj, obj); fieldinfo[] thisfields = thistype.getfields(bindingflags.instance | bindingflags.public | bindingflags.nonpublic); for (int i=0; i<thisfields.length; i++) { thisresult = ((rtfieldinfo)thisfields[i]).unsafegetvalue(thisobj); thatresult = ((rtfieldinfo)thisfields[i]).unsafegetvalue(obj); if (thisresult == null) { if (thatresult != null) return false; } else if (!thisresult.equals(thatresult)) { return false; } } return true; } [system.security.securitysafecritical] // auto-generated [resourceexposure(resourcescope.none)] [methodimplattribute(methodimploptions.internalcall)] private static extern bool cancomparebits(object obj); [system.security.securitysafecritical] // auto-generated [resourceexposure(resourcescope.none)] [methodimplattribute(methodimploptions.internalcall)] private static extern bool fastequalscheck(object a, object b); }
3.2.2、结构体(只有值类型,重写equal函数 and 运算符'==')
3.2.2.1、测试代码:
struct point { public double x; public double y; public double z; public point(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } public override bool equals(object obj) { if (!(obj is point)) { return false; } if (((point)obj).x == this.x) { return true; } return false; } public bool equals(point obj) { if (obj.x == this.x) { return true; } return false; } //运算符“point.operator ==(point, point)”要求也要定义匹配的运算符“!=” public static bool operator ==(point left, point right) { return left.x == right.x; } public static bool operator !=(point left, point right) { return left.x != right.x; } } point p1 = new point(1, 2, 3); point p2 = p1; p1.y = 100; console.writeline(p1 == p2);//返回true console.writeline(p1.equals(p2)); // 返回true console.writeline(p1.equals((object)p2)); // 返回true
3.2.2.2、结论:此时程序执行我们重写的equal函数 and 运算符'=='。
3.2.3、结构体(只有值类型,不重写equal函数 and 运算符'==')
3.2.3.1、测试代码:
struct point { public double x; public double y; public double z; public point(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } } point p1 = new point(1, 2, 3); point p2 = p1; console.writeline(p1 == p2);//编译错误:运算符"=="无法应用于"point"和"point"类型的操作数 console.writeline(p1.equals(p2)); // 返回true console.writeline(p1.equals((object)p2)); // 返回true p1.y = 100; console.writeline(p1.equals(p2)); // 返回false console.writeline(p1.equals((object)p2)); // 返回false
3.2.3.2、程序执行时,cancomparebits(this)返回true,代码执行return fastequalscheck(thisobj, obj);
3.2.3.3、结论:程序判断struct里面所有字段的值,如果全部相等,返回true;否则,返回false。
3.2.4、复杂结构体(有值类型、引用类型,重写equal函数 and 运算符'==')
3.2.4.1、测试代码:
public struct valpoint { public double x; public double y; public double z; public valpoint(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } public static bool operator ==(valpoint left, valpoint right) { return left.x == right.x; } public static bool operator !=(valpoint left, valpoint right) { return left.x != right.x; } } public class refpoint { public double x; public double y; public double z; public refpoint(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } } public struct valline { public valpoint vpoint; // 值类型成员 public refpoint rpoint; // 引用类型成员 public valline(valpoint vpoint, refpoint rpoint) { this.vpoint = vpoint; this.rpoint = rpoint; } public override bool equals(object obj) { if (!(obj is valline)) { return false; } if (((valline)obj).vpoint == this.vpoint) { return true; } return false; } public bool equals(valline obj) { if (obj.vpoint == this.vpoint) { return true; } return false; } public static bool operator ==(valline left, valline right) { return left.vpoint == right.vpoint; } public static bool operator !=(valline left, valline right) { return left.vpoint != right.vpoint; } } valpoint vpoint = new valpoint(1, 2, 3); valpoint vpoint2 = new valpoint(1, 2, 3); valpoint vpoint3 = new valpoint(10, 20, 30); refpoint rpoint = new refpoint(4, 5, 6); refpoint rpoint2 = new refpoint(7, 8, 9); valline p1 = new valline(vpoint, rpoint); valline p2 = p1; p2.vpoint = vpoint2; console.writeline(p1 == p2); //返回true console.writeline(p1.equals(p2)); //返回true console.writeline(p1.equals((object)p2)); //返回true p2 = p1; p2.vpoint = vpoint3; console.writeline(p1 == p2); //返回true console.writeline(p1.equals(p2)); //返回false console.writeline(p1.equals((object)p2)); //返回false p2 = p1; p2.rpoint = rpoint2; console.writeline(p1 == p2); //返回true console.writeline(p1.equals(p2)); //返回true console.writeline(p1.equals((object)p2)); //返回true
3.2.4.2、结论:此时程序执行我们重写的equal函数 and 运算符'=='。
3.2.5、复杂结构体(内部值类型、引用类型,不重写equal函数 and 运算符'==')
3.2.5.1、测试代码:
public struct valpoint { public double x; public double y; public double z; public valpoint(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } } public class refpoint { public double x; public double y; public double z; public refpoint(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } } public struct valline { public valpoint vpoint; // 值类型成员 public refpoint rpoint; // 引用类型成员 public valline(valpoint vpoint, refpoint rpoint) { this.vpoint = vpoint; this.rpoint = rpoint; } } valpoint vpoint = new valpoint(1, 2, 3); valpoint vpoint2 = new valpoint(1, 2, 3); valpoint vpoint3 = new valpoint(10, 20, 30); refpoint rpoint = new refpoint(4, 5, 6); refpoint rpoint2 = new refpoint(7, 8, 9); valline p1 = new valline(vpoint, rpoint); valline p2 = p1; console.writeline(p1 == p2);//编译错误:运算符"=="无法应用于"point"和"point"类型的操作数 p2.vpoint = vpoint2; console.writeline(p1.equals(p2)); //返回true console.writeline(p1.equals((object)p2)); //返回true p2 = p1; p2.vpoint = vpoint3; console.writeline(p1.equals(p2)); //返回false console.writeline(p1.equals((object)p2)); //返回false p2 = p1; p2.rpoint = rpoint2; console.writeline(p1.equals(p2)); //返回false console.writeline(p1.equals((object)p2)); //返回false
3.2.5.2、程序执行时,cancomparebits(this)返回false,代码执行valuetype类equal函数的下面语句
fieldinfo[] thisfields = thistype.getfields(bindingflags.instance | bindingflags.public | bindingflags.nonpublic); for (int i=0; i<thisfields.length; i++) { thisresult = ((rtfieldinfo)thisfields[i]).unsafegetvalue(thisobj); thatresult = ((rtfieldinfo)thisfields[i]).unsafegetvalue(obj); if (thisresult == null) { if (thatresult != null) return false; } else if (!thisresult.equals(thatresult)) { return false; } } return true;
3.2.5.3、结论:程序判断struct里面所有字段,值类型就判断值是否相等;引用类型就判断是否引用相等。
4、引用类型equal函数 and 运算符'=='
4.1、字符串string
4.1.1、c#语言规范5.0中文版中的字符串相等运算符介绍
4.1.2、string的equal函数和'=='重载运算符函数代码
string { // determines whether two strings match. [reliabilitycontract(consistency.willnotcorruptstate, cer.mayfail)] public override bool equals(object obj) { if (this == null) //this is necessary to guard against reverse-pinvokes and throw new nullreferenceexception(); //other callers who do not use the callvirt instruction string str = obj as string; if (str == null) return false; if (object.referenceequals(this, obj)) return true; if (this.length != str.length) return false; return equalshelper(this, str); } // determines whether two strings match. [pure] [reliabilitycontract(consistency.willnotcorruptstate, cer.mayfail)] public bool equals(string value) { if (this == null) //this is necessary to guard against reverse-pinvokes and throw new nullreferenceexception(); //other callers who do not use the callvirt instruction if (value == null) return false; if (object.referenceequals(this, value)) return true; if (this.length != value.length) return false; return equalshelper(this, value); } public static bool operator == (string a, string b) { return string.equals(a, b); } // determines whether two strings match. [pure] public static bool equals(string a, string b) { if ((object)a==(object)b) { return true; } if ((object)a==null || (object)b==null) { return false; } if (a.length != b.length) return false; return equalshelper(a, b); } [system.security.securitysafecritical] // auto-generated [reliabilitycontract(consistency.willnotcorruptstate, cer.mayfail)] private unsafe static bool equalshelper(string stra, string strb) { contract.requires(stra != null); contract.requires(strb != null); contract.requires(stra.length == strb.length); int length = stra.length; fixed (char* ap = &stra.m_firstchar) fixed (char* bp = &strb.m_firstchar) { char* a = ap; char* b = bp; // unroll the loop #if amd64 // for amd64 bit platform we unroll by 12 and // check 3 qword at a time. this is less code // than the 32 bit case and is shorter // pathlength while (length >= 12) { if (*(long*)a != *(long*)b) return false; if (*(long*)(a+4) != *(long*)(b+4)) return false; if (*(long*)(a+8) != *(long*)(b+8)) return false; a += 12; b += 12; length -= 12; } #else while (length >= 10) { if (*(int*)a != *(int*)b) return false; if (*(int*)(a+2) != *(int*)(b+2)) return false; if (*(int*)(a+4) != *(int*)(b+4)) return false; if (*(int*)(a+6) != *(int*)(b+6)) return false; if (*(int*)(a+8) != *(int*)(b+8)) return false; a += 10; b += 10; length -= 10; } #endif // this depends on the fact that the string objects are // always zero terminated and that the terminating zero is not included // in the length. for odd string sizes, the last compare will include // the zero terminator. while (length > 0) { if (*(int*)a != *(int*)b) break; a += 2; b += 2; length -= 2; } return (length <= 0); } } }
4.1.3、object.referenceequals(this, value)如果this、value是同一个引用,返回true;否则,返回false。
{ string a = "a1!"; string b = "a1!"; console.writeline(object.referenceequals(a, b));//返回true,可以判断编译器将a与b所指向的"a1!"优化成一个地方。 } { string a = "test"; string b = string.copy(a); console.writeline(object.referenceequals(a, b));//返回false } { string a = "test"; string b = (string)a.clone(); console.writeline(object.referenceequals(a, b));//返回true } { char[] ch = new char[] { 'a', 'a', '@' }; string a = "aa@"; string b = new string(ch); console.writeline(object.referenceequals(a, b));//返回false }
4.1.4、学习equalshelper(string stra, string strb)函数之前,我们先看一段代码
unsafe { char[] firstchara = "abc".tochararray(); int length = firstchara.length; fixed (char* ap = firstchara) { for (int i = 0; i < length; i++) { console.writeline(*(char*)(ap + i)); } } } unsafe { int[] firstchara = new int[] { 1, 20, 300 }; int length = firstchara.length; fixed (int* ap = firstchara) { for (int i = 0; i < length; i++) { console.writeline(*(int*)(ap + i)); } } }
4.1.5、修改后equalshelper(string stra, string strb)函数
private unsafe static bool equalshelper(string stra, string strb) { contract.requires(stra != null); contract.requires(strb != null); contract.requires(stra.length == strb.length); int length = stra.length; char[] firstchara = stra.tochararray(); char[] firstcharb = strb.tochararray(); fixed (char* ap = &firstchara[0]) fixed (char* bp = &firstcharb[0])//因无法使用m_firstchar,此处是我自行修改。ps:个人认为m_firstchar是指字符串的第一字符,但是无法证明。 //fixed (char* ap = &stra.m_firstchar) fixed (char* bp = &strb.m_firstchar) { char* a = ap; char* b = bp; while (length >= 10) { if (*(int*)a != *(int*)b) return false; if (*(int*)(a + 2) != *(int*)(b + 2)) return false; if (*(int*)(a + 4) != *(int*)(b + 4)) return false; if (*(int*)(a + 6) != *(int*)(b + 6)) return false; if (*(int*)(a + 8) != *(int*)(b + 8)) return false; a += 10; b += 10; length -= 10; } // this depends on the fact that the string objects are // always zero terminated and that the terminating zero is not included // in the length. for odd string sizes, the last compare will include // the zero terminator. while (length > 0) { if (*(int*)a != *(int*)b) break; a += 2; b += 2; length -= 2; } return (length <= 0); } }
4.1.6、修改说明
1、fixed (char* ap = &stra.m_firstchar) fixed (char* bp = &strb.m_firstchar)-> fixed (char* ap = &firstchara[0]) fixed (char* bp = &firstcharb[0]) 2、(*(int*)a->获取的数据是两个char值(低位ascii*65536+高位ascii)[低位在前,高位在后]。 [char两个字节,范围u+0000到u+ffff] 3、(*(char*)a->获取的数据是一个char值[见上面测试例子]
4.1.7、测试equalshelper(string stra, string strb)函数
{ string a = "abcd"; string b = "abcd"; console.writeline(equalshelper(a,b));//返回true } { string a = "test"; string b = string.copy(a); console.writeline(equalshelper(a, b));//返回true } { string a = "test"; string b = (string)a.clone(); console.writeline(equalshelper(a, b));//返回true } { char[] ch = new char[] { 'a', 'a', '@' }; string a = "aa@"; string b = new string(ch); console.writeline(equalshelper(a, b));//返回true }
4.1.8、结论:string类型 a == b、string.equals(a, b)、a.equals(b)、a.equals((object)b),如果 a 的值与 b 的值相同,则为 true;否则为 false。
4.2、类class
4.2.1、c#语言规范5.0中文版中的引用类型相等运算符介绍
4.2.2、object内部的equals函数
object { public virtual bool equals(object obj) { return runtimehelpers.equals(this, obj);//无法查到详细代码 } public static bool equals(object obja, object objb) { if (obja==objb) { return true; } if (obja==null || objb==null) { return false; } return obja.equals(objb); } [reliabilitycontract(consistency.willnotcorruptstate, cer.success)] [system.runtime.versioning.nonversionable] public static bool referenceequals (object obja, object objb) { return obja == objb; } }
4.2.3、类(不重写equal函数 and 运算符'==')
public class refpoint { public double x; public double y; public double z; public refpoint(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } } refpoint p1 = new refpoint(4, 5, 6); refpoint p2 = p1; console.writeline(p1.equals(p2));//返回true console.writeline(object.equals(p1, p2));//返回true console.writeline(object.referenceequals(p1, p2));//返回true console.writeline(p1 == p2);//返回true p2 = new refpoint(4, 5, 6);//虽然值一样,但是引用对象不一样 console.writeline(p1.equals(p2));//返回false console.writeline(object.equals(p1, p2));//返回false console.writeline(object.referenceequals(p1, p2));//返回false console.writeline(p1 == p2);//返回false
4.2.4、类(重写equal函数 and 运算符'==')
public class refpoint { public double x; public double y; public double z; public refpoint(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } public override bool equals(object obj) { if (!(obj is refpoint)) { return false; } if (((refpoint)obj).x == this.x) { return true; } return false; } public bool equals(refpoint obj) { if (obj.x == this.x) { return true; } return false; } public static bool operator ==(refpoint left, refpoint right) { return left.x == right.x; } public static bool operator !=(refpoint left, refpoint right) { return left.x != right.x; } } refpoint p1 = new refpoint(4, 5, 6); refpoint p2 = p1; console.writeline(p1.equals(p2));//返回true console.writeline(object.equals(p1, p2));//返回true console.writeline(object.referenceequals(p1, p2));//返回true console.writeline(p1 == p2);//返回true p2 = new refpoint(4, 50, 60); console.writeline(p1.equals(p2));//返回true console.writeline(object.equals(p1, p2));//返回true console.writeline(object.referenceequals(p1, p2));//返回false console.writeline(p1 == p2);//返回true
4.2.5、referenceequals (object obja, object objb)返回obja == objb。如果obja、 objb引用同一个对象(只判断是否引用同一个对象,即使我们自行重载了'=='运算符,也没用),返回true;否则,返回false。
5、总结
先介绍简单值类型,再到结构体,字符串,类。把每个类型equal和'=='用法做个总结,加深自己记忆的同时,也希望能帮助到你。另:本文只代表本人观点,如果有误,还望告知。
6、参考
6.1、c#类型基础
6.2、 c#语言规范5.0中文版
6.3、reference source
下一篇: 昆仑穴的具体位置,常按有什么好处?