2. El lenguaje de programación C# Integración de Sistemas Diseño e implementación con .NET Introducción Primer lenguaje orientado a componentes en la familia C/C++ ¿Qué es un componente? No sólo clases y métodos, también propiedades y eventos Módulo independiente (desarrollo y reutilización) Granularidad mayor que los objetos Puede incluir múltiples clases Independiente del lenguaje Normalmente, el desarrollador y el usuario de un componente son totalmente independientes 1 Introducción En lenguajes "puristas" como Smalltalk o Lisp: Todo es un objeto Problema: eficiencia reducida En otros lenguajes como C++ o Java No existe interacción entre tipos primitivos (long) y objetos (Long) Se tratan de forma diferente por motivos de rendimiento Introducción En C# todo es un objeto Todo hereda de System.Object Es posible declarar un tipo primitivo (long) y trabajar con él de forma eficiente. Además, es posible asignarlo a un objeto y entonces será tratado como tal Incluye mecanismos transparentes de boxing y unboxing Los tipos primitivos sólo se tratan como objetos cuando la situación lo requiere, mientras tanto pueden aplicárseles optimizaciones específicas El hecho de que todos los tipos del lenguaje deriven de una clase común, facilita enormemente el diseño de colecciones genéricas, que pueden almacenar objetos de cualquier tipo 2 Hola Mundo using System; /* Class HelloWorld Description: simple C# example */ class HelloWorld { // entry point public static void Main() { Console.WriteLine("Hello World"); } } Compilador C# Ubicación Compilador C# Sintaxis C:\windows\Microsoft.NET\Framework\vn.n.nnn\csc.exe csc [opciones] fich1.cs [, fich2.cs] Opciones /out:ficheroSalida /t:winexe /t:library /r:librería.dll Por defecto se referencia a mscorlib.dll. /main:clase 3 Estructura Namespaces Tipos, Namespaces Declaración de tipos Clases, estructuras, interfaces, enumeraciones y delegados Miembros Constantes, atributos, métodos, propiedades, índices, eventos, operadores, constructores, destructores Namespaces Declaración: namespace <NombreEspacio> { <Definición clases> } Anidación de namespaces válida Referencia a namespaces externos NmbEspacio1.NmbEspacio2.NmbClase using Alias: evitar conflictos entre Namespaces using <alias> = <NombreCompletoClase>; 4 Namespaces using using using using using System; System.Collections.Generic; System.Text; System.Collections; System.IO; static void Main(string[] args) { string username; ArrayList namesCollection; using SC = System.Collections; using SIO = System.IO; static void Main(string[] args) { string username; string filename SC.ArrayList namesCollection; filename = SIO.Path.Combine( ... ); ¿A qué namespace pertenece? Sistema de Tipos Unificado Valor Variables contienen datos Valor nulo no permitido Referencia Variables contienen referencias a objetos Valor nulo permitido int i = 123; i string s = "Hello world"; s 123 "Hello world" 5 Sistema de Tipos Unificado Valor Primitivos int i; Enumeraciones enum State { Off, On } Estructuras struct Point { int x, y; } Referencia Raíz object String string Clases class Foo : Bar, IFoo {...} Interfaces interface IFoo : IBar {...} Arrays string[] a = new string[10]; Delegados delegate void Empty(); Sistema de Tipos Unificado Dos tipos de conversiones Implícitas Ocurren automáticamente Éxito asegurado Sin pérdida de precisión Explícitas Requieren un cast Pueden originar errores Precisión puede perderse 6 Sistema de Tipos Unificado Dos tipos de conversiones int x = 123456; long y = x; short z = (short)x; // implicit // explicit double d = 1.2345678901234; float f = (float)d; long l = (long)d; // explicit // explicit Sistema de Tipos Unificado ¿Cómo se tratan polimórficamente los tipos por valor y por referencia? ¿Como se convierte de int (tipo valor) a objeto Int32 (tipo referencia)? Boxing Sólo aplicable a tipos valor 7 Sistema de Tipos Unificado Boxing Reserva espacio Copia valor Unboxing Chequea tipo dato Copia valor int i = 123; object o = i; // boxing int j = (int) o; // unboxing On the stack On the heap On the stack i On the heap (i boxed) o int 123 int i=123; object o=i; (i boxed) o j int 123 123 object o=i; 123 int j=(int) o; Sistema de Tipos Unificado En última instancia todos los tipos derivan de la clase Object Conversiones implícitas desde cualquier tipo al tipo Object object Stream MemoryStream Hashtable int double FileStream 8 Tipos predefinidos C# Reference object, string Signed sbyte, short, int, long Unsigned byte, ushort, uint, ulong Character char Floating-point float, double, decimal Logical bool Importante: realmente se trata de alias a tipos proporcionados por el sistema int es un alias a System.Int32 Válido: int entero = 100; entero.ToString(); Tipos predefinidos Tipo Descripción SByte Bytes con signo Byte Int16 Bits Rango Alias 8 [-128…127] sbyte Bytes sin signo 8 [0…255] byte Enteros cortos con signo 16 [-32.768…32.767] short UInt16 Enteros cortos sin signo 16 [0…65.535] ushort Int32 Enteros normales 32 [-2.147.483.648…2.147.483.647] int UInt32 Enteros normales sin signo 32 [0…4.294.967.295] uint [-9.223.372.036.854.775.808… Int64 Enteros largos long 64 9.223.372.036.854.775.807] UInt64 Enteros largos sin signo 64 [0…18.446.744.073.709.551.615] ulong Single Reales con 7 dígitos 32 [±1,5×10-45…±3,4×1038] float Double Reales de 15-16 dígitos 64 [±5,0×10-324 …± 1,7×10308] double Decimal Reales de 28-29 dígitos significativos 128 [±1,0×10-28 …± 7,9×1028] decimal Boolean Valores lógicos 32 true, false bool Char Caracteres Unicode 16 [‘\u0000’, ‘\uFFFF’] char string object String Cadenas de caracteres Variable Valor máximo determinado por memoria Object Cualquier objeto Variable Cualquier objeto 9 Tipos predefinidos Problema: public static void Foo(int x){...} public static void Foo(long x){...} ¿Llamada Foo(100)? Tipo del literal entero es el primero que permita almacenarlo: int, uint, long, ulong Foo(100) llama al primer método Sufijos L (long, ulong), U (int, uint), UL (ulong) F (float), D (double), M (decimal) Ejemplo Foo(100L) llama al segundo método Tipos predefinidos: Arrays Almacenamiento de elementos del mismo tipo en un bloque contiguo de memoria Son tipos por referencia Deriva de System.Array Zero-based Pueden ser multidimensionales Length: número total de elementos (considerando todas las dimensiones) Rank: obtiene el número de dimensiones 10 Tipos predefinidos: Arrays Declaración int[] coord; Reserva de Espacio int[] coord = new int[9]; Inicialización int[] coord = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int[] coord = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; Acceso y Asignación coord[0] = 100; Tipos predefinidos: Arrays Arrays Multidimensionales Rectangulares int[,] matR = new int[2,3]; Pueden inicializarse de manera declarativa int[,] matR = new int[2,3] { {1,2,3}, {4,5,6} }; Escalonados (Jagged) Un array de arrays int[][] matJ = new int[2][]; Deben inicializarse proceduralmente (no de forma declarativa) 11 Tipos predefinidos: Arrays Métodos estáticos de System.Array void Sort(array) void Reverse(array) int IndexOf(array, object) int LastIndexOf(array, object) object Find(array, condition) object[ ] FindAll(array, condition) bool TrueForAll(array, condition) Clases Herencia Modificadores de acceso Miembros de una clase private internal protected protected internal public Constantes, campos, propiedades, métodos, indizadores, eventos, constructores, destructores Miembros estáticos e instancias Operadores 12 Clases. Herencia Sólo se admite herencia simple Se admite implementación de múltiples interfaces public class ClaseBase { … } public interface IInterfaz { … } public class ClaseDerivada : ClaseBase, IInterfaz { … } Para evitar que una clase se pueda extender se indica con: sealed Los métodos, por defecto, no pueden redefinirse (son sealed). Para poder redefinir un método Definirlo como virtual En la redefinición del método indicar override Clases. Constructores Llamadas entre constructores: this class SuperClass { private string argument1; public SuperClass() : this("<Default arg1>") { } public SuperClass(string arg1) { this.argument1 = arg1; Console.WriteLine("Arguments: " + argument1); } } SuperClass sc = new SuperClass(); // Creating a SuperClass instance Salida: Arguments: <Default arg1> 13 Clases. Constructores Llamadas a la clase base: base class ChildClass : SuperClass { private string argument2; public ChildClass() : this("<Default arg2>") { } public ChildClass(string arg2) { this.argument2 = arg2; Console.WriteLine("Arguments: " + argument2); } public ChildClass(string arg1, string arg2) : base(arg1) { this.argument2 = arg2; Console.WriteLine("Arguments: " + argument2); } } Clases. Constructores Ejemplo static void Main() { SuperClass sc = new SuperClass(); /* Shows: * Arguments: <Default arg1> */ ChildClass cc = new ChildClass(); /* Shows: * Arguments: <Default arg1> * Arguments: <Default arg2> */ ChildClass cc2 = new ChildClass("1", "2"); /* Shows: * Arguments: 1 * Arguments: 2 */ Console.Read(); } 14 Clases. Constructores estáticos Permiten inicialización de código, que se realizará una única vez para la clase Garantizan la ejecución antes de: La creación de la primera instancia de la clase El acceso a cualquier miembro estático Un único constructor estático por clase No pueden tener parámetros Clases. Constructores estáticos Llamada automática al acceder por primera vez a la clase public class LogManager { private static FileStream logFile; // Static Constructor opens the file static LogManager() { logFile = File.Open("logFile.dat", FileMode.Create); } public LogManager() { logFile.WriteLine(System.Date.Now + "Instance created"); } } 15 Clases. Destructores Llamado automáticamente por Garbage Collector public class LogManager { ~LogManager() { logFile.WriteLine(System.Date.Now + "Instance Disposed"); logFile.Close();; } } Llamada a Garbage Collector: System.GC.Collect() No garantiza borrado de memoria Los destructores no se heredan La clase System.Object Todos los tipos heredan de System.Object public virtual bool Equals(object o) public virtual int GetHashCode() public virtual string ToString() protected object MemberWiseClone() public System.Type GetType() protected virtual void Finalize() public static bool Equals(object o1, object o2) protected static bool ReferenceEquals(object o1, object o2) 16 Clases. Modificadores de acceso Con respecto al acceso, los métodos de una clase pueden ser: private: protected: Miembros accesibles desde el mismo assembly protected internal: Miembros accesibles desde la clase que los contiene o desde clases derivadas de ésta internal: Sólo código dentro de la misma clase contenedora tiene acceso a un miembro privado. Miembros accesibles desde el mismo assembly o clases derivadas de la clase que lo contiene (protected + internal) public: No hay restricciones de acceso Clases. Constantes Constantes Se evalúan en tiempo de compilación Son implícitamente estáticas (error si se usa static explícitamente) Ejemplo public class MyClass { public public public // The public const string VERSION = "1.0.0"; const string URI = "http://" + "www.google.es"; const double PI = 3.14159265358979; expression being assigned to SIN must be constant const double SIN = Math.Sin(PI); //ERROR ... } 17 Clases. Campos de sólo lectura Similares a las constantes, pero… Se inicialización en tiempo de ejecución (vs. compilación) Evitan necesidad de recompilar clientes Pueden ser estáticas o por instancia Una vez inicializadas, no pueden modificarse public class MyClass { public static readonly double d1 = Math.Sin(Math.PI); public readonly string s1; public MyClass(string s) { s1 = s; } } Clases. Propiedades Propiedades Encapsulación con métodos getXXX / setXXX Mezcla entre campo y método Externamente son accedidas como un campo público Internamente es posible asociar código a ejecutar en cada asignación (set) o lectura (get) de su valor 18 Clases. Propiedades > Definición public class UserProfileVO { private String loginName; private String encryptedPassword; atributos privados <<...>> public String LoginName { get { return loginName; } set { loginName = value; } } propiedades public String EncryptedPassword { get { return encryptedPassword; } set { encryptedPassword = value; } } <<...>> } Clases. Propiedades > Acceso static void Main(string[] args) { UserProfileDetailsVO userProfileDetailsVO = ... UserProfileVO userProfileVO = new UserProfileVO("jsmith", "7dj39jHT1d4gFl93", userProfileDetailsVO); //get System.Console.Write(userProfileVO.LoginName); //set userProfileVO.LoginName = “jsuarez"; } 19 Clases Abstractas Una clase abstracta no puede ser instanciada Está pensada para ser usada como clase base Puede contener métodos abstractos y no abstractos Similar a una interfaz No puede ser sealed Clases Abstractas public abstract class Product { public abstract String getReference(); } public class Book : Product { public override String getReference() { return ISBN; } } 20 Clases Sealed Es una clase que no se puede extender Las clases sealed no pueden ser abstractas Todas las estructuras son sealed ¿Por qué "cerrar" una clase? Para prevenir que sea extendida de forma no intencionada Optimización de código Las llamadas a métodos virtual pueden resolverse en tiempo de compilación Clases. Métodos Redefinición de métodos: virtual & override public class Product { public virtual String getReference() { return barCode; } } public class Book: Product { public override String getReference() { return ISBN; } } 21 Clases. Métodos Paso de parámetros Tipos primitivos se pasan por valor Para pasar por referencia: ref public class Util { public void Swap(ref int x, ref int y) { int temp; temp = x; x = y; y = temp; } } Clases. Métodos Paso de parámetros Número variable de parámetros: params public class Util { public static void printf(string fmt, params object[] args) {…} } object[] args = {“Texto”, 100} Util.printf(“%s %d”, args); 22 Indexers Un indexer permite a una instancia comportarse como un array virtual Permite sobrecarga (e.g. indexado por int y por string) Puede ser de sólo lectura, sólo escritura o lectura/escritura public class ListBox : Control { private string[] items; public string this[int index] { get { return items[index]; } set { items[index] = value; Repaint(); } } } <<...>> ListBox listBox = new ListBox(); listBox[0] = "hello"; Console.WriteLine(listBox[0]); Estructuras (struct) Similares a las clases pero … Requisitos de almacenamiento menores Paso por valor, no referencia No pueden extender ningún tipo (heredan directamente de System.ValueType) Ningún tipo puede heredar de ellas Pensadas para light weight objects Uso más eficiente de la memoria Ejemplos: Complex, Point, Color La mayoría de los tipos básicos (excepto string y object) implementados como structs Mismos miembros que una clase Modificadores de acceso válidos private (defecto), internal o public 23 Estructuras (struct) public struct Point { private int x, y; public Point(int x, int y) { this.x = x; this.y = y; } public int X { get { return x; } set { x = value; } } public int Y { get { return y; } set { y = value; } } } <<...>> Point p = new Point(2,5); p.X += 100; int px = p.X; // px = 102 Clases vs. Estructuras sp 10 20 cp CPoint 10 20 24 Clases vs. Estructuras. Similitudes Ambas son tipos que pueden ser definidos por el usuario Ambas pueden implementar múltiples interfaces Ambas pueden contener Datos Funciones campos, constantes, eventos, arrays métodos, propiedades, indexers, operadores, constructores Definiciones de tipos clases, estructuras, enumeraciones, interfaces, delegados Clases vs. Estructuras. Diferencias Clase Estructura Referencia Valor Puede heredar desde cualquier tipo no-sealed No puede heredar (hereda únicamente de System.ValueType) Puede tener destructor No puede tener destructor El usuario puede definir un constructor vacío (sin parámetros) El usuario no puede definir un constructor vacío (sin parámetros) 25 Enumeraciones Estructuras con explicitación de elementos Evitan uso excesivo de constantes (números mágicos) Facilitan legibilidad del código Sólo podrán contener campos públicos constantes y estáticos Internamente, los campos se tratarán como alguno de los siguientes tipos: int, byte, sbyte, short, ushort, uint, long, ulong Enumeraciones: ejemplo Declaración public enum MessageType : int { INFO = 1, WARNING = 2, ERROR = 3 } Uso MessageType messageType = MessageType.WARNING; 26 Enumeraciones Dado que los valores de una enumeración son enteros, será posible tratarlos como operandos: ==, !=, <, >, <=, >=, +, -, ^, &, |, ~, ++, -- Ejemplo: if (message > MessageType.INFO) { … } Interfaces Similar a la definición de un contrato Pueden incluir métodos, propiedades, indexers, eventos No pueden incluir operadores, constructores o destructores. Cualquier implementación de la interfaz debe dar soporte a todas las partes del contrato Miembros de una interfaz son por defecto public y abstract Proporcionan polimorfismo Diferentes clases y estructuras pueden implementar la misma interfaz No contienen implementación 27 Interfaces Declaración public interface IUserProfileDAO { // Interface methods void Create(…) { … } void Delete(…) { … } // Interface properties UserProfile LastUser { get; set; } } Implementación public class UserProfileDAO : IUserProfileDAO { … } Interfaces. Herencia multiple Clases y estructuras pueden heredar de múltiples interfaces Interfaces pueden heredar de múltiples interfaces interface IControl { void Paint(); } interface IListBox: IControl { void SetItems(string[] items); } interface IComboBox: ITextBox, IListBox { } 28 Delegados Tipo referencia Define la firma de un método Una vez instanciado, almacena uno o más métodos Esencialmente: puntero a una función OO Convenio para los eventos del framework Delegados /* Declare */ delegate double Del(double x); static void DemoDelegates() { // Instantiate Del delInst = new Del(Math.Sin); // Invoke double x = delInst(1.0); } 29 Operadores Aritméticos +, -, *, /, % checked vs. unchecked Asignación Comparación +=, -=, *=, /=, %=, ++, -- ==, !=, <, >, <=, >= Lógicos &, &&, |, ||, ~, !, ^ Operadores. Sobrecarga public class Complex { private float img; private float real; public Complex (float real, float img) { … } public float Img { ..} override public string ToString() { if ( img >= 0 ) return real + "+" + img +"i"; else return real + " " + img + "i"; } public static Complex operator + (Complex a, Complex b) { return new Complex(a.real + b.real, a.img + b.img); } } <<...>> Complex a; Complex b; Complex c = a + b; 30 Entrada / Salida por Consola System.Console Entrada Console.Read(); Console.ReadLine(); Console.ReadKey(); ConsoleKeyInfo.Key ConsoleKey ConsoleKeyInfo.Modifiers ConsoleModifiers Salida Console.Write(); Console.WriteLine(); Entrada / Salida por Consola: formato Console.Write(“Text {n0:format}”, var0) Console.Write(“Current Balance: {0:C}.”, balance) Sintaxis: <object>.ToString(“format”) long balance = 1000; // Muestra la cantidad en el formato de moneda adecuado Console.Write(balance.ToString("C")); 31 Entrada / Salida por Consola: formato Formatos predefinidos Número C D F P H Fecha Moneda Decimal Punto Fijo Porcentaje Hexadecimal S D t T F Short Date Long Date Short time Long Time Full Date Sentencias Condicionales Control de Excepciones if try ...catch...finally switch throw Iterativas while do for foreach Otras checked, unchecked lock using 32 Sentencias condicionales. if Sintaxis General if (condition) <statementsIF> else <statementsELSE> Sentencias condicionales. switch Sintaxis General ¡Obligatorio incluir break al final de cada rama! switch (i) { case 1: statements; break; case 2: statements; break; default: statements; break; } switch (str) { case “ABC”: statements; break; case “XYZ”: statements; break; default: statements; break; } 33 Sentencias iterativas. while Sintaxis General while (condition) { <statements> } Puede incluir instrucciones Break y/o Continue Sentencias iterativas. do...while Sintaxis General do { <statements> } while(condition) Puede incluir instrucciones Break y/o Continue 34 Sentencias iterativas. for Sintaxis General for (initialize-statement; condition; increment-statement) { statements; } Puede incluir instrucciones Break y/o Continue Sentencias iterativas. foreach Sintaxis General foreach (<Type> <e> in <collection>) { <statements> } Ejemplo String[] daysOfWeek = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" }; // Muestra por pantalla los días de la semana foreach (string s in daysOfWeek) { Console.WriteLine(s); } 35 Sentencias. Gestión de Excepciones Las excepciones son los mecanismos C# para gestionar errores inesperados Mejor que devolver valor de estado No pueden ser ignoradas No tienen porque gestionarse en el punto en el que ocurren Pueden usarse incluso donde no se devuelven valores (e.g. en el acceso a una propiedad) Se proporcionan excepciones estándar Sentencias. Gestión de Excepciones Sentencia try...catch...finally Bloque try contiene código que podría lanzar una excepción Bloque catch gestiona la excepción Puede haber varios bloques catch para gestionar diferentes tipos de excepciones Bloque finally contiene código que se ejecutará siempre 36 Sentencias. Gestión de Excepciones Sentencia throw lanza una excepción Una excepción se representa como una instancia de System.Exception o una clase derivada Contiene información sobre la excepción Propiedades Message StackTrace InnerException Es posible relanzar una excepción, o capturarla y lanzar otra Sentencias. Gestión de Excepciones try { Console.WriteLine("try"); throw new Exception("Message"); } catch (ArgumentNullException e) { Console.WriteLine("Caught null argument"); } catch (Exception e) { Console.WriteLine("catch"); Console.WriteLine("Message: " + e.Message); Console.WriteLine("StackTrace: " + e.StackTrace); } finally { Console.WriteLine("finally"); } 37 Sentencias. checked & unchecked Permiten controlar excepciones por overflow operaciones aritméticas para tipos enteros conversiones de tipos checked fuerza la comprobación de errores por overflow unchecked evita la comprobación de errores por overflow (defecto) Uso: checked(expression) checked{sentences] Sentencias. lock Permite definir regiones críticas dentro de aplicaciones multithreading Previene la corrupción de datos La sentencia lock proporciona exclusión mutua Bloquea acceso a la instancia mientras no finalice la operación Emplea la clase System.Threading.Monitor 38 Sentencias. lock public class CheckingAccount { decimal balance; public void Deposit(decimal amount) { lock (this) { balance += amount; } } public void Withdraw(decimal amount) { lock (this) { balance -= amount; } } } Sentencias. using C# incluye gestión automática de memoria (Garbage Collector) Elimina la mayoría de problemas de gestión de memoria Problema: finalización no determinista No existe seguridad o garantía acerca de cuando se llama a los destructores de clase 39 Sentencias. using Objetos que deben limpiarse una vez usados, deberían implementar la interfaz System.IDisposable Único método: Dispose() Sentencia using permite crear una instancia, emplearla y asegurar que tras ello el método Dispose() se llama Similar a bloque finally en la gestión de excepciones Sentencias. using public class MyResource : IDisposable { public void MyResource() { // Acquire valuble resource } public void Dispose() { // Release valuble resource } public void DoSomething() { ... } } <<...>> using (MyResource r = new MyResource()) { r.DoSomething(); } // r.Dispose() is called 40 Colecciones interface IEnumerable { IEnumerator GetEnumerator(); } interface IEnumerator { object Current {get; } bool MoveNext(); void Reset(); } Colecciones: System.Collection Clases Interfaces ArrayList ICollection Hashtable IComparer DictionaryBase IDictionary SortedList IEnumerable Queue IEnumerator Stack IList 41 Colecciones: ArrayList [Serializable] public class ArrayList : IList, ICollection, IEnumerable, ICloneable Propiedades Capacity Count Item[index] -- Indexer Colecciones: ArrayList Métodos Add(object) AddRange(Collection) Clear() Contains(object) IndexOf(object) Remove(object) RemoveAt(int) Sort() Reverse() GetEnumerator() 42 Colecciones: ArrayList Ejemplo ArrayList a = new ArrayList(); SampleFileManager.ReadSamples(a); IEnumerator enumerador = a.GetEnumerator(); while (enumerador.MoveNext()) { Console.WriteLine(enumerador.Current); } Colecciones: Hashtable Representa una colección de pares de clave y valor organizados en función del código hash de la clave [Serializable] public class Hashtable : IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback, ICloneable Propiedades Count IsFixedSize IsReadOnly Keys Values 43 Colecciones: Hashtable Métodos Contains() ContainsKey(object) ContainsValue(object) GetHash(object) ... Colecciones: Hashtable Ejemplo public class Languages { private static readonly Hashtable LANGUAGES; private static readonly ArrayList LANGUAGES_en = new ArrayList(); static Languages() { LANGUAGES_en.Add(new ListItem("English", "en")); LANGUAGES_en.Add(new ListItem("Spanish", "es")); LANGUAGES = new Hashtable(); LANGUAGES.Add("en", LANGUAGES_en); LANGUAGES.Add("es", LANGUAGES_es); } } 44 Generics Característica de Common Language Runtime, que permite que las clases, estructuras, interfaces y métodos tengan parámetros de tipo genérico para los tipos de datos que almacenan y manipulan Los tipos genéricos son una forma de tipos parametrizados Generics Ejemplo sin utilizar Generics public class List { private object[] elements; private int count; public void Add(object element) { if (count == elements.Length) Resize(count * 2); elements[count++] = element; } public object this[int index] { get { return elements[index]; } set { elements[index] = value; } } public int Count { get { return count; } } } 45 Generics Uso de la lista implementada sin Generics List intList = new List(); intList.Add(1); intList.Add(2); intList.Add("Three"); // Argument is boxed // Argument is boxed // Should be an error int i = (int)intList[0]; // Cast required Generics Implementación de la clase Lista utilizando Generics public class List<ItemType> { private ItemType[] elements; private int count; public void Add(ItemType element) { if (count == elements.Length) Resize(count * 2); elements[count++] = element; } public ItemType this[int index] { get { return elements[index]; } set { elements[index] = value; } } public int Count { get { return count; } } } 46 Generics Uso de la lista implementada utilizando Generics List<int> intList = new List<int>(); intList.Add(1); intList.Add(2); intList.Add("Three"); // No boxing // No boxing // Compile-time error int i = intList[0]; // No cast required Generics ¿Por qué utilizar Generics? Comprobación Rendimiento Reduce de tipos en tiempo de compilación (no boxing, no downcasts) la complejidad del código 47 Generics Los tipos genéricos pueden aplicarse a Clases, estructuras, interfaces, delegados … class Dictionary<KeyType, ValueType> {...} struct Pair<FirstType, SecondType> {...} interface IComparer<T> {...} delegate ResType Func<ArgType, ResType>(ArgType arg); << ... >> Dictionary<string, Customer> customerLookupTable; Dictionary<string, List<Order>> orderLookupTable; Dictionary<int, string> numberSpellings; Generics Los tipos genéricos pueden aplicarse a … y métodos class Array { public static T[] Create<T>(int size) { return new T[size]; } public static void Sort<T>(T[] array) { ... } } << ... >> string[] names = Array.Create<string>(3); names[0] = "Jones"; names[1] = "Anderson"; names[2] = "Williams"; Array.Sort(names); 48 Generics Restricciones Una clase base, varias interfaces, new() Se indica con la clausula where interface IComparable { int CompareTo(object obj); } class Dictionary<K, V> { public void Add(K key, V value) { << ... >> switch (((IComparable)key).CompareTo(x)) { << ... >> } } } Generics Restricciones Una clase base, varias interfaces, new() Se indica con la clausula where interface IComparable { int CompareTo(object obj); } class Dictionary<K, V> where K: IComparable { public void Add(K key, V value) { << ... >> switch (key.CompareTo(x)) { << ... >> } } } 49 Generics Restricciones Una clase base, varias interfaces, new() Se indica con la clausula where interface IComparable<T> { int CompareTo(T obj); } class Dictionary<K, V> : IDictionary<K, V> where K: IComparable<K>, V: IKeyProvider<K>, V: IPersistable, V: new() { << ... >> } Eventos Gestión de eventos es un estilo de programación dónde un objeto notifica a otro que algo de interés ha ocurrido Es un modelo de programación edición-suscripción Los eventos permiten vincular un código a la funcionalidad de un componente creado de forma independiente Los eventos son un tipo de mecanismo de “callback” 50 Eventos Los eventos son idóneos para las interfaces de usuario El usuario hace algo (hace click en un botón, mueve el ratón, cambia un valor, etc.) y el programa reacciona en consecuencia Muchos otros usos, e.g. Programar eventos basados en tiempo Notificar operaciones asíncronas completadas Notificar que se ha recibido un e-mail Notificar que se ha iniciado una sesión Web Eventos C# tiene soporte nativo para eventos Está basado en delegados Un evento es en esencia un campo que contiene un delegado Sin embargo, un usuario de una clase únicamente puede registrar delegados Sólo No puede ejecutar += y -= pueden invocar al delegado del evento 51 Eventos. Ejemplo: Component-Side Define la firma del evento como un delegado public delegate void EventHandler(object sender, EventArgs e); Define el evento y la lógica de activación public class Button { public event EventHandler Click; protected void OnClick(EventArgs e) { // This is called when button is clicked if (Click != null) Click(this, e); } } Eventos. Ejemplo: User-Side Define y registra el gestor del evento public class MyForm : Form { Button okButton; static void OkClicked(object sender, EventArgs e) { ShowMessage("You pressed the OK button"); } public MyForm() { okButton = new Button(); okButton.Caption = "OK"; okButton.Click += new EventHandler(OkClicked); } } 52