When I use is operator why there is only a null-ch

2019-04-19 08:48发布

问题:

I was wondering how is is operator implemented in C#.And I have written a simple test program (nothing special, just for demonstration purposes):

class Base
{
    public void Display() {  Console.WriteLine("Base"); }
}

class Derived : Base { }

class Program
{
    static void Main(string[] args)
    {
        var d = new Derived();

        if (d is Base)
        {
            var b = (Base) d;
            d.Display();
        }
    }
}

And looked at the generated IL code:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       27 (0x1b)
  .maxstack  2
  .locals init ([0] class ConsoleApplication1.Derived d,
           [1] bool V_1,
           [2] class ConsoleApplication1.Base b)
  IL_0000:  nop
  IL_0001:  newobj     instance void ConsoleApplication1.Derived::.ctor()
  IL_0006:  stloc.0  // set derived (d)
  IL_0007:  ldloc.0 // load derived
  IL_0008:  ldnull // push a null reference
  IL_0009:  ceq   // and compare with d !?
  IL_000b:  stloc.1
  IL_000c:  ldloc.1
  IL_000d:  brtrue.s   IL_001a
  IL_000f:  nop
  IL_0010:  ldloc.0
  IL_0011:  stloc.2
  IL_0012:  ldloc.0
  IL_0013:  callvirt   instance void ConsoleApplication1.Base::Display()
  IL_0018:  nop
  IL_0019:  nop
  IL_001a:  ret
} // end of method Program::Main

When I look at the documentation it says:

Pushes a null reference (type O) onto the evaluation stack.

for ldnull. Ofcourse, I wasn't expecting to see a source code here, but I'm surprised that there is only a null-check.I thought it may be relevant with compiler optimizations because Derived derives from Base so there is no check the compatibility about the types.then I check out and see that the optimizations are turned off.when I turn on the optimizations there wasn't even null-check.

So the question is why there is nothing generated about is operator ? why I see only a null-check ? Is it somehow relevant with is operator and I couldn't see ?

回答1:

The type of d is Derived, which is always of type Base or null. That's why the non-optimized code only checks for null.

The optimized code doesn't do a check at all because the optimizer knows that d is not null (since you assigned a new object to it) and didn't change after the assignment.



回答2:

d has compile-time type Derived, so if d is non-null, it is a Derived and a Derived is always a Base because of the inheritance.

You should not use is in a case like that; it is misleading.

The usual situation with is is the opposite one, where the compile-time type is Base and you check for is Derived.



回答3:

As other have said, this is because the compiler already knows for sure what's happening there. If you wrap eveything in a method and use the is operator in the opposite direction you will see something more convincing:

static void f( Base c ) {
    if ( c is Derived ) {
        Console.WriteLine( "HELLO" );
    }
}

Translates to:

.method private hidebysig static void  f(class test.Base c) cil managed
{
  // Code size       31 (0x1f)
  .maxstack  2
  .locals init ([0] bool CS$4$0000)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  isinst     test.Derived
  IL_0007:  ldnull
  IL_0008:  cgt.un
  IL_000a:  ldc.i4.0
  IL_000b:  ceq
  IL_000d:  stloc.0
  IL_000e:  ldloc.0
  IL_000f:  brtrue.s   IL_001e
  IL_0011:  nop
  IL_0012:  ldstr      "HELLO"
  IL_0017:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_001c:  nop
  IL_001d:  nop
  IL_001e:  ret
} // end of method Program::f


标签: c# il