jueves, 3 de junio de 2010

operador +, cadenas, cadenas constante y el compilador en C#

Al igual que en java, el compilador de C# es capaz de realizar optimizaciones al momento de compilar el codigo y convertir una instruccion en otra, utilizando las funciones definidas en la clase String.

Como se vio en el post dedicado a java, es posible utilizar el compilador a nuestro favor, cuando se conoce como funciona.
En el siguiente ejemplo, se muestra una concatenacion, utilizando el operador +.

01: using System;
02: using System.Collections.Generic;
03: using System.Linq;
04: using System.Text;
05: 
06: namespace ClassLibrary1
07: {
08:     public class Class1
09:     {
10:         void Test()
11:         {
12:             string a = "cadena1";
13:             string b = "cadena2";
14:             string x = a + b;
15:             Console.WriteLine(x);
16:         }
17:     }
18: }
19: 

Al decompilar el codigo, empleando el comando ildasm, se obtiene el siguiente codigo:

.method private hidebysig instance void  Test() cil managed
   {
     // Code size       29 (0x1d)
     .maxstack  2
     .locals init ([0] string a,
              [1] string b,
              [2] string x)
     IL_0000:  nop
     IL_0001:  ldstr      "cadena1"
     IL_0006:  stloc.0
     IL_0007:  ldstr      "cadena2"
     IL_000c:  stloc.1
     IL_000d:  ldloc.0
     IL_000e:  ldloc.1
     IL_000f:  call       string [mscorlib]System.String::Concat(string,
                                                              string)
     IL_0014:  stloc.2
     IL_0015:  ldloc.2
     IL_0016:  call       void [mscorlib]System.Console::WriteLine(string)
     IL_001b:  nop
     IL_001c:  ret
   } // end of method Class1::Test

El codigo que genera codigo similar es el siguiente:


01: using System;
02: using System.Collections.Generic;
03: using System.Linq;
04: using System.Text;
05: 
06: namespace ClassLibrary1
07: {
08:     public class Class2
09:     {
10:         void Test()
11:         {
12:             string x = String.Concat("cadena1","cadena2");
13:             Console.WriteLine(x);
14:         }
15:     }
16: }
17: 

Como es posible observar, el codigo generado ejecuta una funcion propia de la clase String, la cual sabe concatenar cadenas, generando una nueva cadena del tamaño necesario. Sin embargo, este comportamiento solo se presenta cuando se emplean 2, 3 y hasta 4 cadenas, ya cuando se trata de 5 o mas cadenas, primero construye un arreglo de cadenas, con las cadenas a concatenar y posteriormente emplea el metodo Concat(String[]). Por ejemplo:


01: using System;
02: using System.Collections.Generic;
03: using System.Linq;
04: using System.Text;
05: 
06: namespace ClassLibrary1
07: {
08:     class Class3
09:     {
10:         void Test()
11:         {
12:             string a = "cadena1";
13:             string b = "cadena2";
14:             string c = "cadena3";
15:             string d = "cadena4";
16:             string e = "cadena5";
17:             string x = a + b + c + d + e;
18:             Console.WriteLine(x);
19:         }
20:     }
21: }
22: 

Produciendo el siguiente codigo:

.method private hidebysig instance void  Test() cil managed
  {
    // Code size       84 (0x54)
    .maxstack  3
    .locals init ([0] string a,
             [1] string b,
             [2] string c,
             [3] string d,
             [4] string e,
             [5] string x,
             [6] string[] CS$0$0000)
    IL_0000:  nop
    IL_0001:  ldstr      "cadena1"
    IL_0006:  stloc.0
    IL_0007:  ldstr      "cadena2"
    IL_000c:  stloc.1
    IL_000d:  ldstr      "cadena3"
    IL_0012:  stloc.2
    IL_0013:  ldstr      "cadena4"
    IL_0018:  stloc.3
    IL_0019:  ldstr      "cadena5"
    IL_001e:  stloc.s    e
    IL_0020:  ldc.i4.5
    IL_0021:  newarr     [mscorlib]System.String
    IL_0026:  stloc.s    CS$0$0000
    IL_0028:  ldloc.s    CS$0$0000
    IL_002a:  ldc.i4.0
    IL_002b:  ldloc.0
    IL_002c:  stelem.ref
    IL_002d:  ldloc.s    CS$0$0000
    IL_002f:  ldc.i4.1
    IL_0030:  ldloc.1
    IL_0031:  stelem.ref
    IL_0032:  ldloc.s    CS$0$0000
    IL_0034:  ldc.i4.2
    IL_0035:  ldloc.2
    IL_0036:  stelem.ref
    IL_0037:  ldloc.s    CS$0$0000
    IL_0039:  ldc.i4.3
    IL_003a:  ldloc.3
    IL_003b:  stelem.ref
    IL_003c:  ldloc.s    CS$0$0000
    IL_003e:  ldc.i4.4
    IL_003f:  ldloc.s    e
    IL_0041:  stelem.ref
    IL_0042:  ldloc.s    CS$0$0000
    IL_0044:  call       string [mscorlib]System.String::Concat(string[])
    IL_0049:  stloc.s    x
    IL_004b:  ldloc.s    x
    IL_004d:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_0052:  nop
    IL_0053:  ret
  } // end of method Class3::Test


En cambio, el compilador de C# al igua que el de java, es capaz de detectar cadenas constantes "inline" y generar una cadena con el resultado en tiempo de compilacion, evitando el procesamiento en tiempo de ejecucion


01: using System;
02: using System.Collections.Generic;
03: using System.Linq;
04: using System.Text;
05: 
06: namespace ClassLibrary1
07: {
08:     public class Class4
09:     {
10:         void Test()
11:         {
12:             string x = "cadena1" + "cadena2";
13:             Console.WriteLine(x);
14:         }
15:     }
16: }
17: 

Generando el siguiente codigo:

.method private hidebysig instance void  Test() cil managed
{
  // Code size       15 (0xf)
  .maxstack  1
  .locals init ([0] string x)
  IL_0000:  nop
  IL_0001:  ldstr      "cadena1cadena2"
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_000d:  nop
  IL_000e:  ret
} // end of method Class4::Test

El compilador puede ayudar en el desempeño del sistema, al generar algunas de estas operaciones previamente.

No hay comentarios.:

Publicar un comentario