Conceptos C#

31
Conceptos de C# Danae Aguilar Guzmán

Transcript of Conceptos C#

Conceptos de C#

Danae Aguilar Guzmán

Conceptos de C#

| 2

Contenido Introducción .................................................................................................................................................. 3

1. Delegados .......................................................................................................................................... 3

2. Eventos .............................................................................................................................................. 7

3. Delegados Genéricos ...................................................................................................................... 10

4. Métodos anónimos ......................................................................................................................... 11

5. Tipos anónimos ............................................................................................................................... 13

6. Expresiones Lambda ....................................................................................................................... 15

7. Métodos de Extensión .................................................................................................................... 16

8. Introducción a LINQ ........................................................................................................................ 18

9. Parámetros opcionales ................................................................................................................... 22

10. Argumentos nombrados ............................................................................................................. 24

11. Covarianza y Contra varianza ...................................................................................................... 26

12. Indexadores................................................................................................................................. 28

13. Atributos ..................................................................................................................................... 29

Conceptos de C#

| 3

Introducción

En esta lección repasaremos algunos conceptos del lenguaje C# los cuales son necesarios tener en

cuenta para desarrollar aplicaciones C# de cualquier tipo.

1. Delegados

El concepto de delegados permite tratar a los métodos como a objetos, asignarlos a variables y pasarlos

como parámetros. En el fondo los delegados son objetos que contienen una referencia a algún método

de algún objeto.

Los tipos delegados en .NET son objetos type-safe que hacen referencia a uno o mas métodos a la vez.

Los delegados son clases que soportan invocación asíncrona de métodos y multicasting. Mediante el uso

de delegados se implementa el mecanismo de Callback en .NET.

Type-safe. Porque conocen la cantidad de parámetros, tipo de parámetros y el tipo de retorno.

Multicasting. Porque permiten llamar a varios métodos secuencialmente.

Conceptos de C#

| 4

1. Declaración del delegado:

Al ser compilado el código los delegados se convierten en clases, por lo tanto es posible declarar un

delegado en cualquier alcance en que declararíamos una clase: anidado dentro de otra clase,

independiente a nivel global.

La manera básica de declarar un delegado es muy parecida a la declaración de un método abstracto solo

incluyendo la palabra delegate, por ejemplo:

public delegate double MetodoDelegate(double x);

En este ejemplo la clase delegado se llama MetodoDelegate (el nombre tiene el sufijo Delegate por

convención), recibe 1 parámetro de tipo double, y retorna double.

2. Algunos métodos con la firma correcta.

Algunos ejemplos de métodos que podríamos usar para instanciar al delegado son los que cumplen la

misma firma, por ejemplo:

double Cuadrado(double x) { return x * x; } static double Cubo(double x) { return x * x * x; }

Conceptos de C#

| 5

3. Crear una instancia del delegado:

Ahora crearemos instancias de nuestro delegado MetodoDelegate, la sintaxis es la siguiente:

Para un método de instancia:

Program p = new Program();

MetodoDelegate instancia1 = new MetodoDelegate(p.Cuadrado);

Para un método estático:

MetodoDelegate instancia3 = new MetodoDelegate(Math.Sqrt);

En ambos casos la sintaxis reducida consiste en asignar directamente el nombre del método a la

instancia del delegado. Ambas sintaxis son equivalentes, ej:

MetodoDelegate instancia1 = p.Cuadrado; MetodoDelegate instancia2 = Cubo; MetodoDelegate instancia3 = Math.Sqrt;

Conceptos de C#

| 6

4. Invocar a la instancia del delegado:

Para invocar al método o métodos suscritos a nuestra instancia del delegado podemos llamar al método

Invoque pasándole los parámetros que le pasaríamos al método suscrito y recibiendo el valor retornado,

ej:

double res1 = instancia1.Invoke(2.0); double res2 = instancia2.Invoke(3.0);

La sintaxis reducida es la siguiente, ambas sintaxis son equivalentes:

double res3 = instancia3(9.0);

Nota: Si se han suscrito varios métodos a la instancia del delegado, el valor de retorno será el valor

retornado por el último método que se ejecute, los demás valores de retorno de los demás métodos

serán ignorados.

Los delegados son referencias a métodos, tanto a métodos estáticos como a métodos de instancia. Esto

nos permite por ejemplo almacenar los métodos en una variable, pasarlos como parámetros a otro

método y posteriormente invocarlos dinámicamente.

Conceptos de C#

| 7

Los delegados en el fondo almacenan una lista de métodos, es posible usar el operador += para agregar

mas métodos a la lista y el operador -= para remover métodos de la lista. Los métodos de la lista serán

invocados uno por uno secuencialmente en el orden en que fueron agregados a la lista.

Los delegados con inmutables, lo que quiere decir que cada vez que se modifica el delegado por

ejemplo al usar el operador += en el fondo de crea un nuevo delegado y se deshecha el anterior.

El operador += se traduce en una llamada al método Combine de la clase Delegate y se encarga de

combinar los métodos en una lista de invocación.

El operador -= se traduce en una llamada al método Remove de la clase Delegate y se encarga de

remover los métodos de la lista de invocación.

2. Eventos

Una de las principales aplicaciones de los delegados es la creación y manejo de eventos.

Los eventos son prácticamente la otra cara del espejo de los delegados. Los delegados son interactivos

ya que el proceso inicia con la invocación del delegado y posteriormente las llamadas a los métodos.

Los eventos son reactivos, porque en el proceso primero están los métodos (event handlers) los cuales

son manejados en reacción a un evento que fue lanzado.

Conceptos de C#

| 8

Los eventos permiten notificar cuando algo sucede:

- Un método puede registrar su interés en un evento.

- Un método puede de registrar su interés en el evento.

- Los métodos registrados serán ejecutados cuando el evento ocurra.

1. Definir y lanzar eventos:

Los eventos se definen en base a delegados, la sintaxis recomendada para definir un nuevo evento es la

siguiente:

public event EventHandler Evento = delegate{};

La sintaxis es parecida a la de instanciar un delegado con la adición de la palabra reservada event

especificando que es un evento y no así una instancia de un delegado. Inicializamos el evento con un

delegado vacio para evitarnos tener que validar si es nulo cada vez que lancemos el evento.

La manera de lanzar el evento es invocarlo como se hace con un delegado. Nótese que el tipo del evento

es EventHandler, este es un delegado que acepta métodos void que reciben 2 parámetros: (object y

EventArgs), ej:

Conceptos de C#

| 9

public void FunctionQueLanzaElEvento() { Evento(this, EventArgs.Empty); }

2. Manejar o recibir eventos:

Para manejar el evento podemos crear métodos (conocidos como event handlers), estos métodos

deben cumplir la firma del evento y deben ser registrados con el evento para ser notificados cuando se

lance el evento.

La manera de registrar un event handler con un evento es agregándolo a la lista de ejecución, ej:

Publicador publicador = new Publicador(); publicador.Evento += new EventHandler(publicador_Evento);

Y definiendo el método (event handler) que se ejecutará en reacción al evento, ej:

void publicador_Evento(object sender, EventArgs e) {

//... Hacer algo }

Conceptos de C#

| 10

Los eventos no son simples instancias de delegados, mas bien son delegados que ofrecen mayor

encapsulación y protección evitando la modificación inadecuada de la lista de invocación desde

cualquier instancia externa.

En el fondo los eventos encapsulan a los delegados mediante los métodos Add y Remove mediante los

cuales suscriben y remueven las suscripciones a los métodos (event handlers) que están interesados en

ser notificados de la ejecución del evento.

Los event handlers se suscriben al evento con el operador += y se remueven las suscripciones con el

operador -= de los eventos.

3. Delegados Genéricos

El .NET Framework define los delegados Action y Func, los cuales nos ahorran el trabajo de tener que

declarar nuestros propios delegados cada vez.

Action representa los métodos que no retornan nada (los métodos void), y permite una combinación de

hasta 16 parámetros, lo cual es normalmente mas que suficiente.

Func representa los métodos que si retornan algún valor cuyo tipo se define al final de la lista genérica

de definición, por ejemplo:

Func<int, string, bool> miDelegado;

Conceptos de C#

| 11

Declara un delegado para métodos que reciben 2 parámetros (int y string) y retornan bool.

Func también soporta hasta 16 parámetros de entrada.

4. Métodos anónimos

Los métodos anónimos simplifican la sintaxis de los delegados y son utiles en casos donde el método

invocado por el delegado es invocado en un solo lugar y cuyo código es simple.

La sintaxis de los métodos anónimos ha sido mejorada con la introducción de las expresiones Lambda,

por lo cual veremos brevemente la sintaxis de los métodos anónimos:

Declaración:

Action <int> imprimirRaizCuadrada = delegate(int numero) {

Console.WriteLine(Math.Sqrt(numero)); };

Invocación:

imprimirRaizCuadrada(9);

Conceptos de C#

| 12

Los métodos anónimos en comparación con los delegados pueden mejorar la legibilidad del código ya

que se puede ver la implementación del método en el lugar donde se lo declara sin tener que crear

otros métodos y otros delegados.

No es muy recomendable usar métodos anónimos cuando la lógica del método es muy larga ya que en

este caso estaríamos haciendo que el código sea menos legible.

En el fondo el compilador creará un método para cada método anónimo por lo cual la ventaja de los

métodos anónimos es principalmente hacer el código mas limpio.

Conceptos de C#

| 13

5. Tipos anónimos

Los tipos anónimos fueron introducidos en C# 3.0 principalmente para colaborar con LINQ, permiten la

creación de clases dinámicamente al vuelo y la instanciación de objetos al mismo tiempo, estas clases no

tienen nombre por eso se las llama anónimas.

Los tipos anónimos son clases que solamente definen propiedades, de definen de la siguiente manera:

var ana = new { Nombre = "Ana", CI = 7513521, Edad = 15 }; var juan = new { Nombre = "Juan", CI = 5295124, Edad = 27 };

Como no se sabe el nombre del tipo se usa var para definirlos y se usa solamente new para

instanciarlos. En este ejemplo hemos definido objetos de un tipo anónimo pero lo que realmente

interesa son las propiedades que el tipo define las cuales en el ejemplo son Nombre, CI y Edad.

Los objetos instanciados mediante tipos anónimos se usan de manera normal, accedemos a las

propiedades definidas como siempre:

Console.WriteLine("{0} con CI {1} tiene {2} años", ana.Nombre, ana.CI, ana.Edad);

Conceptos de C#

| 14

Los tipos anónimos al ser compilados son clases a las que el compilador les da un nombre y las incluye

en el assembly, de esta manera el CLR los trata normalmente como a los tipos comunes (tipos

nomimales).

Los tipos anónimos al ser compilados incluyen solamente un constructor con los parámetros

correspondientes para inicializar todas sus propiedades, las propiedades publicas de solo lectura por lo

cual no es posible modificar el valor de las propiedades una vez instanciada la clase, campos privados de

solo lectura para cada propiedad, los métodos heredados de la clase object: ToString, Equals,

GetHashCode.

Conceptos de C#

| 15

6. Expresiones Lambda

Adiós a la sintaxis de los métodos anónimos!

Las expresiones Lambda ofrecen principalmente el beneficio de remover un nivel de llamadas en

nuestro código. Es decir, lo que normalmente tienes que hacer es crear un método, darle un nombre y

pasar ese nombre a un delegado, esto es útil cuando usas ese código en varios lugares. Pero cuando solo

usas ese código en un lugar entonces es preferible usar expresiones Lambda que te permiten poner el

código directamente sin tener que crear un método y darle un nombre y asignarlo a un delegado.

El concepto es el mismo que el del los métodos anónimos (C# 2.0), las expresiones Lambda fueron

definidas en C# 3.0 y es recomendado usar la nueva sintaxis de expresiones Lambda en vez de la antigua

sintaxis de los métodos anónimos ya que las expresiones Lambda hacen el código mas fácil de escribir,

de leer y de mantener.

Conceptos de C#

| 16

7. Métodos de Extensión

Los métodos de extensión nos permiten agregar nuevos métodos principalmente a clases de las cuales

no somos autores y no tenemos el código. Estos métodos pueden estar definidos en un assembly

distinto al de la clase original. De esta manera muchos métodos han sido agregados a las clases antiguas

del BCL por ejemplo los métodos para manejar colecciones con expresiones Lambda.

Nos damos cuenta que un método es de extensión cuando el primer parámetro que recibe tiene la

palabra this al inicio, entonces este parámetro no espera que se le pase ningún argumento solo indica a

que tipo esta extendiendo el método.

Para definir un método anónimo debemos:

1. Declararlo en una clase static.

2. El método debe ser static también.

3. El primer parámetro debe ser del tipo al que estamos extendiendo por ejemplo string, y debe

tener la palabra this al inicio.

static class Extensiones { public static string InvertirCadena(this string cadena) { char[] caracteres = cadena.ToCharArray(); Array.Reverse(caracteres); string cadenaInversa = new string(caracteres); return cadenaInversa; } }

Conceptos de C#

| 17

Una vez definido el método de extensión debe estar al alcance del código donde se quiere invocar, ya

sea en el mismo assembly o en un assembly que agregamos como referencia. Entonces podemos usar el

nuevo método como si fuera parte de la clase:

string cadena = "!odnumaloH"; Console.WriteLine(cadena.InvertirCadena());

Lo cual es lo mismo que hacer una llamada al método estático definido en la clase:

Console.WriteLine(Extensiones.InvertirCadena(cadena));

Conceptos de C#

| 18

En resumen los métodos de extensión nos permiten extender la funcionalidad de tipos previamente

compilados lo cual es útil especialmente si no tenemos el código fuente para manipularlo y

recompilarlo.

Los métodos de extensión no pueden ser usados para redefinir y reemplazar métodos que ya existen en

la clase.

Deben ser definidos en una clase estática cuyo nombre no es relevante.

8. Introducción a LINQ

LINQ ofrece una sintaxis conveniente para realizar consultas sobre colecciones de datos, usando LINQ

podemos fácilmente filtrar ítems, ordenarlos, obtener una proyección de un conjunto de los ítems y

mucho más.

LINQ permite hacer consultas sobre cualquier colección que implemente IEnumerable<T>, ya sea un

arreglo, una lista, XML DOM, fuentes de datos remotas como tablas en un servidor SQL.

La declaración de una consulta LINQ tiene una sintaxis parecida al lenguaje de consultas SQL pero en

LINQ primero especificamos de donde obtendremos los resultados de la consulta mediante las palabras

reservadas from in. Luego podemos o no especificar una condición con where, y posteriormente

especificamos lo que deseamos seleccionar con select.

Conceptos de C#

| 19

En este ejemplo declaramos la consulta para seleccionar los empleados cuyo apellido empiece con la

letra A:

IEnumerable<Empleado> consultaEmpleados = from e in empleados where e.Apellido.StartsWith("A") select e;

Tener este código no quiere decir que tengamos el resultado de la consulta. LINQ no ejecuta la consulta

hasta que se accede al resultado ya sea recorriéndolo con un foreach o mediante la llamada a algún

método como Count por ejemplo.

foreach (var empleado in consultaEmpleados) { Console.WriteLine(empleado.Apellido); }

Aquí es donde realmente se ejecuta la consulta, también podría ser aquí:

int cantidad = consultaEmpleados.Count();

Conceptos de C#

| 20

LINQ permite obtener los resultados de una consulta en un orden especifico, esto se consigue

especificando el comando orderby antes de select. En el ejemplo retornamos los empleados en orden

alfabético de apellidos.

Para evitar obtener resultados repetidos podemos hacer uso del método Distinct() aplicado sobre la

consulta. Es importante notar que al aplicar la ejecución de cualquier método como Distinct() sobre la

consulta se esta realizando la ejecución de la misma.

La manera de realizar agrupaciones con LINQ es mediante el comando group by, el cual nos retornara

una estructura de tipo IGrouping<T,S> donde T es el tipo del campo por el cual estamos agrupando y S

es el tipo de los objetos agrupados. Entonces tendremos una colección de IGrouping<T, S> a la cual

podemos iterar mediante dos foreach anidados.

Conceptos de C#

| 21

LINQ realiza consultas sobre tipos IEnumerable o IEnumerable<T>, por lo cual si alguna colección no es

de este tipo primero tendremos que convertirla si queremos usar LINQ sobre ella.

LINQ tiene ejecución diferida, lo cual quiere decir que la declaración de la consulta en realidad no la

ejecuta solo la define, la ejecución se realiza la primera vez que se trata de acceder a los resultados.

LINQ nos da el beneficio de verificar los tipos en tiempo de compilación lo cual evita errores posteriores.

Además nos permite tener un mismo modelo de consulta consistente entre diferentes y diversas

fuentes de datos como listas, tablas, XML y mas.

Conceptos de C#

| 22

9. Parámetros opcionales

Los parámetros opcionales son una nueva característica de C# 4.0 que nos permite especificar un valor

por defecto para los parámetros que no sean obligatorios, de esta manera cuando llamemos al método

podemos omitir estos parámetros y ellos tomaran el valor por defecto.

Los parámetros opcionales nos ahorran el trabajo de definir diversas sobrecargas de un método en el

cual la única diferencia es la cantidad de parámetros.

La manera de especificar que un parámetro de un método es opcional es tan sencilla como asignarle un

valor por defecto en el mismo lugar de su declaración:

public Producto(string nombre, decimal? precio = null) { … }

Entonces podemos usar el método ya sea pasándole el parámetro u omitiendo el mismo:

Producto producto1 = new Producto("Chocolate blanco", 9); Producto producto2 = new Producto("Chocolate");

Conceptos de C#

| 23

Uno de los principales objetivos de los parámetros opcionales es el de facilitar la interacción con

componentes COM, pero como hemos visto también nos ahorra tener que escribir múltiples

sobrecargas del mismo método.

Los parámetros opcionales deben declarar un valor constante por defecto que será usado en caso de

que el parámetro no sea especificado en la llamada al método.

Deben ser especificados siempre al final del método después de los parámetros obligatorios excepto en

el caso de params que va al final.

Los parámetros opcionales no pueden ser out ni ref.

Conceptos de C#

| 24

10. Argumentos nombrados

Esta característica nueva de C# 4.0 va de la mano de los parámetros opcionales, permite cambiar el

orden de los argumentos cuando se llama a un método, para esto se debe especificar el nombre del

parámetro al que se refiere nuestro argumento seguido de dos puntos : y el valor. Esto es útil cuando se

tiene varios parámetros opcionales del mismo tipo en un método.

También facilita la comprensión especificando a que parámetro se refiere cada argumento en la llamada

a un método.

Los argumetos nombrados pueden ser usados con ref y out, para esto solo basta especificar ref u out

antes del valor del argumento nombrado y proceder de la manera normal:

Conceptos de C#

| 25

int numero; bool success = int.TryParse("10", result: out numero);

Los argumentos nombrados nos permiten especificar los parámetros sin importar su posición

basándonos en su nombre.

Hace más legible el código de las llamadas a los métodos ya que el programador puede saber que

representa cada argumento.

Cuando se usan argumentos nombrados se los debe especificar después de los argumentos posicionales

normales.

Conceptos de C#

| 26

11. Covarianza y Contra varianza

El concepto de covarianza y contra varianza no es algo nuevo, sin embargo desde la versión 4.0 de C# lo

nuevo es el soporte de covarianza y contra varianza en colecciones genéricos lo cual antes no era

posible.

La varianza y contra varianza están relacionadas a la conversión implícita de un tipo hijo a un tipo padre,

por lo cual es posible asignar un objeto de tipo Estudiante y almacenarlo en una variable de tipo

Persona.

Ahora también es posible realizar esta operación en colecciones genéricas como las definidas en este

ejemplo.

Conceptos de C#

| 27

La covarianza permite agregar colecciones de un tipo hijo por ejemplo de Estudiante a una colección

definida con un tipo padre por ejemplo Persona. Esto parece algo obvio pero no había sido permitido

antes de C# 4.0

La contra varianza nos permite usar métodos definidos para un tipo padre por ejemplo Persona en

colecciones genéricas definidas para un tipo hijo por ejemplo Estudiante. Igualmente esta operación

parece obvia ya que un Estudiante puede ser tratado como Persona debido a la herencia, pero antes de

C# 4.0 esto no era posible en colecciones genéricas como la del ejemplo.

Conceptos de C#

| 28

12. Indexadores

Los indexadores permiten acceder a colecciones declaradas dentro de nuestras clases mediante uno o

más parámetros usando una sintaxis similar a la de los arreglos.

Los indexadores son propiedades que se definen de manera especial y reciben parámetros, para

empezar su nombre es this y en vez de usar paréntesis para los parámetros (como los hacen los

métodos) se usa corchetes.

class Semana { private string[] dias = {"Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"}; public string this[int numDia] // indexer { get { return dias[numDia]; } set { dias[numDia] = value; } } }

La manera de usar los indexadores es pasando los argumentos entre corchetes:

Semana semana = new Semana(); Console.WriteLine(semana[0]);

Conceptos de C#

| 29

Los indexadores permiten acceder a elementos de una colección declarada en una clase o struct. Son

similares a las propiedades pero reciben parámetros que normalmente se usan como un índice.

Se declaran con el nombre this y los parámetros se declaran entre corchetes [], no es obligatorio recibir

solo un parámetro, pueden ser mas.

13. Atributos

Conceptos de C#

| 30

Los atributos o atributos personalizados (custom attributes) son una manera de asociar información

adicional a nuestros tipos, esta información es emitida por el compilador en la metadata del módulo.

Muchos atributos no tienen significado para el compilador pero de todos modos los agrega en la

metadata. Los atributos son útiles para los programadores en tiempo de diseño y de ejecución.

Varios frameworks usan atributos para identificar los tipos y métodos, por ejemplo [Serializable]

identifica a una clase como apta para ser serializada, [TestMethod] especifica que un método define un

test en la aplicación.

La manera de crear nuestros propios atributos personalizados es creando una clase que herede de

Attribute, por convención nuestra clase llevara el sufijo Attribute en su nombre:

public class CommandLineAliasAttribute : Attribute { public CommandLineAliasAttribute(string alias) { Alias = alias; } public string Alias { get; set; } }

Nuestra clase atributo puede tener propiedades que guarden la información que nos interesa. Una vez

definida nuestra clase atributo podemos usarla instanciándola entre corchertes sobre el tipo que

queremos marcar por nuestro atributo:

class CommandLineInfo { [CommandLineAlias("?")] public bool Ayuda { get; set; } // ... }

Es importante notar que al momento de usar el atributo no es necesario usar el sufijo Attribute con el

que nombramos a nuestra clase, de esta manera reducimos el largo del nombre lo cual es mas cómodo y

hace que el código sea mas limpio.

Conceptos de C#

| 31

Los atributos tienen como objetivo principal agregar información personalizada a elementos del código.

Para implementarlos debemos derivar de la clase Attribute, por convención el nombre debe llevar el

sufijo Attribute que no es necesario a la hora de usar el atributo. Los atributos se aplican

instanciándolos entre corchetes sobre el elemento al cual queremos aplicarlo.