2. El lenguaje de programación C# Integración de Sistemas Diseño e implementación con .NET Introducción En C# todo es un objeto Todo hereda de System.Object y j 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, q , mientras tanto p pueden aplicárseles p optimizaciones p específicas p 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 1 Hola Mundo using System; namespace Es.UDC.DotNet.CSharpTutorial { /* * Class HelloWorld * Description: simple C# example */ class HelloWorld { #region Test code. Uncomment for testing // entry point public static void Main() { Console.WriteLine("Hello World!"); () Console.ReadLine(); } #endregion } } 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 2 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>; Namespaces using using i using using using System; S System.Collections.Generic; t C ll ti G i System.Text; System.Collections; System.IO; static void Main(string[] args) { string username; ArrayList namesCollection; using SC = System.Collections; using i SIO = S System.IO; t IO static void Main(string[] args) { string username; string filename SC.ArrayList namesCollection; filename = SIO.Path.Combine( ... ); ¿A qué namespace pertenece? 3 Sistema de Tipos Unificado Valor Primitivos int i; Enumeraciones enum State { Off, On } Estructuras struct Point { int x, y; } Referencia Raíz object String St g string st g Clases class Foo : Bar, IFoo {...} Interfaces interface IFoo : IBar {...} Arrays string[] a = new string[10]; Sistema de Tipos Unificado Dos tipos de conversiones Implícitas p Ocurren automáticamente Éxito asegurado Sin pérdida de precisión Explícitas Requieren un cast Pueden originar errores Precisión puede perderse int x = 123456; long y = x; short z = (short)x; // implicit // explicit double d = 1.2345678901234; float f = (float)d; // explicit long l = (long)d; // explicit 4 Sistema de Tipos Unificado Boxing Reserva espacio p 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 i On the stack (i boxed) o int 123 int i=123; object o=i; (i boxed) o 123 123 j int object o=i; On the heap 123 int j=(int) o; 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(); 5 Tipos predefinidos Tipo Descripción SByte Bytes con signo Byte Bytes sin signo Int16 Enteros cortos con signo UInt16 Enteros cortos sin signo Int32 UInt32 Bits Rango Alias [-128…127] sbyte 8 [0…255] byte 16 [-32.768…32.767] short 16 [0…65.535] ushort Enteros normales 32 [-2.147.483.648…2.147.483.647] int Enteros normales sin signo 32 [0…4.294.967.295] uint 8 [-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 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 6 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); } public static void Main() { // C Creating eat g a Supe SuperClass C ass instance sta ce SuperClass sc = new SuperClass(); /* Shows: * Arguments: <Default arg1> */ Console.ReadLine(); } } 7 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 public 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: h * Arguments: 1 * Arguments: 2 */ Console.ReadLine(); } 8 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 i 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.DateTime.Now.ToString() + created ); " Instance created"); } } 9 Clases. Destructores Llamado automáticamente por Garbage Collector public class LogManager { ~LogManager() { logFile.WriteLine(System.DateTime.Now.ToString() + " Instance Disposed"); logFile.Close(); } } Llamada a Garbage Collector: System.GC.Collect() 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 bli virtual i t l b bool l E Equals(object l ( bj t o) ) public virtual int GetHashCode() public virtual string ToString() protected object MemberWiseClone() public System.Type GetType() protected virtual void Finalize() p public static bool Equals(object o1, object o2) protected static bool ReferenceEquals(object o1, object o2) 10 Clases. Modificadores de acceso Con respecto al acceso, los métodos de una clase pueden ser: private: Sólo código dentro de la misma clase contenedora tiene acceso a un miembro privado protected: Miembros accesibles desde la clase que los contiene o desde clases derivadas de ésta internal: protected internal: Miembros accesibles desde el mismo assembly 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 const string public const string public const double public const double VERSION = "1.0.0"; URI = "http://" + "www.google.es"; PI = 3.14159265358979; SIN = Math.Sin(PI); //ERROR << <<...>> >> } Ejemplo de acceso desde código externo MyClass.URI 11 Clases. Campos de sólo lectura Similares a las constantes, pero… Se inicializan en tiempo p de ejecución j ((vs. compilación) p ) Evitan necesidad de recompilar clientes Pueden ser estáticas o por instancia Una vez inicializadas, no pueden modificarse public class UserFacadeDelegate { private static readonly String connectionString = Settings.Default.UserProfileDAOFactory_connectionString; private static readonly String providerInvariantName = Settings.Default.UserProfileDAOFactory_providerInvariantName; private static readonly DbProviderFactory dbProviderFactory = DbProviderFactories.GetFactory(providerInvariantName); <<...>> } 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 12 Clases. Propiedades > Definición public class UserProfileVO { private String loginName; private String encryptedPassword; atributos privados <<...>> public String LoginName { get { return loginName; } set { loginName = value; } } public String EncryptedPassword { get { return encryptedPassword; } set { encryptedPassword = value; } } propiedades <<...>> } Clases. Propiedades > Acceso static void Main(string[] args) { UserProfileDetailsVO userProfileDetailsVO = <<...>> << >> UserProfileVO userProfileVO = new UserProfileVO("jsmith", "7dj39jHT1d4gFl93", userProfileDetailsVO); //get Console.WriteLine(userProfileVO.LoginName); //set userProfileVO.LoginName = "jsuarez"; } 13 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 AbstractSQLAccountDAO : IAccountDAO { public bli abstract b t t List<AccountVO> Li t A tVO FindByUserIdentifier( Fi dB U Id tifi ( DbConnection connection, DbTransaction transaction, long userIdentifier, int startIndex, int count); <<...>> } public class CCSqlServerAccountDAO : AbstractSQLAccountDAO { public override List<AccountVO> FindByUserIdentifier( DbConnection connection, DbTransaction transaction, long userIdentifier, int startIndex, int count) { <<...>> } } 14 Clases Sealed Es una clase que no se puede extender L clases Las l sealed l d no pueden d ser abstractas b t t Todas las estructuras son sealed ¿Por qué "cerrar" una clase? Para prevenir que sea extendida de forma no intencionada Clases. Métodos Redefinición de métodos: virtual & override public bli class l P d t Product { public virtual String getReference() { return barCode; } } public class Book : Product { public override String getReference() { return ISBN; } } 15 Clases. Métodos Paso de parámetros Tipos p p primitivos se p pasan p 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; } } Estructuras (struct) Similares a las clases pero … Requisitos de almacenamiento menores P Paso por valor, l no referencia f i 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 L mayoría La í d de llos titipos bá básicos i ((excepto t string t i y object) bj t) implementados como structs Mismos miembros que una clase Modificadores de acceso válidos private (defecto), internal o public 16 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 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 l siguientes los i i t ti tipos: int, byte, sbyte, short, ushort, uint, long, ulong 17 Enumeraciones: ejemplo Declaración public enum MessageType : int { INFO = 1, WARNING = 2, ERROR = 3 } Uso MessageType messageType = MessageType.WARNING; Interfaces Similar a la definición de un contrato Pueden incluir métodos métodos, propiedades, propiedades 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 18 Interfaces Declaración public interface IUserProfileDAO { // Interface methods void Create(…) { … } void Delete(…) { … } // Interface properties UserProfile LastUser { get; set; } } Implementación public class UserProfileDAO : IUserProfileDAO { … } Operadores Aritméticos Asignación +=, -=, *=, /=, %=, ++, -- Comparación + -, +, - *, * /, / % ==, !=, <, >, <=, >= Lógicos &, &&, |, ||, ~, !, ^ 19 Operadores Obtención de información sobre tipos typeof(Type t) <expression> is <type> sizeof(Type t) as Entrada / Salida por Consola System.Console Entrada Salida Console.Read(); Console.ReadLine(); Console.ReadKey(); Console.Write(); Console.WriteLine(); System.Diagnostics Salida Debug.WriteLine(); Debug.WriteLineIf(); Trace.WriteLine(); Trace.WriteLineIf(); 20 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")); Entrada / Salida por Consola: formato Formatos predefinidos Número C D F P H Moneda Decimal Punto Fijo Porcentaje Hexadecimal Fecha S D t T F Short Date Long Date Short time Long Time Full Date 21 Sentencias Condicionales Control de Excepciones if try ...catch...finally switch throw Iterativas while do for foreach Otras lock using Sentencias condicionales. if Sintaxis General if (condition) <statementsIF> else <statementsELSE> 22 Sentencias condicionales. switch Sintaxis General ¡Obligatorio incluir break al final de cada rama! switch (i) { case 1: statements; break; case 2: statements; t t t break; default: statements; break; } switch (str) { case "ABC": statements; break; case "XYZ": statements; t t t break; default: statements; break; } Sentencias iterativas. while Sintaxis General while (condition) { <statements> } Puede incluir instrucciones break y/o continue 23 Sentencias iterativas. do...while Sintaxis General do { <statements> } while(condition) Puede incluir instrucciones break y/o continue Sentencias iterativas. for Sintaxis General for (initialize-statement; condition; increment-statement) { statements; } Puede incluir instrucciones break y/o continue 24 Sentencias iterativas. foreach Sintaxis General foreach (<Type> yp <e> in <collection>) { <statements> } Ejemplo String[] daysOfWeek = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" }; // Print the days of the week foreach (string day in daysOfWeek) { Console.WriteLine(day); } 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 ell acceso a una propiedad) i d d) Se proporcionan excepciones estándar 25 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 Sentencias. Gestión de Excepciones Sentencia throw lanza una excepción Una excepción U ió se representa t como una iinstancia t i d 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 26 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"); } Sentencias. lock Permite definir regiones críticas dentro de aplicaciones g 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 27 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 Objetos que deben limpiarse una vez usados, deberían p la interfaz System.IDisposable y p implementar Ú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 28 Sentencias. using public class MyResource : IDisposable { public void MyResource() { // Acquire valuable resource } public void Dispose() { // Release valuable resource } public void DoSomething() { // Do something } } <<...>> static void Main() { using (MyResource r = new MyResource()) { r.DoSomething(); } // r.Dispose() is called } Colecciones interface IEnumerable { IEnumerator GetEnumerator(); } interface IEnumerator { object Current { get; } bool MoveNext(); void Reset(); } 29 Colecciones: System.Collection Clases Interfaces ArrayList A Li t ICollection IC ll ti Hashtable IComparer DictionaryBase IDictionary SortedList IEnumerable Queue IEnumerator Stack IList Colecciones: ArrayList [Serializable] public class ArrayList : IList IList, ICollection, IEnumerable, ICloneable Propiedades Capacity Count Item[index] -- Indexer 30 Colecciones: ArrayList Métodos Add(object) AddRange(Collection) Clear() Contains(object) IndexOf(object) Remove(object) RemoveAt(int) Sort() Reverse() GetEnumerator() Colecciones: ArrayList ArrayList months = new ArrayList(); // Populate ArrayList... months.Add("January"); <<...>> months.Add("December"); // Access data with IEnumerator... IEnumerator enumerator = months.GetEnumerator(); while (enumerator.MoveNext()) { Console.WriteLine(enumerator.Current); } // Access data with foreach foreach (String month in months) { Console.WriteLine(month); } 31 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 Colecciones: Hashtable Métodos Contains() ContainsKey(object) ContainsValue(object) GetHash(object) ... 32 Colecciones: Hashtable Ejemplo public class Languages { private static readonly Hashtable LANGUAGES = new Hashtable(); private static readonly ArrayList LANGUAGES_en = new ArrayList(); private static readonly ArrayList LANGUAGES_es = new ArrayList(); // static constructors initializes hashtable values static Languages() { // ArrayLists stores the ListBox information LANGUAGES_en.Add(new ListItem("English", "en")); LANGUAGES_en.Add(new ListItem("Spanish", "es")); LANGUAGES_es.Add(new ListItem("Inglés", "en")); LANGUAGES_es.Add(new ListItem("Español", "es")); //Key: "en" Value: ArrayList with english information LANGUAGES.Add("en", LANGUAGES_en); //Key: "es" Value: ArrayList with spanish information LANGUAGES.Add("es", LANGUAGES_es); } } Generics Característica de Common Language Runtime, que permite q p 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 33 Generics Ejemplo sin utilizar Generics public class List { private object[] elements; private int count = 0; // array to store list elements // number of elements in the list <<...>> public void Add(object element) { if (count == elements.Length) { Resize(); } elements[count++] l t [ t ] = element; l t } /* Allows indexer access to class List */ public object this[int index] { get { return elements[index]; } set { elements[index] = value; } } } 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 34 Generics Implementación de la clase Lista utilizando Generics public class List<ItemType> { private ItemType[] elements; private int count = 0; // array to store list elements // number of elements in the list <<...>> public void Add(ItemType element) { if (count == elements.Length) { Resize(); } elements[count++] l t [ t++] = element; l t } /* Allows indexer access to class List */ public ItemType this[int index] { get { return elements[index]; } set { elements[index] = value; } } } 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 35 Generics ¿Por qué utilizar Generics? Comprobación de tipos en tiempo de compilación Rendimiento (no boxing, no downcasts) Reduce la complejidad del código Generics Los tipos genéricos pueden aplicarse a Clases,, estructuras,, interfaces,, … class Dictionary<KeyType, ValueType> {...} struct Pair<FirstType, SecondType> {...} interface IComparer<T> {...} << ... >> Dictionary<string, Customer> customerLookupTable; Dictionary<string, List<Order>> orderLookupTable; Dictionary<int, string> numberSpellings; 36 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); 37