question

WilliamLiu-0692 avatar image
0 Votes"
WilliamLiu-0692 asked Paul-5034 commented

A question about unboxing

Learned the "Boxing and Unboxing (C# Programming Guide)" article from msdn.

These lines are called boxing and unboxing.

 int i = 123;
 // The following line boxes i.
 object o = i;

 o = 456;
 i = (int)o;  // unboxing

My question is, is the following codes also called "unboxing"? If so, does it suffer the same performance penalty like above codes?

 int i = 10;
 object o = i;
 if (o is int j) // unboxing?
 {
     System.Console.WriteLine(j);
 }

 if (o is 10) // one further step, unboxing?
 {
     System.Console.WriteLine("It`s 10! ");
 }






dotnet-csharp
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

Paul-5034 avatar image
0 Votes"
Paul-5034 answered Paul-5034 commented

If you're interested in how you'd figure this out you could look at the IL that's generated.

I use this for testing C# expressions/programs, and you can see the IL that's generated if you click the "IL" button above the results window:
https://www.linqpad.net

Once you have the IL all you need to do is cross-reference the instruction codes (for example unbox.any, unbox, stloc, call) to this list:
https://en.wikipedia.org/wiki/List_of_CIL_instructions

Your first expression produces IL like the following:

 IL_0000:  nop         
 IL_0001:  ldc.i4.s    0A 
 IL_0003:  stloc.0     // i
 IL_0004:  ldloc.0     // i
 IL_0005:  box         System.Int32
 IL_000A:  stloc.1     // o
 IL_000B:  ldloc.1     // o
 IL_000C:  dup         
 IL_000D:  stloc.s     04 
 IL_000F:  isinst      System.Int32
 IL_0014:  brfalse.s   IL_0021
 IL_0016:  ldloc.s     04 
 IL_0018:  unbox.any   System.Int32
 IL_001D:  stloc.2     // j
 IL_001E:  ldc.i4.1    
 IL_001F:  br.s        IL_0022
 IL_0021:  ldc.i4.0    
 IL_0022:  stloc.3     
 IL_0023:  ldloc.3     
 IL_0024:  brfalse.s   IL_002F
 IL_0026:  nop         
 IL_0027:  ldloc.2     // j
 IL_0028:  call        System.Console.WriteLine
 IL_002D:  nop         
 IL_002E:  nop         
 IL_002F:  ret

You can see there is an "unbox.any" in there, which the article states means:
"Extract a value-type from obj, its boxed representation, and copy to the top of the stack."

So that certainly suggests that there's an unboxing going on, which makes sense because that statement is syntactical sugar for:

 int i = 10;
 object o = i;
 if (o is int)
 {
     int j = (int)o;
     System.Console.WriteLine(j);
 }

And this does have an explicit unboxing.

Your second snippet produces this IL:

 IL_0000:  nop         
 IL_0001:  ldc.i4.s    0A 
 IL_0003:  stloc.0     // i
 IL_0004:  ldloc.0     // i
 IL_0005:  box         System.Int32
 IL_000A:  stloc.1     // o
 IL_000B:  ldc.i4.s    0A 
 IL_000D:  box         System.Int32
 IL_0012:  ldloc.1     // o
 IL_0013:  call        System.Object.Equals
 IL_0018:  stloc.2     
 IL_0019:  ldloc.2     
 IL_001A:  brfalse.s   IL_0029
 IL_001C:  nop         
 IL_001D:  ldstr       "It`s 10! "
 IL_0022:  call        System.Console.WriteLine
 IL_0027:  nop         
 IL_0028:  nop         
 IL_0029:  ret  

You can see there is a "call" to "System.Object.Equals" that is being done on "o", but no unboxing required which suggests it's just doing a standard value-equality check.



· 6
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Very clear to me, thanks so much!

0 Votes 0 ·
Paul-5034 avatar image Paul-5034 WilliamLiu-0692 ·

No problem

0 Votes 0 ·

One more question, I test the following code with ildasm.exe which can also inspect the IL code.
C# 9 with .net5:

 namespace ConsoleApp3
 {
     internal static class Program
     {
         private static void Main()
         {
             int i = 10;
             object o = i;
             if (o is int j) // unboxing?
             {
                 System.Console.WriteLine(j);
             }
             if (o is 10) // one further step, unboxing?
             {
                 System.Console.WriteLine("It`s 10! ");
             }
         }
     }
 }


I saw there are two unbox.any lines in the IL code, looks like it`s using unboxing here.. I also tried with dnSpy to look into the generated IL code, but still get two "unbox.any".

Could you let me know if there is something I mistake? Or it`s just using unboxing here?






0 Votes 0 ·
WilliamLiu-0692 avatar image WilliamLiu-0692 WilliamLiu-0692 ·

IL code is a bit long, so I paste it in a new reply..

IL code from ildasm

   .locals init (int32 V_0,
            object V_1,
            int32 V_2,
            bool V_3,
            bool V_4)
   IL_0000:  nop
   IL_0001:  ldc.i4.s   10
   IL_0003:  stloc.0
   IL_0004:  ldloc.0
   IL_0005:  box        [System.Runtime]System.Int32
   IL_000a:  stloc.1
   IL_000b:  ldloc.1
   IL_000c:  isinst     [System.Runtime]System.Int32
   IL_0011:  brfalse.s  IL_001d
   IL_0013:  ldloc.1
   IL_0014:  unbox.any  [System.Runtime]System.Int32
   IL_0019:  stloc.2
   IL_001a:  ldc.i4.1
   IL_001b:  br.s       IL_001e
   IL_001d:  ldc.i4.0
   IL_001e:  stloc.3
   IL_001f:  ldloc.3
   IL_0020:  brfalse.s  IL_002b
   IL_0022:  nop
   IL_0023:  ldloc.2
   IL_0024:  call       void [System.Console]System.Console::WriteLine(int32)
   IL_0029:  nop
   IL_002a:  nop
   IL_002b:  ldloc.1
   IL_002c:  isinst     [System.Runtime]System.Int32
   IL_0031:  brfalse.s  IL_003f
   IL_0033:  ldloc.1
   IL_0034:  unbox.any  [System.Runtime]System.Int32
   IL_0039:  ldc.i4.s   10
   IL_003b:  ceq
   IL_003d:  br.s       IL_0040
   IL_003f:  ldc.i4.0
   IL_0040:  stloc.s    V_4
   IL_0042:  ldloc.s    V_4
   IL_0044:  brfalse.s  IL_0053
   IL_0046:  nop
   IL_0047:  ldstr      "It`s 10! "
   IL_004c:  call       void [System.Console]System.Console::WriteLine(string)
   IL_0051:  nop
   IL_0052:  nop
   IL_0053:  ret
 } // end of method Program::Main
0 Votes 0 ·
WilliamLiu-0692 avatar image WilliamLiu-0692 WilliamLiu-0692 ·

Find a online tool, sharplab.io, also see the two "unbox.any" lines.


0 Votes 0 ·
Show more comments