try { // Dentro de este cdigo se puede lanzar alguna excepcin. } catch(ExceptionA ex) { // Manejamos la excepcin de tipo ExceptionA. } catch(ExceptionB ex) { // ManejamOs la excepcin de tipo ExceptionB. } finally { // Cdigo de limpieza. }
En este ejemplo manejamos la excepcin que se lanza al dividir por cero. Este ejemplo es slo para ilustrar; lo ideal es filtrar x antes de llamar Calc.
class Prueba { static int Calc(int x) { return 10 / x; } static void Main() { try { int y = Calc(0); // Esto lanza una excepcin! Console.WriteLine(y); } catch(DivideByZeroException ex) { Console.WriteLine(x no puede ser cero.); } Console.WriteLine(Programa terminado.); } }
Las excepciones son relativamente costosas de tratar porque toman cientos de ciclos del reloj del procesador. Estos ejemplos son slo para
class Prueba { static int Calc(int x) { return 10 / x; } static void Main(string[] args) { try { byte b = byte.Parse(args[0]); Console.WriteLine(b); } catch(IndexOutOfRangeException ex) { Console.WriteLine(Debe especificar un valor.); } catch(FormatException ex) { Console.WriteLine(Esto no es un nmero.); } catch(OverflowException ex) { Console.WriteLine(Ha especificado algo ms grande que un byte.); } } }
Tambin se puede omitir el tipo de dato y el nombre de la variable para capturar todas las excepciones: catch{ }
El archivo se cierra sin importar si (1) el bloque try termina correctamente, (2) si el control sale temprano porque el archivo estaba vaco (EndOfStream) o (3) se lanza una excepcin IOException mientras se lee el archivo.
static void LeerArchivo() { StreamReader reader = null; // En el namespace System.IO try { reader = File.OpenText(archivo.txt); if(reader.EndOfStream) return; Console.WriteLine(reader.ReadToEnd()); } finally { if (reader != null) reader.Dispose(); } }
(2) StreamReader reader = File.OpenText(file.txt); try { ... } finally { if(reader != null) ((Idisposable)reader).Dispose(); }
Las excepciones pueden ser lanzadas tanto en tiempo de ejecucin como en el cdigo. En este ejemplo, Mostrar_Info lanza una excepcin System.Argument NullException
{ static void Mostrar_Info(string Nombre) { if(Nombre == null) throw new ArgumentNullException(Nombre); Console.WriteLine(Nombre); } static void Main() { try{ Mostrar_Info(null); } catch(ArgumentNullException ex) { Console.WriteLine(Excepcin manejada.); } } }
Las excepciones se pueden volver a lanzar una vez capturadas, ya sea slo para registrar dicho error, para lanzar una ms especfica o porque las cosas se salieron de control, como se muestra en este
string s = null; using (WebClient wc = new WebClient()) { try{s = wc.DownloadString(http://www.albahari.com/nutshell/); } catch (WebException ex) { // Antes, podramos registrar el error. if(ex.Status == WebExceptionStatus.NameResolutionFailure) Console.WriteLine(Nombre de dominio invlido.); else throw; // Otro tipo de WebException. Relanzamos. } }
System.NotSupportedException: Indica que una funcionalidad no es soportada. Ej.: Al llamar el mtodo Add de una lista marcada como slo lectura (IsReadOnly = true).
System.NotImplementedException: Indica que una funcin no ha sido implementada.
System.ObjectDisposedException: Lanzada cuando el objeto del cual se le llama una funcin ha sido liberado de su instancia.
Stream Adapter
Decorator Streams
Un BackingStore hace referencia a mecanismos para acceso persistente a datos. Los DecoratorStreams son parecidos en funcionamiento a los BackingStore Streams, pero convierte la data en alguna manera. Los StreamAdapters permiten manejar a un nivel ms alto (texto, XML, float, int) lo que se maneja a travs de los BackingStore Streams.
StreamReader (texto) StreamWriter (texto) BinaryReader (int, float, ) BinaryWriter (int, float, ) XmlReader (XML) XmlWriter (XML)
Miembros
public abstract bool CanRead { get; } public abstract int Read(byte[] buffer, int offset, int count) public virtual int ReadByte(); public abstract bool CanWrite { get; } public abstract void Write (byte[] buffer, int offset, int count); public virtual void WriteByte (byte value);
Bsqueda
public abstract bool CanSeek { get; } public abstract long Position { get; set; } public abstract void SetLength (long value); public abstract long Length { get; } public abstract long Seek (long offset, SeekOrigin origin);
public virtual void Close(); public void Dispose(); public abstract void Flush(); public virtual bool CanTimeout { get; } public virtual int ReadTimeout { get; set; } public virtual int WriteTimeout { get; set; } public static readonly Stream Null; // Null stream. public static Stream Synchronized (Stream stream);
En este ejemplo se utiliza un FileStream para leer, escribir y realizar desplazamiento (bsqueda) en un archivo de texto.
using System; using System.IO; class Program { // Crear un archivo llamado prueba.txt. using (Stream s = new FileStream(prueba.txt, FileMode.Create)) { Console.WriteLine(s.CanRead); // True Console.WriteLine(s.CanWrite); // True Console.WriteLine(s.CanSeek); // True s.WriteByte(101); s.WriteByte(102); byte[] bloque = {1, 2, 3, 4, 5}; s.Write(bloque, 0, bloque.Length); // Graba 5 bytes // CDIGO PARA DESPLAZARNOS Y LEER. } }
En este ejemplo se utiliza un FileStream para leer, escribir y realizar desplazamiento (bsqueda) en un archivo de texto.
Console.WriteLine(s.Length); // 7 Console.WriteLine(s.Position); // 7 s.Position = 0; // Nos movemos al inicio. Console.WriteLine(s.ReadByte()); // 101 Console.WriteLine(s.ReadByte()); // 102 // Volvemos a leer desde el Stream al arreglo: Console.WriteLine(s.Read(bloque, 0, bloque.Length)); /* Si la lnea anterior retorn 5, estaremos al final del archivo, por lo que volver a leer nos retorna 0*/ Console.WriteLine(s.Read(bloque, 0, block.Length));
Implementadas en lenguajes como ActionScript, Delphi, Groovy, Haskell, Matlab, Objective-C, Perl, Smalltalk, Visual Basic .Net
Una expresin lambda puede ser asignada a un tipo delegado de la siguiente forma:
delegate int del(int i); static void Main(string[] args) { del miDelegado = x => x * x; int j = miDelegado(5); // j = 25 }
Una expresin lambda puede ser asignada a un tipo delegado de la siguiente forma:
delegate int del(int i); static void Main(string[] args) { del miDelegado = x => x * x; int j = miDelegado(5); // j = 25 }
delegate void DelegadoPrueba(string s); DelegadoPrueba miDelegado = n => { string s = n + + Mundo; Console.WriteLine(s); } miDelegado(Hola );
El siguiente ejemplo muestra cmo hacer un bloque de instrucciones lambda que genera un nmero aleatorio y lo imprime por pantalla:
delegate int sinParametros(); private static void BloqueLambda() { sinParametros aleat = () => { int random = new Random().Next(); Console.WriteLine("Random number generated - {0}", random); return random; }; Console.WriteLine(aleat()); }
Estos delegados son muy comunes a la hora de encasillar expresiones definidas por el usuario que nos interesa que sean aplicadas a cada elemento dentro de una coleccin de datos.
Varios ejemplos de consultas estndard: (No confunda la expresin lamda => con el operador de comparacin >=)
En el ejemplo, se extraen los nmeros pares de una coleccin. Debido a que la expresin lambda retorna un booleano, se le considera actuar como un predicado, el cual es usado para comparar cada elemento del arreglo y filtrar slo aquellos verdaderos.
public delegate void SampleDelegate(string str); class SampleClass { // Mtodo que concuerda el SampleDelegate static void sampleMethod(string message) { // Aqu va el cdigo } // Mtodo que instancia el delegado. void SampleDelegate() { SampleDelegate sd = sampleMethod; sd("Sample string"); } }
La declaracin de un delegado es precedida de la palabra delegate; por lo dems es similar a la declaracin de un mtodo abstracto. delegate int Transformar(int x);
Para crear una instancia de un delegado se puede asignar el mtodo a la variable del delegado:
delegate int Transformar(int x); class Prueba { static void Main() { Transformar t = Cuadrado; // Crea la instancia. int result = t(3); // Invoca al delegado. Console.WriteLine(result); // 9 } static int Cuadrado(int x) { return x * x; } }
Esta tcnica es til para crear mtodos plugin. En este ejemplo, el mtodo que se ejecutar se especifica dinmicamente.
public delegate int Transformar(int x); class Util { public static void Realizar_Transf(int[] valores, Transformar t) { for(int i = 0; i < valores.Length; i++) valores[i] = t(valores[i]); } } class Prueba { static void Main() { int[] vals = { 1, 2, 3}; Util.Realizar_Transf(vals, Cuadrado); // Dinmicamente! foreach(int i in vals) Console.Write(i + ); // 1 4 9 } static int Cuadrado(int x) { return x * x; } }
Delegados Multicast:
Todas las instancias de delegados tienen capacidad de multicast. Esto significa que una instancia de un delegado puede llamar ms de un mtodo. Se inicializa usando los operadores + y +=. AlgunDelegado d = AlgunMetodo1; d += AlgunMetodo2; Al invocar a d estaremos llamando, entonces, a ambos mtodos en el mismo orden en que fueron aadidos. Tambin se puede usar y -= para el efecto inverso. Se permite usar estos operadores an si el valor del delegado es null. Si el mtodo retorna algn valor, ste es retornado al mtodo invocador. En el caso de Multicast, se retorna el valor del ltimo mtodo; los retornos de los dems mtodos son ignorados.
Suponga que desea crear una rutina que tarda mucho tiempo. Podra enviar eventualmente informacin a algn mtodo que se encargue de dar retroalimentacin al usuario sobre el progreso utilizando un delegado.
public delegate void Reportar_Progreso(int porcientoCompletado); class Util{ public static void Trabajo_Duro(Reportar_Progreso p){ for(int i = 0; i < 10; i++) { p(i * 10); // Invocar al delegado. System.Threading.Thread.Sleep(100); // Simular trabajo. } } } class Prueba{ static void Main(){ Reportar_Progreso p = Mostrar_Progreso; p += Escribir_Progreso_en_Disco; Util.Trabajo_Duro(p); } static void Mostrar_Progreso(int porcientoCompletado){ Console.WriteLine(porcientoCompletado); } static void Escribir_Progreso_en_Disco(int porcientoCompletado){ System.IO.File.WriteAllText(progreso.txt, porcientoCompletado.ToString()); } }
Un tipo delegado puede contener parmetros de tipo genrico. Con esta definicin, es posible escribir un mtodo utilitario ms generalizado para el delegado Transformar que trabaje con cualquier tipo:
public delegate T Transformar<T> (T arg); class Util{ public static void Transformar<T> (T[] valores, Transformar<T> t{ for(int i = 0; i < valores.Length; i++) valores[i] = t(valores[i]); } } class Prueba{ static void Main(){ int[] valores = { 1, 2, 3 }; Util.Transformar(valores, Cuadrado); // Mtodo plugin foreach(int i in valores) Console.Write( i + ); // 1 4 9 } static int Cuadrado (int x) { return x * x; } }
Considere el siguiente ejemplo. La clase Almacen desencadena su evento Precio_Cambia do cada vez que su propiedad Precio cambia.
Public delegate void Precio_CambiadoHandler(decimal Precio_Anterior, decimal Precio_Nuevo); public class Almacen{ string _lstr_simbolo; decimal _ldec_precio; public Almacen(string Simbolo) { this._lstr_simbolo = Simbolo; } public event Precio_CambiadoHandler Precio_Cambiado; public decimal Precio{ get{ return _ldec_precio; } set{ if(_ldec_precio == value) return; if(Precio_Cambiado != null) Precio_Cambiado(_ldec_precio, value); _ldec_precio = value; } } }
Conectando a la B.D. Salvando los datos de Vuelta en la B.D. Preparando la Aplicacin para Recibir Datos
Este es un bloque de cdigo que realiza una conexin directa con una B.D. para ejecutar un procedimiento almacenado.
List<Computadora> _resp = new List<Computadora>(); try { SqlConnection ConexionDB = new SqlConnection(ConfigurationManager.ConnectionStrings["conexionDB"].C onnectionString); ConexionDB.Open(); SqlDataReader dr; comandoDB = new SqlCommand(); comandoDB.CommandType = CommandType.StoredProcedure; comandoDB.CommandText = "ObtenerComputadoras"; comandoDB.Parameters.Add(new SqlParameter("@id", id)); comandoDB.Parameters.Add(new SqlParameter("@vendida", vendida)); comandoDB.Connection = ConexionDB; dr = comandoDB.ExecuteReader(); while (dr.Read()) { _resp.Add(new Computadora(dr)); } } catch { ; } finally { ConexionDB.Close(); }