El Gourmet .NET: Que es mas eficiente, un if, un ?: o un ??

|

Hace tiempo que no hacia una entrega del Goumet .NET, pues bien hace dias estaba preguntandome esto, es que mas eficiente? una instruccion if, el operador ?: o el operador ?? (Este operador lo he descubierto recientemente!!! Es tan grande C# que a uno se le pasan estas cosas...), bueno para probar esto hice el siguiente codigo:


using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
namespace CSharpTestHost
{
public class clsTest
{
///
/// Prueba con instruccion If
///

/// pdtbData1: Parametro a ser evaluado
/// Devuelve: Un datatable instanciado
public DataTable IfTest(DataTable pdtbData1)
{
DataTable dtbResult;
if (pdtbData1 != null)
{
dtbResult = pdtbData1;
}
else
{
dtbResult = new DataTable();
}
return dtbResult;
}

///
/// Prueba con operador ?:
///

/// pdtbData1:Parametro a ser evaluado
/// Devuelve: Un datatable instanciado

public DataTable InLineIfTest(DataTable pdtbData1)
{
return (pdtbData1 != null) ? pdtbData1 : new DataTable();
}

///
/// Prueba con operador ??
///

/// pdtbData1: Parametro a ser evaluado
/// Devuelve: Un datatable instanciado

public DataTable InLineIfTest2(DataTable pdtbData1)
{
return pdtbData1 ?? new DataTable();
}
}
}

Despues de esto si ustedes revisan los 3 metodos de esa clase cumplen exactamente la misma funcion, es decir evaluan si el objeto parametro, en este caso un DataTable, es diferente de null y devuelven un nuevo objeto de ser esto cierto, debemos recordar que el hecho de usar menos codigo no necesariamente quiere decir que es mas eficiente, como ustedes saben cuando uno usa C# la implementacion de operadores es posible y detras de esos tambien se puede poner bastante codigo!!
Con esta duda en mente, se me ocurrio utilizar ildasm (para quienes no la conocen a esta herramienta lo que hace es desemsablar el codigo de tu assembly .net y te lo muestra en MSIL, que es muy parecido al assembler y la verdad es bastante facil de leer) y compare los 3 metodos, con la referencia de que MSIL es casi assembler es un punto perfecto para comparar los 3 metodos, aqui estan los resultados:

Metodo con If:


.method public hidebysig instance class [System.Data]System.Data.DataTable
IfTest(class [System.Data]System.Data.DataTable pdtbData1) cil managed
{
// Code size 29 (0x1d)
.maxstack 2
.locals init ([0] class [System.Data]System.Data.DataTable dtbResult,
[1] class [System.Data]System.Data.DataTable CS$1$0000,
[2] bool CS$4$0001)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldnull
IL_0003: ceq
IL_0005: stloc.2
IL_0006: ldloc.2
IL_0007: brtrue.s IL_000f
IL_0009: nop
IL_000a: ldarg.1
IL_000b: stloc.0
IL_000c: nop
IL_000d: br.s IL_0017
IL_000f: nop
IL_0010: newobj instance void [System.Data]System.Data.DataTable::.ctor()
IL_0015: stloc.0
IL_0016: nop
IL_0017: ldloc.0
IL_0018: stloc.1
IL_0019: br.s IL_001b
IL_001b: ldloc.1
IL_001c: ret
} // end of method clsTest::IfTest

Metodo con In Line If u operador ?:


.method public hidebysig instance class [System.Data]System.Data.DataTable
InLineIfTest(class [System.Data]System.Data.DataTable pdtbData1) cil managed
{
// Code size 17 (0x11)
.maxstack 2
.locals init ([0] class [System.Data]System.Data.DataTable CS$1$0000)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: brtrue.s IL_000b
IL_0004: newobj instance void [System.Data]System.Data.DataTable::.ctor()
IL_0009: br.s IL_000c
IL_000b: ldarg.1
IL_000c: stloc.0
IL_000d: br.s IL_000f
IL_000f: ldloc.0
IL_0010: ret
} // end of method clsTest::InLineIfTest

Metodo con operador ??:


.method public hidebysig instance class [System.Data]System.Data.DataTable
InLineIfTest2(class [System.Data]System.Data.DataTable pdtbData1) cil managed
{
// Code size 16 (0x10)
.maxstack 2
.locals init ([0] class [System.Data]System.Data.DataTable CS$1$0000)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: dup
IL_0003: brtrue.s IL_000b
IL_0005: pop
IL_0006: newobj instance void [System.Data]System.Data.DataTable::.ctor()
IL_000b: stloc.0
IL_000c: br.s IL_000e
IL_000e: ldloc.0
IL_000f: ret
} // end of method clsTest::InLineIfTest2

Ganador: Definitivamente el operador ?? es el ganador, por 1 byte!!

Ahora claro esta comparacion esta basada en la comprobacion de si un objeto esta vacio (es decir tiene una referencia a null) y que devolver, no siempre es practico el operador ??, por ejemplo en objetos que tienen solo valores (tipos primitivos como int, double, etc...) no es aplicable, a menos claro que uses nullable types, y en otros casos en los que tienes que ejecutar varias operaciones definitivamente el tradicional if sera el llamado a ejecutar las operaciones!!!

Espero que esto les ayude en sus decisiones sobre como escribir codigo, a veces 1 milisegundo menos de ejecucion ayuda a todo el perfomance de la aplicacion!!!

0 comments: