aelena.com

13 January 2009

¿Se puede cambiar el valor de una struct readonly?

Filed under: .NET, c# — admin @ 9:25

Si te enseñan el siguiente código, ¿cuál crees que es el resultado?

   1:  struct MutableStruct
   2:  {
   3:      private int x;
   4:      public int Mutate ( )
   5:      {
   6:          return ++x;
   7:      }
   8:  }
   9:  
  10:  class Program
  11:  {
  12:  public readonly MutableStruct _ms = new MutableStruct ();
  13:  static void Main ( string [] args )
  14:  {
  15:  Program _p = new Program ();
  16:  Console.WriteLine ( “Valor de la copia: {0} “,
  17:  _p._ms.Mutate ());
  18:  Console.WriteLine ( “Valor de la copia: {0} “,
  19:  _p._ms.Mutate () );
  20:  Console.WriteLine ( “Valor de la copia: {0} “,
  21:  _p._ms.Mutate ( ));
  22:  Console.ReadLine ();
  23:  }
  24:  }

El resultado puede sorprendernos a muchos. En realidad, no es 0, 0, 0 ni 1, 2, 3 sino 1,1,1. ¿Porqué? ¿cómo es eso? La cosa reside en la propia especificación del lenguaje C#. Recordemos que las struct son tipos de valor (value types), no referencias, es decir, son como un int y no como un objeto, como por ejemplo string. Por tanto, su valor no puede cambiar. Lo que ocurre es que al acceder a la struct en el código, obtenemos una copia de dicho valor, que no una referencia como ocurriría si accedieramos a un objeto, a una instancia de la clase “Producto”, por ejemplo, en nuestra aplicación. Es decir, que al hacer _p.ms estamos obteniendo una copia, y esa copia si es mutable, mientras que _m no lo es. Si modificamos el código ahora para comparar el valor original y la copia lo veremos más claro:

struct MutableStruct
{
private int x;
public int Mutate ( )
{
return ++x;
}
public override string ToString ( )
{
return String.Format ( “Valor de x: {0}”, x );
}

}

class Program
{
public readonly MutableStruct _ms = new MutableStruct ();
static void Main ( string [] args )
{
Program _p = new Program ();
Console.WriteLine ( “Valor de la copia: {0},{1}”,
_p._ms.Mutate (), _p._ms.ToString () );
Console.WriteLine ( “Valor de la copia: {0},{1}”,
_p._ms.Mutate (), _p._ms.ToString () );
Console.WriteLine ( “Valor de la copia: {0},{1}”,
_p._ms.Mutate ( ), _p._ms.ToString () );
Console.ReadLine ();
}
}

Al ejecutar veremos la siguiente salida por pantalla:

Valor de la copia: 1, Valor de x: 0
Valor de la copia: 1, Valor de x: 0
Valor de la copia: 1, Valor de x: 0

Esto nos permite ver que realmente lo único que cambia es el valor de la x interna de _p._ms, pero no cambia la variable asociada a ese campo, que sería la x privada que vemos en la definición de la struct.
Interesante ¿verdad?

Disclaimer: esto no se me ha ocurrido a mi, sino a Eric Lippert, pero me ha parecido muy interesante reproducirlo para trastear.

¿Y si le quitamos el readOnly?

Perdonad el formato, el editor es una puta mierda.

Saludos.

9 July 2008

Nested Dictionaries en C#

Filed under: c# — admin @ 9:12

Aunque no con una sintaxis tan tersa como en Python, la forma de declarar diccionarios anidados en C# sería la siguiente:

  1. SortedDictionary<string, SortedDictionary<string, double>> _bandsAndAlbums3 =
  2. new SortedDictionary<string, SortedDictionary<string, double>>()
  3. {
  4.   {“Paradise Lost”, new SortedDictionary<string, double>()
  5.      {
  6.       {“Host”, 8.9},  {“Icon”, 9.9}, {“Draconian Times”, 9.9}, {“One Second”, 8.2}
  7.     }
  8.   },
  9.   {“Megadeth”, new SortedDictionary<string, double>()
  10.      {
  11.        {“Youthanasia”, 8.2},  {“Rest In Peace”, 10},
  12.        {“Cryptic Writings”, 9.4}, {“The System has Failed”, 9.5}
  13.      }
  14.   },
  15.   {“Judas Priest”, new SortedDictionary<string, double>()
  16.     {
  17.        {“Ram It Down”, 8.5},  {“Painkiller”, 9.5},
  18.        {“Point of Entry”, 7.5}, {“Sin After Sin”, 6.5}
  19.     }
  20.   }
  21. };

15 January 2007

La forma más simple de ejecutar una macro desde c#

Filed under: Office, c#, excel, macros — admin @ 12:09

Supongamos que queremos ejecutar una macro en excel desde c#. La forma más sencilla que veo yo es a través de Reflection. Veamos un ejemplo:

ApplicationClass excelApp = new ApplicationClass();
Workbook w = excelApp.Workbooks.Open("miExcel.xls",Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing );

RunMacro(w.Application, new object [] {"Nombre_Macro"});

Con este código hemos abierto un archivo de excel y hemos llamado a una función que nos va a ejecutar la macro.

Veamos ahora esa función:

private static void RunMacro(object oApp, object[] oRunArgs)
{
oApp.GetType().InvokeMember("Run",
System.Reflection.BindingFlags.Default |
System.Reflection.BindingFlags.InvokeMethod,
null, oApp, oRunArgs);
}

Así de sencillo. Saludos.