Null的==运算

看C#代码:

internal class Program
{
    // Fields
    private string _isSuper;

    // Methods
    private static void Main(string[] args)
    {
        Program program = new Program();
        if (program._isSuper == "qwe")
        {
            Console.WriteLine("There is a1 Exception!");
        }
        Console.Read();
    }
}

 

msil看看:

.class private auto ansi beforefieldinit Program
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 8
        L_0000: ldarg.0
        L_0001: call instance void [mscorlib]System.Object::.ctor()
        L_0006: ret
    }

    .method private hidebysig static void Main(string[] args) cil managed
    {
        .entrypoint
        .maxstack 2
        .locals init (
            [0] class ConsoleApplication1.Program program,
            [1] bool CS$4$0000)
        L_0000: nop
        L_0001: newobj instance void ConsoleApplication1.Program::.ctor()
        L_0006: stloc.0
        L_0007: ldloc.0
        L_0008: ldfld string ConsoleApplication1.Program::_isSuper
        L_000d: ldstr "qwe"
        L_0012: call bool [mscorlib]System.String::op_Equality(string, string)
        L_0017: ldc.i4.0
        L_0018: ceq
        L_001a: stloc.1
        L_001b: ldloc.1
        L_001c: brtrue.s L_002b
        L_001e: nop
        L_001f: ldstr "There is a1 Exception!"
        L_0024: call void [mscorlib]System.Console::WriteLine(string)
        L_0029: nop
        L_002a: nop
        L_002b: call int32 [mscorlib]System.Console::Read()
        L_0030: pop
        L_0031: ret
    }

特别注意了:

    .method private hidebysig static void Main(string[] args) cil managed
    {
        .entrypoint
        .maxstack 2
        .locals init (
            [0] class ConsoleApplication1.Program program,
            [1] bool CS$4$0000)
        L_0000: nop
        L_0001: newobj instance void ConsoleApplication1.Program::.ctor()
        L_0006: stloc.0
        L_0007: ldloc.0
        L_0008: ldfld string ConsoleApplication1.Program::_isSuper
        L_000d: ldstr "qwe"
        L_0012: call bool [mscorlib]System.String::op_Equality(string, string)
        L_0017: ldc.i4.0
        L_0018: ceq
        L_001a: stloc.1
        L_001b: ldloc.1
        L_001c: brtrue.s L_002b
        L_001e: nop
        L_001f: ldstr "There is a1 Exception!"
        L_0024: call void [mscorlib]System.Console::WriteLine(string)
        L_0029: nop
        L_002a: nop
        L_002b: call int32 [mscorlib]System.Console::Read()
        L_0030: pop
        L_0031: ret
    }
 

修改C#:

            if(program._isSuper==null)
            {
                Console.WriteLine("There is a1 Exception!");
            }

再看msil:

.class private auto ansi beforefieldinit ConsoleApplication1.Program
    extends [mscorlib]System.Object
{
    // Fields
    .field private string _isSuper

    // Methods
    .method private hidebysig static 
        void Main (
            string[] args
        ) cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 43 (0x2b)
        .maxstack 2
        .entrypoint
        .locals init (
            [0] class ConsoleApplication1.Program program,
            [1] bool CS$4$0000
        )

        IL_0000: nop
        IL_0001: newobj instance void ConsoleApplication1.Program::.ctor()
        IL_0006: stloc.0
        IL_0007: ldloc.0
        IL_0008: ldfld string ConsoleApplication1.Program::_isSuper
        IL_000d: ldnull
        IL_000e: ceq
        IL_0010: ldc.i4.0
        IL_0011: ceq
        IL_0013: stloc.1
        IL_0014: ldloc.1
        IL_0015: brtrue.s IL_0024

        IL_0017: nop
        IL_0018: ldstr "There is a1 Exception!"
        IL_001d: call void [mscorlib]System.Console::WriteLine(string)
        IL_0022: nop
        IL_0023: nop

        IL_0024: call int32 [mscorlib]System.Console::Read()
        IL_0029: pop
        IL_002a: ret
    } // end of method Program::Main

    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x2087
        // Code size 7 (0x7)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        IL_0006: ret
    } // end of method Program::.ctor

// end of class ConsoleApplication1.Program

 

特别注意的是:

        IL_0008: ldfld string ConsoleApplication1.Program::_isSuper
        IL_000d: ldnull
        IL_000e: ceq
        IL_0010: ldc.i4.0

前后比较:比较方法由call bool [mscorlib]System.String::op_Equality(string, string)变成了ceq,同时这段代码的长度也变长了4个字节,因为string是引用类型了!

 public static bool operator ==(string a, string b)
{
    return Equals(a, b);
}

public static bool Equals(string a, string b)
{
    return ((a == b) || (((a != null) && (b != null)) && a.Equals(b)));
}

就是string的运算符==的重载方法

另外要注意:

The == operator doesn't always get translated to ceq.A type can overload it with operator == ().

System.Decimal does this for example,it overloads all of the operators since their implementation is untrivial and the jitter doesn't have special knowledge of the type(the compiler does).

You'll find it back with Reflector as the Decimal.op_Equality() method.Which leads you to FCllCompare,a method that's attributed with MethodImplOptions.IntenalCall.These kind of method are special ,the jitter has secret knowledge of them.It contaims a table of all internal call functions.the jitter looks yp the table entry by the method name.Then compiled the address of the corresponding C++ function as provided in the table into the call instruction.Beware that the function name was changed since the Rotor release, search for FCallAdd, it it the next entry in the table. Which takes you to COMDecimal::Compare. Which takes you to the comdecimal.cpp source code file.

The x86 and x64 jitters know how to convert the ceq opcode to machine code directly without needing a helper function, it generates the native machine instructions inline. Actual generated code depends on the type of the values being compared. And the target, the x64 jitter uses SSE instructions, the x86 uses FPU instructions to compare floating point values. Other jitters will implement them differently yet of course.

A helper function like Object.InternalEquals() is also an internal method, just like FCallCompare. You'd use the same strategy to find the implementation.

posted @ 2012-03-22 17:50  szjdw  阅读(271)  评论(0编辑  收藏  举报