当前位置: 移动技术网 > IT编程>开发语言>c# > c# Equal函数 and 运算符'==' (原发布 csdn 2017年10月15日 20:39:26)

c# Equal函数 and 运算符'==' (原发布 csdn 2017年10月15日 20:39:26)

2019年09月07日  | 移动技术网IT编程  | 我要评论

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、感兴趣的可去查看全部代码。

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、

6.2、 c#语言规范5.0中文版

6.3、

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网