Estamos acostumbrados a usar variables estáticas para valores “constantes”, que no cambiarán de valor independientemente del estado de la aplicación. El ejemplo más típico es el valor de PI. Lo cierto es que suena tan sencillo que rara vez nos paramos a pensar si estamos usando las variables estáticas donde debemos o no. Sin embargo, esto puede traer bastantes quebraderos de cabeza si estamos creando código que será usado por otros…
Supongamos que hemos desarrollado una librería que se encarga de gestionar conexiones para algún servicio (IncredibleService) que tiene un número máximo de llamadas a la API por hora, 150. Dado que ese límite es constante y no cambiará independientemente del estado de la aplicación, podríamos escribir algo así:
Esa librería podría ser usada por un programa como este:
using System;
public class IncredibleService
{
public const int MaxApiCalls = 150;
// Here we'd have the rest of the implementation
}
Esa librería podría ser usada por un programa como este:
using System;
public class Program
{
public static void Main()
{
Console.WriteLine("Maximum number of calls to the API: " + IncredibleService.MaxApiCalls);
}
}
Si compilamos la librería, compilamos el programa y lo ejecutamos, nos mostraría por pantalla el texto “Maximum number of calls to the API: 150”, que es precisamente lo que debería pasar, así que hasta aquí, todo bien.
Pablos-MacBook-Pro:csharp carballude$ dmcs -target:library IncredibleService.cs Pablos-MacBook-Pro:csharp carballude$ dmcs -reference:IncredibleService.dll Program.cs Pablos-MacBook-Pro:csharp carballude$ mono Program.exe Maximum number of calls to the API: 150
Supongamos que tres meses más tarde, el numero de usuarios del servicio crece y la empresa decide realizar una inversión y mejorar la experiencia de los usuarios permitiendo el doble de consultas a la API por hora, es decir, 300. Nosotros, como desarrolladores de la librería IncredibleService deberíamos cambiar el valor 150 por 300, compilar la librería y distribuirla a nuestros clientes:
using System;
public class IncredibleService
{
public const int MaxApiCalls = 300;
// Here we'd have the rest of the implementation
}
La mayoría de nosotros esperaríamos que una vez que Program.exe haya recibido la nueva dll, mostraría por pantalla el valor 300… sin embargo:
Pablos-MacBook-Pro:csharp carballude$ dmcs -target:library IncredibleService.cs Pablos-MacBook-Pro:csharp carballude$ mono Program.exe Maximum number of calls to the API: 150
¿Cómo es posible que IncredibleService.dll tenga el valor 300 para MaxApiCalls, Program.exe llame a IncredibleService.MaxApiCalls y este siga mostrando el valor 150? Yo también me quedé con un palmo la primera vez que lo vi xD Examinemos lo que ha generado el compilador:
Pablos-MacBook-Pro:csharp carballude$ mono disassembler.exe --disassemble-all --methods-matching Main Program.exe DotNet disassembler v1.0 - Pablo Carballude Program Public Void Main() -- Local variables -- End of local variables IL_0: ldstr IL_1: break IL_2: nop IL_3: nop IL_4: cpobj IL_5: ldc.i4 IL_6: ldelem.i8 IL_7: nop IL_8: nop IL_9: nop IL_10: box IL_11: ldarg.0 IL_12: nop IL_13: nop IL_14: break IL_15: call System.String::Concat IL_20: call System.Console::WriteLine IL_25: ret
Si observamos el código, veremos que el compilador ha generado “ldc.i4” en el IL_5, es decir, está guardando el valor directamente en nuestro código y no mirando la librería. ¿Por qué? Fácil, el compilador se ha dado cuenta de que estamos llamando a IncredibleService para leer una constante, dado que esa constante no va a cambiar de valor (porque para eso es constante) en vez de cargar la dll en memoria y hacer la llamada, ahorra memoria y tiempo incrustando el valor en nuestra código directamente. El problema es que si actualizamos el valor de la constante en la dll, el programa no recibirá el nuevo valor hasta que la recompilemos contra la nueva versión ¡porque la librería ni siquiera se está cargando en memoria!
Arreglando el entuerto
Cuando tengamos que fijar un valor que va a ser constante respecto del estado de la aplicación, pero susceptible de ser modificado (como el caso del ejemplo) es aconsejable hacer uso de variables “readonly”. El código quedaría así:
using System;
public class IncredibleService
{
public static readonly int MaxApiCalls = 150;
// Here we'd have the rest of the implementation
}
Ahora la variable no es “const” sino “static readonly”, pero esto no produce ningún cambio sintáctico en los clientes, así que podemos compilar Program sin hacerle ningún cambio:
Pablos-MacBook-Pro:csharp carballude$ dmcs -target:library IncredibleService.cs Pablos-MacBook-Pro:csharp carballude$ dmcs -reference:IncredibleService.dll Program.cs Pablos-MacBook-Pro:csharp carballude$ mono Program.exe Maximum number of calls to the API: 150
Si ahora actualizamos el código de IncredibleService.dll para que tenga el valor 300 y compilamos, Program sí mostrará el resultado esperado:
Pablos-MacBook-Pro:csharp carballude$ dmcs -target:library IncredibleService.cs Pablos-MacBook-Pro:csharp carballude$ mono Program.exe Maximum number of calls to the API: 300
Podemos comprobar además que ahora el código generado por el compilador sí llama a nuestra dll:
Pablos-MacBook-Pro:csharp carballude$ mono disassembler.exe --disassemble-all --methods-matching Main Program.exe DotNet disassembler v1.0 - Pablo Carballude Program Public Void Main() -- Local variables -- End of local variables IL_0: ldstr IL_1: break IL_2: nop IL_3: nop IL_4: cpobj IL_5: ldsfld IL_6: ldarg.0 IL_7: nop IL_8: nop IL_9: stloc.0 IL_10: box IL_11: ldarg.1 IL_12: nop IL_13: nop IL_14: break IL_15: call System.String::Concat IL_20: call System.Console::WriteLine IL_25: ret
Ahora el compilador sí ha generado código para mirar el campo estático «ldsfld» y no está incrustándolo en nuestra aplicación :)
s/500/300/
s/ahora/ahorra/
Gracias Pablo, ya está corregido :)
No conocía el modificador «readonly» :-)
Ya que estás, me podrías decir cual es la diferencia entre una variable read-only y una constante? Me cederás que a nivel conceptual, una variable que solo puede leerse es… una constante :P
Mafias, te he respondido con otro post :) C#: Readonly vs Const
Amigo
Tengo un servicio de tipo Windows Aplication
quisiera saber como puedo hacer para obtener el numero de usuarios que
estan conectados en un determinado tiempo.
Por favor ayudame. Gracias
POr Favor
Much of state Security comes from the lack need. Health of the populace cbeoinmd with opportunity and hope create an easily governable nation. If It is more fruitful to work within the system to build a future then laws will be followed.“Poverty in all its forms is the greatest single threat to peace, security, democracy, human rights and the environment.”-Mike Moore, former Director-General World Trade Organisation (WTO) We therefore have to…fight poverty not only for moral and humanitarian reasons, but also as an integral part of the fight against terrorism.”-Jan Kavan, former President of the General Assembly of the United Nations
Kedves Hajnalka!Igen, folyamatos bÅ‘vül a kutatásokat megrendelÅ‘ cégek száma is. Egyre többféle termékre lehet beváltani a vásárlási utalványokat is. ÉS rohamosan növekszik az EU-ban élÅ‘ felhasználók száma is. Valóban különleges és sokrétű lehetÅ‘ség a ProDm Szövetség által kÃnált szortiment. Sok sikert kÃvánunk önnek is!ProDm Admin Hungary
Completely agree. It seems they are addicted to dramatising politics. Making soap opera. As soon as the PM gets a boost in the polls, Marius Benson will whip out a story about Kevin Rudd coming back to invent some leadership challenge. Malcolm Turnbull’s ridiculous lies creating FUD about the NBN are never reported in the MSM, but get a big run on the 5th estate. A news limited journalist on “Insiders” practically admitted that the Margie Abbott coverage was a coordinated campaign with News. If the MSM journalists can’t present information fairly, then what are they for?
zegt:ze zijn leuk, maarre even van een babyleek, hoelang kan je zwanger zijn dan? dacht dat het met 9.1/2 maand toch wel klaar zou zijn! heb echt geen idee,hoe dat werkt, wanneer gaan ze het anders halen dan?Hoop voor je dat je morgen een verse mama mag zijn:-)groetjes