static void Main(string[] args) { EncabezadoYPieConsola Escritor = new EncabezadoYPieConsola(); #region Ejemplo 5.1 //Ejemplo de Swap usando una generic function llamada Swap //ver la dfinición más abajo Escritor.EscribirEncabezado("Ejamplo 5.1: Swap usando generics"); int x = 2; int y = 3; System.Console.WriteLine("Inicialmente x es: {0}, e y es {1}", x.ToString(), y.ToString()); //Esta función se puede llamar como se llama debajo o así: Swap<int>(ref x, ref y); Swap(ref x, ref y); System.Console.WriteLine("Ahora x es: {0}, e y es {1}", x.ToString(), y.ToString()); Escritor.EscribirPie("Fin de Ejemplo 5.1"); #endregion //Ejemplo de uso de la función genérica var accounts = new List <Account>() { new Account("Moe", 11.40M), new Account("Curly", 20.50M), new Account("Larry", 50.15M) }; decimal sum = Algorithms.SimpleAccumulate(accounts); System.Console.WriteLine("Total: {0}", sum.ToString()); int uno = 1; int? algo = uno; bool tieneValor = algo.HasValue; }
static void Main(string[] args) { EncabezadoYPieConsola separador = new EncabezadoYPieConsola(); //Ejemplo 1: Dos maneras de iterar en un array #region Ejemplo 1 separador.EscribirEncabezado("Ejemplo 1: Dos maneras de iterar en un array"); int[] myArray = { 0, 1, 2, 3 }; for (int i = 0; i < myArray.Length; i++) { Console.WriteLine(myArray[i].ToString()); } foreach (var item in myArray) { Console.WriteLine(item.ToString()); } separador.EscribirPie("Fin Ejemplo 1"); #endregion //Ejemplo 2: Maneras de reservar espacio en memoria para un array de User-Defined Types (UDTs) #region Ejemplo 2 separador.EscribirEncabezado("Ejemplo 2: Array de UDTs"); Person[] myPersons = new Person[2]; //Si intento acceder a los elmentos del array antes de incializarlos tengo un error //El ciclo forach ejecutado aqui antes de inicializar los elementos me daría NullReferenceException myPersons[0] = new Person { FirstName = "Albert", LastName = "Einstein" }; myPersons[1] = new Person { FirstName = "Erwin", LastName = "Schrödinger" }; foreach (Person item in myPersons) { Console.WriteLine(item.ToString()); } Person[] newPersons = { new Person { FirstName = "Albert", LastName = "Einstein" }, new Person { FirstName = "Erwin", LastName = "Schrödinger" } }; foreach (Person item in newPersons) { Console.WriteLine(item.ToString()); } separador.EscribirPie("Fin de ejemplo 2"); #endregion //Ejemplo 3: Arrays multidimensionales rectangulares (todas las filas tienen la misma cantidad de columnas) #region Ejemplo 3 separador.EscribirEncabezado("Ejemplo 3: Arrays multidimensionales recatngulares"); int[,] twoDim = new int[, ] { { 0, 1 }, { 2, 3 } }; for (int row = 0; row < twoDim.Length / 2; row++) { for (int col = 0; col < twoDim.Length / 2; col++) { Console.WriteLine(twoDim[row, col].ToString()); } } //Tambien se podría escribir //int[,,] threeDim; //int[,,,] fourDim; //Pero en estos casos es mejor usar CreateInstance separador.EscribirPie("Fin Ejemplo 3"); #endregion //Ejemplo 4: Jagged Arrays (arrays donde cada fila puede tener un número de columnas diferente) #region Ejemplo 4 separador.EscribirEncabezado("Ejemplo 4: Jagged Arrays"); int[][] jagged = new int[3][]; jagged[0] = new int[2] { 0, 1 }; jagged[1] = new int[3] { 2, 3, 4 }; jagged[2] = new int[2] { 5, 6 }; for (int row = 0; row < jagged.Length; row++) { for (int col = 0; col < jagged[row].Length; col++) { Console.Write(jagged[row][col].ToString() + " "); if (col == jagged[row].Length - 1) { Console.Write("\n"); } } } separador.EscribirPie("Fin Ejemplo 4"); #endregion //Ejemplo 5: Sort simple. Los tipos primitivos proveen un método CompareTo y llamando al método Sort se ordenan #region Ejemplo 5 separador.EscribirEncabezado("Ejemplo 5: Sort simple usando CompareTo de Tipos Primitivos"); string[] cantantes = new string[] { "Glen Hughes", "Joe Linterna", "Jon Anderson", "Ian Gillan" }; Array.Sort(cantantes); foreach (var cantante in cantantes) { Console.WriteLine(cantante); } separador.EscribirPie("Fin de Ejemplo 5"); #endregion //Ejemplo 6: En un array de objetos tengo que hacer que el tipo definido x el usuario //implemente ISortable y provea una implementación de CompareTo (ver la definición de SortablePerson #region Ejemplo 6 separador.EscribirEncabezado("Ejemplo 6: Ordenamiento usando método CompareTo del UDT"); SortablePerson[] SortablePersons = new SortablePerson[] { new SortablePerson { FirstName = "Jon", LastName = "Anderson" }, new SortablePerson { FirstName = "Jon", LastName = "Bon Jovi" }, new SortablePerson { FirstName = "Ian", LastName = "Anderson" }, new SortablePerson { FirstName = "Ian", LastName = "Gillan" } }; Array.Sort(SortablePersons); foreach (var sortablePerson in SortablePersons) { Console.WriteLine(sortablePerson.ToString()); } separador.EscribirPie("Fin de Ejemplo 6"); #endregion //Ejemplo 7: Inicializo un array usando CreateInstance. Ver que todo el código referido al array usa Object //tanto para setear el tipo de elemento, como para recuperarlo. Es decir, el código del array es independiente //del tipo que guardo en el array. GetValue devuelve un Object. CreateInstance tiene varias sobrecargas //para crear arrays multidimensionales y crear arrays que no son zero-based #region Ejemplo 7 separador.EscribirEncabezado("Ejemplo 7: Uso de CreateInstance"); object myObject; int myInt = 5; myObject = myInt; Array thisArray = Array.CreateInstance(myObject.GetType(), 5); //Si supiera el tipo pondría por ejemplo typeof(int), pero la idea aquí es que desconozco el tipo, por eso uso el GetType object valor; int entero = 12; valor = entero; thisArray.SetValue(valor, 0); //Uso de SetValue para fijar el valor. De nuevo uso un Object para recibir el valor entero = 69; valor = entero; thisArray.SetValue(valor, 1); for (int i = 0; i < thisArray.Length; i++) { valor = thisArray.GetValue(i); Console.WriteLine("Este es el valor: {0}", valor.ToString()); //No inicialicé los valores, pero como esta boxed, esto no me da error } separador.EscribirPie("Fin de Ejemplo 7"); #endregion //Ejemplo 7b: Casteo el Array obtenido con CreateInstance a un array de enteros. A ver: #region Ejemplo 7b separador.EscribirEncabezado("Ejemplo 7b: Casteo del objeto Array"); int[] arrayDeEnteros = (int[])thisArray; //A pesar de tener objetos sin inicializar, se castean al valor default del int que es cero for (int i = 0; i < arrayDeEnteros.Length; i++) { Console.WriteLine("Después de castearlo, valor: {0}", arrayDeEnteros[i].ToString()); } separador.EscribirPie("Fin de Ejemplo 7b)"); #endregion //Ejemplo 8: Arrays multidimensionales con CreateInstance //Primero creo un array unidimensional que especifica el número de elementos en cada coordenada. Lo llamo coordenadas //Es un objeto Array, creado con CreateInstance y esto es diferente a un int[]. Cuando lo pase como argumento //en la segunda llamada a CreateInstance, lo tenga que castear a int[]. Es un poco excesivo de mi parte. Este array que //representa las coordenadas se puede crear de tipo int directamente #region Ejemplo 8 separador.EscribirEncabezado("Ejemplo 8: Arrays multidimensionales con CreateInstance"); Array coordenadas = Array.CreateInstance(typeof(int), 2); //Creación del array de coordenadas coordenadas.SetValue(1, 0); //Valor del primer elemento: el array que voy a crear tendrá 1 fila coordenadas.SetValue(2, 1); //Valor del segundo elemento: el array que voy a crear tendrá 2 columnas Array otroArrayMas = Array.CreateInstance(myObject.GetType(), (int[])coordenadas); //usé myObject creado en el ejemplo 7 //A partir de acá puedo fijar y obtener valores como antes otroArrayMas.SetValue(11, new int[] { 0, 0 }); //Fijo el valor del primer elemento //Fijate que uso un array para indicar las coordenadas otroArrayMas.SetValue(12, new int[] { 0, 1 }); Console.WriteLine("Valores de otroArrayMas: {0}", otroArrayMas.GetValue(new int[] { 0, 0 })); Console.WriteLine("Valores de otroArrayMas: {0}", otroArrayMas.GetValue(new int[] { 0, 1 })); separador.EscribirPie("Fin Ejemplo 8"); #endregion //Ejemplo 8b: Arrays Multidimensionales usando CreateInstance //Un ejemplo con un poco más de detalle #region Ejemplo 8.b) separador.EscribirEncabezado("Ejemplo 8b: CreateInstance, más detalles"); //Array de Coordenadas (2 x 3) Array miArrayDeInts = Array.CreateInstance(typeof(int), new int[3] { 2, 2, 2 }); Random miRandom = new Random(DateTime.Now.Millisecond); int randomInt; for (int x = 0; x < 2; x++) { for (int y = 0; y < 2; y++) { for (int z = 0; z < 2; z++) { randomInt = miRandom.Next(9); miArrayDeInts.SetValue(randomInt, x, y, z); } } } for (int x = 0; x < 2; x++) { for (int y = 0; y < 2; y++) { for (int z = 0; z < 2; z++) { Console.WriteLine("Valor en: {0},{1},{2}: {3}", x.ToString(), y.ToString(), z.ToString(), miArrayDeInts.GetValue(x, y, z).ToString()); } } } separador.EscribirPie("Fin Ejemplo 8.b"); #endregion //Ejemplo 8.c) Crear un array que no es zero-based #region Ejemplo 8.c) separador.EscribirEncabezado("Ejemplo 8.c) Crear un array que no es zero-based"); //Primero creamos un array para fijar las coordenadas //Este array va a tener 5 dimensiones int[] coordenadasArray = new int[5] { 1, 2, 3, 4, 5 }; //Ahora creamos un array para el límite inferior de cada coordenada //Las coordenadas impares tienen un límite inferior de uno (1), las pares de cero (0) int[] limitesInferiores = new int[5] { 1, 0, 1, 0, 1 }; //Ahora creo un array Array arrayEspecial = Array.CreateInstance(typeof(int), coordenadasArray, limitesInferiores); //Por ultimo puedo fijar los valores arrayEspecial.SetValue(5, new int[] { 1, 0, 1, 0, 1 }); arrayEspecial.SetValue(6, new int[] { 1, 1, 1, 0, 1 }); Console.WriteLine("El valor 10101 es: {0}", arrayEspecial.GetValue(new int[] { 1, 0, 1, 0, 1 })); Console.WriteLine("El valor 11101 es: {0}", arrayEspecial.GetValue(new int[] { 1, 1, 1, 0, 1 })); separador.EscribirPie("Fin Ejemplo 8.c)"); #endregion //Ejemplo 9: Usando el array SortablePersons del ejemplo 6, creo una copia usando Clone, y otra usando Copy //Ojo que al crear el Clone hay que hacer un casting porque de lo contrario se crean de tipo Object[] //Luego hago lo mismo, pero usando Copy. Con respecto a Copy recordar que es un método estático #region Ejemplo 9 separador.EscribirEncabezado("Ejemplo 9: Shallow Copy de Arrays"); SortablePerson[] sortablePersonsClone = (SortablePerson[])SortablePersons.Clone(); foreach (var unaPersona in sortablePersonsClone) { Console.WriteLine("Nombre del Clon: {0}", unaPersona.FirstName + " " + unaPersona.LastName); } SortablePerson[] sortablePersonsCopy = new SortablePerson[4]; Array.Copy(SortablePersons, sortablePersonsCopy, 4); foreach (var unaPersona in sortablePersonsCopy) { Console.WriteLine("Nombre de la Copia: {0}", unaPersona.FirstName + " " + unaPersona.LastName); } separador.EscribirPie("Fin de Ejemplo 9"); #endregion //Ejemplo 10: La característica de Covarianza de los Arrays puede llevar a un error en runtime //del cual el compilador no se percata //La última línea de este ejemplo da un Type Mismatch #region Ejemplo 10 object[] objectArray; SortablePerson[] PersonArrayTest = new SortablePerson[3]; objectArray = PersonArrayTest; objectArray[0] = new SortablePerson(); //La siguiente línea daría un error //objectArray[1] = "Una string de prueba"; #endregion //Ejemplo 11: Segmentos de Arrays. En este caso creo un segmento pasando dos segmentos //uno de cada array de enteros creado al principio //Es decir, el segmento está creado por la unión de dos segmentos //Esto me muestra el constructor que supongo es más habitual usar: //new ArraySegment<int>(arrayOriginal, offset, count) //En este ejemplo, se crea un array de segmentos de array //new ArraySegment<int>[]{new Arraysegment<int>(enterosPares, 1, 2), //new Arraysegment<int>(enterosImpares, 1, 2)} #region Ejemplo 11 separador.EscribirEncabezado("Ejemplo 11: Segmentos de Arrays"); int[] enterosImpares = { 1, 3, 5, 7, 9 }; int[] enterosPares = { 0, 2, 4, 6, 8 }; var segmentoDeEnteros = new ArraySegment <int>[] { new ArraySegment <int> (enterosImpares, 1, 2), new ArraySegment <int>(enterosPares, 1, 2) }; Console.WriteLine("La manera siguiente de enumerar los elementos del segmento de array no funciona"); for (int i = 0; i < segmentoDeEnteros.Length; i++) { Console.WriteLine("Valor de Elemento {0}: {1}", i.ToString(), segmentoDeEnteros[i].ToString()); } Console.WriteLine("Esta es la correcta:"); int segmentOffset; int segmentCount; segmentOffset = segmentoDeEnteros[0].Offset; segmentCount = segmentoDeEnteros[0].Count; for (int i = segmentOffset; i < segmentOffset + segmentCount; i++) { Console.WriteLine("Este es el valor del elemento {0} del primer segmento: {1}", i.ToString(), segmentoDeEnteros[0].Array[i].ToString()); } segmentOffset = segmentoDeEnteros[1].Offset; segmentCount = segmentoDeEnteros[1].Count; for (int i = segmentOffset; i < segmentOffset + segmentCount; i++) { Console.WriteLine("Este es el valor del elemento {0} del segundo segmento: {1}", i.ToString(), segmentoDeEnteros[1].Array[i].ToString()); } separador.EscribirPie("Fin Ejemplo 11"); #endregion //Ejemplo 12: Comparaciones //Para comparar dos arrays lo mejor es usar IStructuralEquatable //que me permite comparar dos arrays en secuencia. Es decir, la secuencia de elementos en el array tiene //que ser la misma. Si están desordenados, aunque los valores sean iguales, la comparación indica que son distintos //Con las tuplas puedo usar Equals también, lo cual con arrays no funciona porque compara por referencia //De todos modos, usar siempre IStructuralEquatable #region Ejemplo 12 separador.EscribirEncabezado("Ejemplo 12: Comparaciones de Arrays"); int[] enterosComparacion = { 1, 3, 5, 7, 9 }; int[] enterosComparacionInvertida = { 9, 7, 5, 3, 1 }; Console.WriteLine("Comparación usando: StructuralComparisons.StructuralEqualityComparer.Equals(arg1, arg2)"); Console.WriteLine("Comparación entre enterosImpares y enterosComparacion: {0}", StructuralComparisons.StructuralEqualityComparer.Equals(enterosImpares, enterosComparacion)); Console.WriteLine("Comparación entre enterosPares y enterosComparacion: {0}", StructuralComparisons.StructuralEqualityComparer.Equals(enterosPares, enterosComparacion)); Console.WriteLine("Comparación entre enterosPares y enterosComparacionInvertida: {0}", StructuralComparisons.StructuralEqualityComparer.Equals(enterosPares, enterosComparacionInvertida)); //Otro modo de comparar los arays de enteros Console.WriteLine("Otro modo de comparar: enterosImpares as IStructuralEquatable).Equals(enterosComparacion, EqualityComparer<int>.Default"); if ((enterosImpares as IStructuralEquatable).Equals(enterosComparacion, EqualityComparer <int> .Default)) { Console.WriteLine("Siguen siendo iguales: enterosImpares y EnterosComparacion"); } else { Console.WriteLine("enterosImpares y EneterosComparacion no son iguales!?"); } //Ahora hago un sort de los arrays enterosImpares y enterosComparacionInvertida para que me den iguales //Si no quiero alterar los arrays, debería implementar un método que los clone a ambos y que los ordene //y comparo los elementos clonados Array.Sort <int>(enterosComparacion); Array.Sort <int>(enterosComparacionInvertida); Console.WriteLine("Comparación entre enterosImpares y enterosComparacionInvertida luego de hacer un Sort: {0}", StructuralComparisons.StructuralEqualityComparer.Equals(enterosImpares, enterosComparacionInvertida)); //Comparación de Tuplas var t1 = Tuple.Create <int, string>(1, "tonto"); var t2 = Tuple.Create <int, string>(1, "tonto"); var t3 = Tuple.Create <string, int>("tonto", 1); Console.WriteLine("Comparación entre t1 y t2: {0}", StructuralComparisons.StructuralEqualityComparer.Equals(t1, t2)); Console.WriteLine("Comparación entre t1 y t3: {0}", StructuralComparisons.StructuralEqualityComparer.Equals(t1, t3)); //Comparación de Referencias. Esto da True int unEntero = 5; object unObjeto = unEntero; object otroObjeto = unEntero; Console.WriteLine(unObjeto.Equals(otroObjeto)); separador.EscribirPie("Fin Ejemplo 12"); #endregion //Ejemplo 13: Enumeración y Enumeración inversa //La manera sencilla de enumerar Arrays es con foreach //foreach no permite enumerar en forma inversa, para eso tengo que crear mi propia clase #region Ejemplo 13 separador.EscribirEncabezado("Ejemplo 13; Enumeraciones"); //Primero definimos un array con números random del 0 al 100 int[] arrayAleatorio = new int[25]; Random asignador = new Random(DateTime.Now.Millisecond); for (int i = 0; i < arrayAleatorio.Length; i++) { arrayAleatorio[i] = asignador.Next(100); } //Ahora enumeramos //Primero en forma directa Console.WriteLine("Enumeración directa"); foreach (var enteroAleatorio in arrayAleatorio) { Console.WriteLine(enteroAleatorio.ToString()); } separador.EscribirPie("Fin Ejemplo 13"); #endregion //Ejemplo 14: Enumeradores personalizados //Se muestra el uso de Yield y la definición de enumeradores personalizados #region Ejemplo 14 separador.EscribirEncabezado("Ejemplo 14: Enumeradores personalizados"); SerieDeEnteros miSerie = new SerieDeEnteros(50, 10); Console.WriteLine("Enumeración Directa:"); string linea = ""; foreach (var miEntero in miSerie) { linea += miEntero.ToString() + ", "; } Console.WriteLine(linea); Console.WriteLine("Enumeración inversa:"); linea = ""; foreach (var miEntero in miSerie.EnumeracionReversa()) { linea += miEntero.ToString() + ", "; } Console.WriteLine(linea); Console.WriteLine("Enumerar Pares"); linea = ""; foreach (var miEnteroPar in miSerie.EnumerarPares()) { linea += miEnteroPar.ToString() + ", "; } Console.WriteLine(linea); separador.EscribirPie("Fin de Ejemplo 14"); #endregion //Ejemplo 15: Comparo dos arrays de UDTs usando la clase PersonasComparables //que está mal nombrada, debería haber sido en singlular #region Ejemplo 15 separador.EscribirEncabezado("Ejemplo 15: Comparación estructural de Arrays de UDTs"); Console.WriteLine("Comparamos dos arrays de UDTs estructuralmente"); var jlb = new PersonasComparables { Apellido = "Borges", Nombre = "Jorge Luis" }; PersonasComparables[] unasPersonas = { new PersonasComparables { Apellido = "Asimov", Nombre = "Isaac" }, jlb }; PersonasComparables[] otrasPersonas = { jlb, new PersonasComparables { Nombre = "Isaac",Apellido = "Asimov" } }; Console.WriteLine("Primero comparo con un simple '=='. Esto compara referencias, debe dar distinto"); if (unasPersonas == otrasPersonas) { Console.WriteLine("Las referencias son iguales! (WTF)"); } else { Console.WriteLine("Las referencias son distintas, como cabía esperar"); } Console.WriteLine("Ahora usamos una comparación con el código de Stack Overflow"); Console.WriteLine("Recorda que va using System.Cllections"); bool sonIguales = StructuralComparisons.StructuralEqualityComparer.Equals(unasPersonas, otrasPersonas); Console.WriteLine("Son iguales? Respuesta: {0}", sonIguales.ToString()); //Recordemos que hay que ordenarlos para compararlos Array.Sort <PersonasComparables>(unasPersonas); Array.Sort <PersonasComparables>(otrasPersonas); sonIguales = StructuralComparisons.StructuralEqualityComparer.Equals(unasPersonas, otrasPersonas); Console.WriteLine("Comparación luego de ordenar. Son iguales? Respuesta: {0}", sonIguales.ToString()); //Ahora usamos la comparación del libro sonIguales = false; sonIguales = (unasPersonas as IStructuralEquatable).Equals(otrasPersonas as IStructuralEquatable, EqualityComparer <PersonasComparables> .Default); Console.WriteLine("Comparación según el libro. Son iguales? Respuesta: {0}", sonIguales.ToString()); Console.WriteLine("Este es el primero: {0}", unasPersonas[0].ToString()); Console.WriteLine("Este es el segundo: {0}", unasPersonas[1].ToString()); separador.EscribirPie("Fin Ejemplo 15"); #endregion }
static void Main(string[] args) { EncabezadoYPieConsola Separador = new EncabezadoYPieConsola(); //Ejemplo 1: Diferencia entre prefix y postfix //Con el prefijo, primero se suma 1 a x y luefo se evalúa el if //con el sufijo primero se evalúa el if y luego se suma 1 a x #region Ejemplo 1 Separador.EscribirEncabezado("Ejemplo 1: Operador prefix y postfix"); int x = 5; if (++x == 6) { Console.WriteLine("x es igual a 6 con el prefix"); } if (x++ == 7) { Console.WriteLine("x es igual a 7 con el postfix"); } else { Console.WriteLine("El operador postfix no incrementó el valor!"); } Separador.EscribirPie("Fin Ejemplo 1"); #endregion //Ejemplo 2: Overflow y como prevenirlo con checked #region Ejemplo 2 Separador.EscribirEncabezado("Ejemplo 2: Overflow y prevención"); //Aquí unByte hace overflow y termina valiendo cero byte unByte = 255; Console.WriteLine("Antes del operador, el Byte vale: {0}", unByte.ToString()); unByte++; Console.WriteLine("Ahora el byte vale {0}", unByte.ToString()); //Aquí otroByte sigue valiendo 255 //Ver la técnica de encerrar el bloque checked dentro de un try //Esto permite atrapar el error eventual que purde producirse al realizar la //operación byte otroByte = 255; try { checked { otroByte++; } } catch (Exception e) { Console.WriteLine("Ocurrió la siguiente excepción: {0}", e.Message); } Console.WriteLine("El valor de otroByte es: {0}", otroByte.ToString()); Separador.EscribirPie("Fin Ejemplo 2"); #endregion //Ejemplo 3: Conversión explícita usando "as" //Ojo sólo se usa para Reference Types #region Ejemplo 3 Separador.EscribirEncabezado("Ejemplo 3: Conversión explícita usando 'as'"); object miEntero = "5"; object str = 12; Console.WriteLine("Conversión de object a string: {0}", (miEntero as string) + " es ahora una string"); if (str as int? != null) { Console.WriteLine("La conversión de object a 'int?' me anuló la variable"); } else { Console.WriteLine("Conversión de object a int: {0}", ((str as int?) + 5).ToString()); } Separador.EscribirPie("Fin ejemplo 3"); #endregion //Ejemplo 4: Pérdida de precisión al convertir de long a float #region Ejemplo 4 Separador.EscribirEncabezado("Ejemplo 4: Pérdida de precisión en conversiones"); long enteroLargo = 922337293685477580; Console.WriteLine("EnteroLargo vale: {0}", enteroLargo.ToString()); float flotante = enteroLargo; Console.WriteLine("Flotante vale: {0}", flotante.ToString()); Console.WriteLine("Prestar atención al redondeo que hizo: 922337293685477580 pasó a ser: 92233730000000000"); Separador.EscribirPie("Fin Ejemplo 4"); #endregion //Ejemplo 5: Parseo de strings usando el método Parse. //Notar que Parse es un método estático de los tipos a los cuales //quiero convertir la string. En el ejemplo, de bool y de int #region Ejemplo 5 Separador.EscribirEncabezado("Ejemplo 5: Parseo de Strings usando el método Parse de los tipos primitivos"); string strBooleano = "true"; string strEntero = "16"; //Probemos conversiones explícitas por medio de parse if (bool.Parse(strBooleano)) { Console.WriteLine("El booleano se parseó correctamente"); } if (int.Parse(strEntero) == 16) { Console.WriteLine("El entero se parseó correctamente"); } Separador.EscribirPie("Fin Ejemplo 5"); #endregion //Ejemplo 6: Un overflow en unboxing //Fijate que en la línea donde asigno byteGrandeUnboxed tengo un doble cast: //El primero es para pasar byteGrandeBoxed a byte y poder sumarle 1 //El segundo es para pasar el resultado de la suma a Byte, ya que el compilador lo convierte a int //En la segunda parte del ejemplo obtenemos un InvalidCastException al hacer unboxing con un tipo diferente al inicial #region Ejemplo 6 Separador.EscribirEncabezado("Ejemplo 6: Overflow en Unbozing"); byte byteGrande = 255; object byteGrandeBoxed = (object)byteGrande; byte byteGrandeUnboxed = (byte)((byte)byteGrandeBoxed + 1); Console.WriteLine("Sorpresa! byteGrandeUnboxed vale: {0}", byteGrandeUnboxed.ToString()); long unLongCualquiera = 333333423; object unLongCualquieraBoxed = (object)unLongCualquiera; //La siguiente línea da una excpción, por eso está comentada //int aDisney = (int)unLongCualquieraBoxed; Separador.EscribirPie("Fin ejemplo 6"); #endregion //Ejemplo 7: Comparando objetos //En el primer caso comparo por referencia usando el método static de System.Object ReferenceEquals //En la segunda y tercera comparaciones uso un método virtual overrideado en la clase Person //El override es simple cuando comparo objeto por objeto, no hace falta implementar interfases //como se vio en Arrays #region Ejemplo 7 Separador.EscribirEncabezado("Ejemplo 7: Comparaciones de Objetos"); Person curly = new Person(Person.HashType.Fijo); curly.FirstName = "Curly"; curly.LastName = "Howard"; Person otraRef = curly; Console.WriteLine("Las dos variables: curly y otraRef son referencias a un mismo objeto de tipo Person"); Console.WriteLine("Pregunta: las referencias de curly y otraRef son iguales (por medio de ReferenceEquals)? Respuesta: {0}", object.ReferenceEquals(curly, otraRef)); Console.WriteLine("Comparación por medio de Equals. Son iguales? Respuesta: {0}", (curly.Equals(otraRef)).ToString()); Console.WriteLine("Comparación por medio de '=='. Son iguales? Respuesta: {0}", (curly == otraRef).ToString()); Person shemp = new Person(Person.HashType.Fijo); shemp.FirstName = "Shemp"; shemp.LastName = "Howard"; Console.WriteLine("En este caso las variables: curly y shemp apuntan a dos instancias distintas de la clase Person"); Console.WriteLine("Comparación de curly vs shemp por medio de Equals. Son iguales? {0}", (shemp.Equals(curly))); Console.WriteLine("Comparación de curly vs shemp por medio de '=='. Son iguales? {0}", (shemp == curly).ToString()); Console.WriteLine("Hash de Curly: {0}", curly.GetHashCode().ToString()); Console.WriteLine("Hash de Shemp: {0}", shemp.GetHashCode().ToString()); Person curlyClon = new Person(Person.HashType.Algoritmo); curlyClon.FirstName = "Curly"; curlyClon.LastName = "Howard"; Console.WriteLine("Comparación de Curly vs CurlyClon por medio de Equals. Son iguales? {0}", (curlyClon.Equals(curly))); Console.WriteLine("Comparación de Curly vs CurlyClon por medio de '=='. Son iguales? {0}", (curlyClon == curly).ToString()); Console.WriteLine("Hash de Curly: {0}", curly.GetHashCode().ToString()); Console.WriteLine("Hash de CurlyClon: {0}", curlyClon.GetHashCode().ToString()); Separador.EscribirPie("Fin Ejemplo 7"); #endregion //Ejemplo 8: Comparación de value types usando Equals de instancia (no se precisa castear, se hace boxing) #region Ejemplo 8 Separador.EscribirEncabezado("Ejemplo 8: Comparación de Value Types"); int primerEntero = 5; int segundoEntero = 5; Console.WriteLine("Comparación de dos enteros usando Equals de instancia, equals de ReferenceType y '=='"); Console.WriteLine("P: Son iguales (Equals de instancia)? R: {0}", (primerEntero.Equals(segundoEntero)).ToString()); Console.WriteLine("P: Son iguales (Equals de ValueType)? R: {0}", (ValueType.Equals(primerEntero, segundoEntero)).ToString()); Console.WriteLine("P: Son iguales (==)? R: {0}", (primerEntero == segundoEntero).ToString()); //Segunda parte del ejemplo: Comparando structs con el Equals de instancia Console.WriteLine("Segunda parte: comparación de Structs (son value types). Dos instancias distintas con el mismo contenido"); MisMascotas mascotasReales = new MisMascotas(); mascotasReales.NombreDelGato = "Wanda"; mascotasReales.NombreDelPerro = "Barbie"; MisMascotas mascotasImaginarias = new MisMascotas(); mascotasImaginarias.NombreDelGato = "Wanda"; mascotasImaginarias.NombreDelPerro = "Barbie"; Console.WriteLine("P: Son iguales las dos instancias (utilizando Equals de instancia)? R: {0}", (mascotasReales.Equals(mascotasImaginarias)).ToString()); Console.WriteLine("P: Son iguales las dos instancias (utilizando Equals de ValueType)? R: {0}", (ValueType.Equals(mascotasImaginarias, mascotasReales)).ToString()); Separador.EscribirPie("Fin Ejemplo 8"); #endregion //Ejemplo 9: Operator Overloading para un vector en 3D //EN verdad lo más importante está en la definición del struct vector, que es donde está el overload #region Ejemplo 9 Separador.EscribirEncabezado("Ejemplo 9: Sobrecarga de operadores en clases"); Vector velocidad = new Vector(1, 2, 3); Vector velocidadAdicional = new Vector(4, 5, 6); Vector velocidadFinal = velocidad + velocidadAdicional; Console.WriteLine("El resultado es: {0}", velocidadFinal.ToString()); Separador.EscribirPie("Fin de ejemplo 9"); #endregion //Ejemplo 9b: Este código muestra una peculiaridad del producto con respecto a la operación XOR //Multiplicar por cero un valor no nulo y después hacer un XOR no es lo mismo que hacer un XOR con cero #region Ejemplo 9b var result = 0; var result2 = 0; result = (result * 397) ^ 41; result = (result * 397) ^ 37; Console.WriteLine(result.ToString()); Console.WriteLine((result2 * 397).ToString()); #endregion //Ejemplo 10: Conversión con System.Convert //Usando System.Convert no se pierden centavos, mientras que usando una conversión explícita de float a unint sí se pierde #region Ejemplo 10 Separador.EscribirEncabezado("Ejemplo 10: Conversiones usando System.Convert"); float amount = 0.63f; uint cents = System.Convert.ToUInt16(amount * 100.0f); float dollars = cents / 100.0f; Console.WriteLine("Valor float inicial es de tipo float: {0}", amount.ToString()); Console.WriteLine("Cents (uint convertido con System.Convert): {0}", cents.ToString()); Console.WriteLine("Dollars (uint a float implícito) : {0}", dollars.ToString()); cents = (uint)(amount * 100.0f); dollars = cents / 100.0f; Console.WriteLine("Cents (conversión explicita a uint desde float): {0}", cents.ToString()); Console.WriteLine("Dollars (conversión implícita desde uint a float usando el segundo valor de cents: {0}", dollars.ToString()); Separador.EscribirPie("Fin Ejemplo 10"); #endregion //Ejemplo 11: En este caso, es una definción de Cast entre dos clases creadas por mí. //Ver en Chapter7.Classes las definicones de OneMan y AnotherMan. //La conversión puede definrise en cualquiera de las dos clases (origen y target) con exactamente el mismo código, //y funcionará de las dos maneras #region Ejemplo 11 Separador.EscribirEncabezado("Ejemplo 11: Conversiones personalizadas"); OneMan unHombre = new OneMan("Juan Carlos", "Pelotudo"); Console.WriteLine("El nombre de OneMan es: {0}, {1}", unHombre.LastName, unHombre.FirstName); AnotherMan otroHombre = (AnotherMan)unHombre; Console.WriteLine("El nombre completo de AnotherMan es: {0}", otroHombre.FullName); Separador.EscribirPie("Fin Ejemplo 11"); #endregion //Ejemplo 12: En estos ejemplos se ve que el casteo de una clase derivada a una clase base no sirve de mucho //En ninguno de estos casos recupero el comportamiento de la clase base. Esto es porque el casting implícito //provisto por el compilador sólo cambia el tipo de referencia pero el objeto creado en Managed Heap es el mismo //Por eso siempre obtengo 4 divisores sin importar los pasajes que haga entre tipo derivado y tipo base //El único modo de obtener dos divisores es que el tipo base sea puro #region Ejemplo 12 Separador.EscribirEncabezado("Ejemplo 12: Conversión entre clases"); //Primer escenario: Casteo un EnteroPar para convertirlo en un Entero. Recibo el cast en una variable Entero EnteroPar dos = new EnteroPar(3); //Aunque sea un contrasentido acá, sirve para los ejemplos de casteo con EnteroPrimo abajo para ver si tuvo éxito o no Entero uno = (Entero)dos; int[] divisores = uno.Divisores(); for (int i = 0; i < divisores.Length; i++) { Console.WriteLine("Divisores[{0}]={1}", i.ToString(), divisores[i].ToString()); } //Segundo escenario: Declaro con el tipo base, pero uso el contructor del tipo derivado //Después casteo al tipo base recibiendo el cast en una variable del tipo base. Acá tengo dos escanrios distintos Entero cuatro = new EnteroPar(4); Entero cinco = (Entero)cuatro; int[] DivisoresDe4 = cuatro.Divisores(); for (int i = 0; i < DivisoresDe4.Length; i++) { Console.WriteLine("DivisoresDe4[{0}]={1}", i.ToString(), DivisoresDe4[i].ToString()); } int[] DivisoresDe5 = cinco.Divisores(); for (int i = 0; i < DivisoresDe5.Length; i++) { Console.WriteLine("DivisoresDe5[{0}]={1}", i.ToString(), DivisoresDe5[i].ToString()); } //Aquí tengo un objeto puero de la clase base declarado y construido como de la clase base Entero entero6 = new Entero(6); int[] DivisoresDe6 = entero6.Divisores(); for (int i = 0; i < DivisoresDe6.Length; i++) { Console.WriteLine("DivisoresDe6[{0}]={1}", i.ToString(), DivisoresDe6[i].ToString()); } //Ahora van escenarios entre EnteroPrimo y EnteroPar //Tomando el mismo objeto dos creado arriba EnteroPrimo tres = (EnteroPrimo)dos; int[] divisoresDe3 = tres.Divisores(); for (int i = 0; i < divisoresDe3.Length; i++) { Console.WriteLine("divisoresDe3[{0}]={1}", i.ToString(), divisoresDe3[i].ToString()); } //Y al revés, desde un primo genero un par EnteroPar seis = (EnteroPar)tres; int[] divisoresDe6 = seis.Divisores(); for (int i = 0; i < divisoresDe6.Length; i++) { Console.WriteLine("divisoresDe6[{0}]={1}", i.ToString(), divisoresDe6[i].ToString()); } Separador.EscribirPie("Fin ejemplo 12"); #endregion //int i = 5; //if (i is object) //{ // Console.WriteLine(@"i is an object :)"); //} //else //{ // Console.WriteLine(@"i is not an object :("); //} //Console.WriteLine("Un int necesita {0} bytes", sizeof(int).ToString()); //Console.WriteLine("Un long necesita {0} bytes", sizeof(long).ToString()); //int? a = null; //Nullable<int> b = null; //Console.WriteLine(b.HasValue); //b = a; //int entero = 5; //int? enteroNulo = null; //int enteroFinal = enteroNulo ?? entero; //Console.WriteLine("El valor de enteroFinal es {0}", enteroFinal.ToString()); //long val = 30000000000; //try //{ // int otroVal = checked((int)val); // Console.WriteLine("El valor de otroVal es: {0}", otroVal.ToString()); //} //catch (Exception e) //{ // Console.WriteLine("Ocurrió una excepción de tipo {0}", e.ToString()); //} //Person Curly = new Person(); //Person Shemp = Curly; //bool test = ReferenceEquals(Shemp, Curly); //Console.WriteLine(test.ToString()); }
static void Main(string[] args) { EncabezadoYPieConsola Separador = new EncabezadoYPieConsola(); //Ejemplo 1: Creo una función, le apunto con un delegado //y luego llamo al delegado que es lo mismo que llamar a la función //Aquí uso Delegate Inference, la línea 18 pudo haber sido: AStringFunction firstStringFunction = new AStringFunction(ThisFunction); #region Ejemplo 1 Separador.EscribirEncabezado("Ejemplo 1: Ejemplo simple de Delegado"); AStringFuntion firstStringFunction = ThisFunction; string mensaje = firstStringFunction(); Console.WriteLine(mensaje); Separador.EscribirEncabezado("Fin Ejemplo 1"); #endregion //Ejemplo 2: Usar un array de delegates #region Ejemplo 2 Separador.EscribirEncabezado("Ejemplo 2: Array de Delegados"); Operacion[] Operaciones = { new Operacion(MathOperations.MultiplicarPorDos), new Operacion(MathOperations.Cuadrado) }; for (int i = 0; i < Operaciones.Length; i++) { CalcularYMostrar(Operaciones[i]); } Separador.EscribirPie("Fin Ejemplo 2"); #endregion //Ejemplo 3: Lo mismo que en ejemplo 2, pero usando un Generic Delegate //Vemos que no hace falta declarar el delegado específico, porque uso la declaración Genérica que ya está provista por C# #region Ejemplo 3 Separador.EscribirEncabezado("Ejemplo 3: Generic Delegate"); Func <int, long>[] OperacionesConGeneric = { MathOperations.MultiplicarPorDos, MathOperations.Cuadrado }; for (int i = 0; i < OperacionesConGeneric.Length; i++) { CalcularConGenericYMostrar(OperacionesConGeneric[i]); } Separador.EscribirPie("Fin Ejemplo 3"); #endregion //Ejemplo 4: Aquí veo el poder real de los Generics y de los Delegate. #region Ejemplo 4 Separador.EscribirEncabezado("Ejemplo 4: Bubblesorter"); //En el primer caso ordeno un array de enteros usando un BubbleSorter que está definido //sólo para el caso en que tenga que ordenar enteros, es una implementación específica //Ordenar un array de enteros int[] array = PrepareArray(); Console.WriteLine("Array antes de ordenar"); PrintArray(array); BubbleSorter.BubbleSort(array); Console.WriteLine("Array después de ordenar"); PrintArray(array); //Ahora, voy a ordenar una lista de objetos definidos por mí //En este caso, la definición del BubbleSorter no está atada a la clase sino que es completamente genérica //Ordenar una List de Employees List <Employee> empleados = PrepareEmployees(); Console.WriteLine("Lista de Empleados antes de ordenar"); PrintEmployees(empleados); BubbleSorter.GenericBubbleSort(empleados, Employee.CompareTo); Console.WriteLine("Lista de Empleados después de ordenar"); PrintEmployees(empleados); //Ordenar un Array de Employees //Como el BubbleSorter tiene un parámetro de tipo //IList<T> en List<T> puedo usar también un array Employee[] arrayDeEmpleados = PrepareEmployeeArray(); Console.WriteLine("Array de Empleados antes de ordenar"); PrintEmployees(arrayDeEmpleados); BubbleSorter.GenericBubbleSort(arrayDeEmpleados, Employee.CompareTo); Console.WriteLine("Array de Empleados después de ordenar"); PrintEmployees(arrayDeEmpleados); Separador.EscribirPie("Fin de Ejemplo 4"); #endregion //Ejemplo 5: Multicast Delegate //Como se ve, no hay necesidad de declarar el Multicast Delegate ya que uso el Generic Delegate Action<T> //Y con una sola llamada se invocan todas las funciones de la lista #region Eejemplo 5 Separador.EscribirEncabezado("Ejemplo 5: Multicast Delegate"); Action <int> OperacionesNulas = MathOperations.CuadradoYMostrar; OperacionesNulas += MathOperations.Dividir5PorX; OperacionesNulas += MathOperations.MutiplicarPorDosyMostrar; OperacionesNulas(2); OperacionesNulas(500); //El problema potencial es que si llega a fallar algo en el medio (una excepción en alguna invocación) //pueden no invocarse todas las funciones. Para eso uso la enumeración con un try catch Delegate[] OperacionesPorLista = OperacionesNulas.GetInvocationList(); foreach (Action <int> accion in OperacionesPorLista) { accion(7); try { accion(0); } catch (Exception e) { ReportarExcepcion(e); } accion(1000); } Separador.EscribirPie("Fin Ejemplo 5"); #endregion //Ejemplo 6: Anonymous Delegate //Recordemos todas las instancias de definción de delegados //Primero la más explícita y verbosa: //delegate string GetAstring(); //int x = 5; //GetAstring StringDeEntero = new GetAString(x.toString()); //**** //Despsués le saqueé la llamada explícita al constructor con Inferencia. Reemplazo la última línea por: //GetAString StringDentero = x.ToString(); //Después usé Generics para no tener que declarar (me libro de la primera línea de arriba): //Func<string> StringDeEntero = x.ToString(): //Y ahora finalmente uso método anónimo: //Func<string> StringDeEntero = delegate() //{ // return x.ToString(); //} //Incluso puedo usar la variable x declarada fuera del Delegate #region Ejemplo 6 //Usar Anonymous Delegate Func <int, int> anonDel = delegate(int param) { param += 10; return(param); }; Console.WriteLine("El valor retornado usando un Anonymous Delagate es: {0}", anonDel(50)); //Usar Lambda Expression - Ejemplo simple Func <int, int> lambda = param => { param += 10; return(param); }; Console.WriteLine("El valor retornado usando una Lambda Expression es: {0}", lambda(50)); #endregion //Ejemplo 6: Lambda Expression #region Ejemplo 7 //Usar Lambda expression inline Func <int, int> LambdaSingle = param => param += 10; Console.WriteLine("El valor retornado usando una Single Line Lambda es: {0}", LambdaSingle(50)); #endregion }