Sie sind auf Seite 1von 67

Captulo 1. Introduccin 1.1.

El lenguaje C#
1.1.1. Introduccin
Los primeros rumores de que Microsoft estaba desarrollando un nuevo lenguaje de programacin surgieron en 1998, haciendo referencia a un lenguaje que entonces llamaban COOL y que decan era muy similar a Java. En junio de 2000, Microsoft despej todas las dudas liberando la especificacin de un nuevo lenguaje llamado C#. A esto le sigui rpidamente la primera versin de prueba del entorno de desarrollo estndar (SDK) .Net, que inclua un compilador de C#. El nuevo lenguaje estaba diseado por Anders Hejlsberg ( creador de Turbo Pascal y arquitecto de Delphi ), Scott Wiltamuth y Peter Golde. Entonces describieron el lenguaje como "...simple, moderno, orientado a objetos, de tipado seguro y con una fuerte herencia de C/C++".

1.1.2. Programacin basada en componentes


En los ltimos 10 aos se han asentado diferentes tcnicas de programacin como son la orientacin a objetos, la programacin basada en interfaces o los componentes. A pesar de sto, los lenguajes de programacin siempre han ido un paso por detrs de las mejores prcticas de programacin del momento. Como resultado, los programadores tienden a depender de cdigo especfico, usar convenciones, o simplemente a no usar las nuevas tcnicas. Por ejemplo, C++ soporta orientacin a objetos, pero no tiene el concepto formal de interfaces. Los programadores entonces recurren a clases abstractas para simular programacin basada en interfaces, mientras que utilizan modelos externos de componentes, como COM y CORBA para obtener los beneficios de la programacin orientada a componentes. Aunque Java est un paso adelante de C++ al proporcionar soporte a nivel de lenguaje para interfaces y paquetes (entre otras cosas), le sigue faltando soporte para construir y mantener a la largo del tiempo completos sistemas basados en componentes (en los que uno necesita desarrollar, desplegar, interconectar y manejar distintas versiones en un extenso periodo de tiempo). Esto no significa que la comunidad Java no haya construido tales sistemas, simplemente que las necesidades derivadas de la implementacin de tales sistemas se han conseguido a travs de convenciones de notacin y cdigo propio, no a travs de una caracterstica del lenguaje. Por otra parte, el lenguaje C# se ha construido suponiendo que los modernos sistemas de software se construyen usando componentes. Por lo tanto, C# proporciona soporte a nivel de lenguaje para los constructores bsicos de los componentes, como puden ser propiedades, mtodos y eventos. Esto no significa que todo esto no se haya hecho antes, lenguajes como LISP o Smalltak hacan cosas parecidas, pero con un gran coste. C#

tiene mecanismos para permitir al mismo tiempo un orientacin a componentes y un gran rendimiento.

1.1.3. Orientacin a objetos


Adems del soporte para desarrollo de software basado en componentes, C# es un lenguaje completamente orientado a objetos, que implementa casi todo los conceptos y abstracciones presentes en C++ y Java. Como es de esperar en un lenguaje orientado a objetos, C# implementa conceptos como herencia, encapsulacin, polimorfismo y programacin basada en interfaces. Adems soporta las construcciones tpicas de C++ y Java, como clases, estructuras, interfaces y enumeraciones, as como algunas construcciones nuevas, como los delegados, que son parecidos a los punteros a funciones de C++, o los atributos, lo cual permite aadir metainformacin al cdigo. C# consigue aunar orientacin a objetos y rendimiento. Algunos lenguajes, como Smalltalk, se basan en que "todo es un objetos". Esta aproximacin tiene la ventaja de una completa orientacin a objetos, pero tiene la desventaja de ser muy ineficiente. Para mejorar el rendimiento, otros lenguajes, como Java, separan el sistema de tipos en tipos primitivos y todo el resto, dando lugar a mejor rendimiento en los tipos primitivos, pero en una separacin a veces molesta entre tipos primitivos y tipos definidos por el usuario. En C# se han aunado ambas aproximaciones presentando lo que se llama un sistema unificado de tipos, en el que todos los tipos, incluso los primitivos, derivan de un tipo objeto comn, a la vez que permite el uso de optimizaciones para tipos primitivos.

1.1.4. Librera del lenguaje


Contrariamente a la mayora de lenguajes, C# no incluye una librera especfica, sino que utiliza la librera de clases de la plataforma .NET para todas sus necesidades, desde utilizacin de la consola hasta la programacin multihilo o el cifrado de seguridad.

1.1.5. Estandarizacin
Adems de los mritos tcnicos, uno de las razones del xito de C# y la plataforma .NET ha sido por el proceso de estandarizacin que Micrsoft ha seguido (y que ha sorprendido a ms de uno). Micrsoft, en lugar de reservarse todos los derechos sobre el lenguaje y la plataforma, ha publicado las especificaciones del lenguaje y de la plataforma, que han sido posteriormente revisadas y ratificadas por la Asociacin Europea de Fabricantes de Computadoras (ECMA). Esta especifcacin (que se puede descargar libremente de aqu) permite la implementacin del lenguaje C# y de la plataforma .NET por terceros, incluso en entornos distintos de Windows.

1.1.6. C# frente a Java


C# y Java son lenguajes similares, de sintaxis basada en C/C++, orientados a objetos, y ambos incluyen las caractersticas ms importantes de los lenguajes modernos, como son la gestin automtica de memoria y la compilacin a cdigo intermedio. Pero por

supuesto, tambin hay diferencias. Una de las diferencias ms importantes es que C# es mucho ms cercano a C++ en cuanto a diseo se refiere. C# toma casi todos sus operadores, palabras reservadas y expresiones directamente de C++. Tambin se han mantenido algunas caractersticas que en Java se han desestimado. Por ejemplo las enumeraciones. No hay enumeraciones en Java y sin embargo era un concepto muy usado en C/C++. En C# se han mantenido las enumeraciones, y se han adaptado al nuevo lenguaje, de forma que ahora las enumeraciones no son simplemente enteros, sino que son tipos de tipado seguro que derivan de System.Enum en la librera de clases base. Una enumeracin de tipo "ej1" no se puede cambiar con una enumeracin de tipo "ej2" sin una conversin. Otra caracterstica que no est presente en Java es la posibilidad de trabajar directamente con direcciones de memoria. Si bien tanto Java como .NET proporcionan gestin automtica de memoria, en C# es posible usar lo que se denomina "cdigo no seguro". Cuando se usa cdigo no seguro en C# es posible operar con punteros de forma muy similar a como se hara en C/C++, pero el cdigo que utiliza punteros se queda marcado como no seguro y no se ejecuta en entornos en los que no tiene permisos.

1.1.7. C# frente a C++


Puesto que C# se ejecuta en una mquina virtual, sta se hace cargo de la gestin de memoria y por lo tanto el uso de punteros es mucho menos importante en C# que en C+ +. C# tambin es mucho ms orientado a objetos, hasta el punto de que todos los tipos usados derivan en ltima instancia el tipo 'object'. Adems, muchos tipos se usan de forma distinta. Por ejemplo, en C# se comprueban los lmites de los arrays antes de usarlos, evitando as que se pueda escribir pasado el final del vector. Al igual que Java, C# renuncia a la idea de herencia mltiple de clases presente en C++. Sin embargo, referido a clases, C# implemente 'propiedades' del tipo de las que existen en Visual Basic, y los mtodos de las clases son accedidos mediante '.' en lugar de '::'.

1.1.8. Porqu C#?


La plataforma .NET acepta varios lenguajes. Por ahora, C#, Visual Basic, C++ gestionado, Nemerle, FORTRAN, Java, Python, etc. , y con capacidad para aceptar prcticamente cualquier lenguaje. Entonces la pregunta es, porqu se eligi C# en lugar de cualquier otro lenguaje?. La razn fundamental es que C# se dise para la plataforma .NET y es capaz de utilizar todo su potencial. Tambin es cierto que es un lenguaje "limpio" en el sentido de que al no tener que proporcionar compatibilidad hacia detrs se ha tenido ms libertad en el diseo y se ha puesto especial incapi en la simplicidad. Por ejemplo, en C# hay un tipo de clase y siempre se le aplica el recolector de basura mientras que en C++ gestionado hay dos tipos de clases, una a las que se le aplica el recolector y otra a la que no.

1.2. Primer ejemplo

Para empezar con C#, que mejor que con un ejemplo bsico para entender la estructura bsica de un programa en C# y empezar a conocer las caractersticas del lenguaje. El ejemplo sera el siguiente:
//Declaracin del espacio de nombres using System; //Clase de nuestro programa principal class PrimerEjemplo { public static void Main() { // Escribir a la consola Console.WriteLine ("Bienvenido al tutorial de C# de M-H"); } }

Todo programa que escribamos en C# va a tener una estructura similar a esta en la que declararemos uno/varios espacios de nombres a utilizar (System), una clase y el mtodo "Main" de esa clase con las sentencias de nuestro programa. Por cierto, todos los archivos en C# llevan la extensin .cs (no hay ficheros de cabecera ni nada similar ). Una vez ya visto el primer ejemplo, para compilarlo habra que utilizar mcs (mono compiler suite), que es el compilador de mono de C#, implementado segn las especificaciones del lenguaje segn ECMA-334, que ser el encargado de generar los ejecutables en cdigo intermedio (CIL) que posteriormente tendr que ser ejecutado por mono. Para ello se procedera de la siguiente forma:
# mcs ejemplo.cs # mono ejemplo.exe

[1] Dando el siguiente resultado:


Bienvenido al tutorial de C# de M-H

Sobre todo si ests en entornos Windows tal vez querrs que la consola no se cierre automticamente. Entonces tendrs que escribir Console.Read() detrs de la ltima sentencia para que el programa espere a que pulses una tecla para poder cerrarse. Esto se hace extensible a todos los ejemplos de este tutorial. En nuestro ejemplo, System es un espacio de nombres y con l le estaremos diciendo que podamos usar todos las clases asociadas a ese espacio de nombres, en nuestro caso la clase Console con el mtodo WriteLine que es el que se encarga de escribir por pantalla el mensaje que queramos mostrar. La clase PrimerEjemplo es la que va a contener la definicin de datos y mtodos que va a usar nuestro programa al ejecutarse. Adems de clases veremos que se pueden definir

otros tipos diferentes de elementos tales como estructuras e interfaces con los mtodos asociados a estos tipos. Al utilizar el mtodo Main le estaremos diciendo que nuestro programa empieza ah y tiene los modificadores static (slo se va a usar en esa clase) y void diciendole que nuestro mtodo no va a devolver nada. Ya nicamente queda mostrar por pantalla el resultado, esto se hace utilizando la clase Console y el mtodo asociado WriteLine que es el que muestra por pantalla el mensaje de bienvenido. Para hacer referencia a los mtodos en WriteLine en C# se va a hacer con el operador ".", en diferencia a lo que puede ser en C++ el "::". Para los comentarios se utiliza tanto // como /* esto es un comentario */ al ms puro estilo de C++ y que todas las sentencias tienen que acabar con ; y los delimitadores de bloque son { y }.

Captulo 2. Tipos 2.1. Tipos


2.1.1. Importancia de los tipos de datos
Los tipos son la base de cualquier programa. Un tipo no es ms que un espacio en memoria en el que se almacena informacin, ya sean nmeros, palabras o tu fecha de nacimiento. Los tipos de datos son especialmente importantes en C# porque es un lenguaje con informacin de tipos. Esto significa que, en todas las operaciones, el compilador comprueba los tipos para ver su compatibilidad. Las operaciones no vlidas no se compilan. De esta forma se evitan muchos errores y se consigue una mayor fiabilidad

2.1.2. Tipos en C#
En C# los tipos bsicos no son ms que sinnimos para tipos predefinidos en la librera base de la plataforma Mono/.NET . As, el tipo entero int, no es ms que un sinnimo de System.Int32 . Los tipos de C# estn divididos en dos grandes categoras: tipos por valor y tipos por referencia. Existe adems una tercera categora, los punteros (disponibles solo cuando se usa cdigo no seguro), que se discutirn ms adelante. Los tipos por valor difieren de los tipos por referencia en que las variables de los tipos por valor contienen directamente su valor, mientras que las variables de los tipos por referencia almacenan referencias a objetos. Con los tipos por referencia, es posible que dos variables se refieran al mismo objeto, y por tanto es posible que las operaciones sobre una variable afecten al objeto al que hace referencia otra variable. Con los tipos

por valor, cada variable tienen su propia copia de los datos, y las operaciones sobre una no afectar a la otra.

2.2. Tipos por valor


2.2.1. Tipos por valor
Como hemos comentado, el trmino tipo por valor indica que las variables de esos tipos contienen directamente su valor. De esta forma, los tipos por valor actan de forma muy parecida a los tipos de datos de otros lenguajes de programacin como C++. Los tipos por valor se conocen tambin como tipos sencillos Tabla 2-1. Tipos por valor Nombre para la plataforma Mono/.NET System.Boolean System.Byte System.SByte System.Int16 System.Uint16 System.Int32 System.Uint32 System.Int64 System.Uint64 System.Single Con Bytes signo? utilizados No No Si Si No Si No Si No Si Si 1 1 1 2 2 4 4 8 8 4 8

Tipo C# bool byte sbyte short ushort int uint long ulong float

Rango verdadero o falso 0 hasta 255 -128 hasta 127 -32.768 hasta 32.767 0 hasta 65535 -2.147.483.648 hasta 2.147.483.647 0 hasta 4.394.967.395 -9.223.372.036.854.775.808 hasta 9.223.372.036.854.775.807 0 hasta 18446744073709551615 Approximadamente 1.5E-45 hasta 3.4E38 con 7 cifras significativas Approximadamente 5.0E-324 hasta 1.7E308 con 7 cifras significativas Approximadamente 1.0E-28 hasta 7.9E28 con 28 29 cifras significativas Cualquier carcter Unicode (16 bits)

double System.Double

decimal System.Decimal char System.Char

Si

12 2

2.2.2. Enteros
Los tipos que sirven para almacenar nmeros enteros son: byte, sbyte. short, ushort, int, uint, long y ulong. Como se aprecia en la tabla, C# define versiones con y sin signo para tipos con los mismo bytes utilizados. La diferencia entre enteros con signo y sin signo radica en el modo de interpretar el bit de nivel superior del entero. Si se especifica un

entero con signo, el compilador entender que el primer bit indica el signo: 0 si es positivo, 1 si es negativo. Sin embargo, los enteros sin signo, ese bit se puede utilizar para almacen el nmero y as se consigue que los enteros sin signo puedan almacenar nmeros el doble de grandes que los enteros con signo. Probablemente el tipo ms utilizado es el int, pus se utiliza para controlar matrices, inidizar arreglos adems de las operaciones normales con enteros. Adems, se trata de un entero de tamao medio: ms pequeo que long y ulong, pero ms grande que byte, sbyte, short y ushort. El siguiente ejemplo muestra la declaracin y uso de algunos tipos enteros calculando el nmero de segundos en una hora, dia y en un ao.
using System; class Enteros{ public static void Main() { int Minuto = 60; //segundos por minuto int Hora = Minuto*60; int Dia = Hora*24; long Anio = Dia*365; Console.WriteLine("Segundos en un dia: {0}", Dia); Console.WriteLine("Segundos en un ao: {0}", Anio);

} }

De nuevo hemos usado el mtodo Console.WriteLine para imprimir los resultados por la consola. El identificador {0} dentro de la cadena de texto indica que se sustituye {0} por el primer argumento. si hubiera ms de un argumento, se seguira con {1}, y as sucesivamente. Por ejemplo, las dos lneas que utilizan Console.WriteLine se pueden simplificar as:
Console.WriteLine("En un dia: {0}; en un ao: {1}", Dia, Anio );

2.2.3. Tipos de coma flotante


Los tipos de coma flotante sirven para representar a nmeros con parte fraccionaria. La representacin por supuesto puede no ser exacta, bien por errores de la mquina, bien porque el nmero de decimales que se puede alojar es finito. Existen dos clases de tipos de punto flotante, float y double. De los dos, el ms usado es double, pus es el valor que devuelven la mayora de las funciones matemticas de la librera base. El siguiente ejemplo calcula la raz cuadrada y el logaritmo de dos:
using System;

class Flotante{ public static void Main() { int a = 2; double log2 = Math.Log(2); double raiz2 = Math.Sqrt(2); Console.WriteLine("El logaritmo de dos es {0}", log2 ); Console.WriteLine("La raiz de dos es {0}", raiz2 ); } }

y la salida ser la siguiente:


El logaritmo de dos es 0.693147180559945 La raiz de dos es 1.4142135623731

si intentamos cambiar el tipo de log2 a otro de menos precisin, como float o int, el compilador protestar. Esto se debe, como hemos dicho a que el valor devuelto por Math.Log() es de tipo double y si se quiere convertir a float, pus se perdern datos. Lo mismo ocurre con la mayora de los miembros de la clase Math, como Math.Sin(), Math.Tan(), etc.

2.2.4. El tipo decimal


El tipo decimal es un tipo "nuevo" en el sentido de que no tiene equivalente en C/C++. Es muy parecido a los tipo de coma flotante float y double. En la aritmtica de los tipos de coma flotante ordinarios, se pueden producir leves errores de redondeo. El tipo decimal elimina estos errores y puede representar correctamente hasta 28 lugares decimales. Esta capacidad para representar valores decimales sin errores de redondeo lo hace especialmente eficaz para clculos monetarios.

2.2.5. El tipo bool


El tipo bool sirve para expresar los valores verdadero/falso, que en C# se muestran con las palabras reservadas true y false. En C#, por ejemplo, una instruccin if solo puede estar gobernada por un valor bool, no como en C/C++, que lo puede estar tambin por un entero. De esta forma se ayuda a eliminar el error tan frecuente en programadores de C/C++ cuando usa "=" en lugar de "==". En definitiva, la inclusin del tipo bool en el lenguaje ayuda a la claridad del cdigo y evita algunos errores muy comunes. El siguiente ejemplo, muestra algunos usos del tipo bool:
using System; class Booleano{ public static void Main() {

bool b; b = true; Console.WriteLine("b es {0}", b); if(b) { Console.WriteLine("esto saldr"); } b = false; if(b) { Console.WriteLine("esto no saldr"); } } } Console.WriteLine("2==2 es {0}", 2==2);

En la ltima lnea se muesta que el operador "==" tambin devuele un valor booleano. El resultado debera ser el siguiente:
b es True esto saldr 2==2 es True

2.2.6. Tipo arreglo


En C# se pueden construir arreglos de prcticamente cualquier tipo de dato. Los arreglos, tambin llamados vectores o arrays, no son ms que una sucesin de datos. Por ejemplo, el concepto matemtico de vector es una sucesin de nmeros y por lo tanto es un arreglo unidimensional. As, podemos construir arreglos de objetos, de cadenas de texto, y, por supuesto, arreglos de enteros:
using System; class Arreglo{ public static void Main() { int[] arr = new int[3]; arr[0] = 1; arr[1] = 2; arr[2] = 3; } } Console.WriteLine( arr[1] );

En este ejemplo se crea un arreglo arr unidimensional con capacidad para 3 enteros, y luego se le asigna a cada valor un entero distinto (ntese que se comienza a contar a partir de 0 ). Existe una forma ms corta para declarar el arreglo y asignarle las variables:

int[] arr = {1,2,3};

Tambin se pueden crear arreglos bidimensionales ( de la misma forma para ms dimensiones). En ese caso la sintaxis para declarar un arreglo bidimensional de enterios ser
int[,] arr

en contraposicin a C/C++, en el que se declarara como


int[][] arr

De esta forma, un arreglo bidimensional se declarara y utilizara de la siguiente forma:


using System; class Arreglo2{ public static void Main() { int[,] arr = new int[2,2]; arr[0,0] = 1; arr[1,0] = 2; arr[0,1] = 3; arr[1,1] = 4; Console.WriteLine( arr[1,1] ); } }

que, igual que el ejemplo anterior, podamos hacer declarado todo el arreglo de la siguiente forma:
int[,] arr = {{1,2},{3,4}};

Se hablar con ms detalle sobre arreglos en la seccin

2.2.7. El tipo char


El tipo char permite almacenar un carcter en formato unicode de 16 bits, lo que nos garantiza que los acentos se ven de forma adecuada y adems permite la representacin de otros alfabetos, como el griego, cirlico, etc. Para introducir un carcter se utilizan comillas simples, de forma de declarar un carcter sigue la estructura
char letra = 'a'

De igual forma que hemos hecho con los enteros, es posible declarar un arreglo de char
char[] cadena = {'a', 'b', 'c' };

aunque para almacenar algunas cadenas de caracteres, como las palabras, es ms indicado usar el tipo string .

Captulo 3. Estructuras de control 3.1. Estructuras de control


En este captulo se describen algunas sentencias que sirven para controlar la ejecucin de un programa. Algunas son muy similares a las existentes en otros lenguajes, como las sentencias if, for, while, etc. y otras, como foreach, throw o continue, son algo ms especficas.

3.1.1. Instruccin if
Esta sentencia sirve para ejecutar unas instrucciones en caso de que se cumpla determinada condicin. La forma completa de la instruccin if es
if( condicin ) { instruccin1; instruccin2; ... } else { instruccin1; instruccin2; ... }

donde la clusula else es opcional. Si la condicin es verdadera, se ejecutarn las instrucciones dentro del bloque if, mientras que si es falsa, se ejecutar el bloque else. El valor que controla la sentencia if debe ser de tipo bool. El siguiente ejemplo
//programa que determina si un valor es positivo o negativo using System; class InstruccionIf{ public static void Main() { double d; Console.WriteLine("Introduce un numero"); d = Double.Parse( Console.ReadLine() ); if( d>0 ) { Console.WriteLine("El numero {0} es positivo", d); } else { Console.WriteLine("El numero {0} es negativo", d); } } }

te pide que introduzcas un nmero y dependiendo de si se cumple que dicho nmero es mayor que cero (condicin), se ejecuta un bloque u otro. La sentencia d = Double.Parse( Console.ReadLine() ); tal vez requiera algo de explicacin adicional. En realidad, con Console.ReadLine() estamos leyendo lo que el usuario introduce por pantalla, que es una cadena de caractres, y con Double.Parse lo que hacemos es interpretar esa cadena de caractres y conventirna en un tipo numrico double, de forma que d tendr el valor del nmero que introduzcamos por la consola. Las intrucciones if se pueden anidar, y existe tambin una extensin de la sentencia if, la sentencia if-else-if. Su formato es el siguiente:
if( condicion1 ) { instrucciones; } else if( condicion2 ) { instrucciones; } ... else { instrucciones; }

Las instrucciones condicionales se evalan de arriba a abajo. Tan pronto como se encuentra una condicin true, se ejecuta la instruccin asociada con ella, y el resto de la escalera se omite. Si ninguna de las condiciones es true, se ejecutar la ltima instruccin else. La ltima instruccin else acta como condicin predeterminada, es decir, si no funciona ninguna de las otras pruebas condicionaes, se realiza esta ltima instruccin. Si no existe esta instruccin else final y el resto de de las condiciones son falsas, entonces no se realizar ninguna accin. El siguiente ejemplo
using System; class IfElseIf{ public static void Main() { string opcion; Console.WriteLine("Elija una opcin (si/no)"); opcion = Console.ReadLine(); if( opcion=="si" ) { Console.WriteLine( "Muy bien, ha elegido si" ); } else if( opcion=="no" ) { Console.WriteLine( "Ha elegido no" ); } else{ Console.WriteLine("No entiendo lo que ha escrito"); } }

le pide al usuario que elija una opcin si/no y la procesa usando una estructura if-else-if. Si la opcin no es ni "si" ni "no", entonces se ejecuta la sentencia else por defecto, que imprime por pantalla el mensaje "No entiendo lo que ha escrito"

3.1.2. Instruccin switch


La instruccin switch es muy parecida a la estructura if-else-if, slo que permite seleccionar entre varias alternativas de una manera ms cmoda. Funciona de la siguiente manera: el valor de una expresin se prueba sucesivamente con una lista de constantes. Cuando se encuentra una coincidencia, se ejecuta la secuencia de instrucciones asociada con esa coincidencia. La forma general de la instruccin switch es la siguiente:
switch( expresin ){ case constante1: instrucciones; break; case constante2: instrucciones; break; ... default: instrucciones; break; }

La sentencia default se ejecutar slo si ninguna constante de las que siguen a case coincide con expresin. Es algo similar al else final de la instruccin if-ese-if. Sin ms, vamos a por un ejemplo
using System; class InstruccionSwitch{ public static void Main() { string s; Console.WriteLine( "Elige hacer algo con los nmeros 2 y 3"); Console.WriteLine( Console.WriteLine( Console.WriteLine( Console.WriteLine( " " " " + * / para para para para sumarlos" ); restarlos" ); multiplicarlos" ); dividirlos (division

entera)" );

s = Console.ReadLine(); switch(s){ case "+": Console.WriteLine("El resultado es {0}", 2+3); break; case "-":

Console.WriteLine("El break; case "*": Console.WriteLine("El break; case "/": Console.WriteLine("El break; default: Console.WriteLine("No break; } } }

resultado es {0}", 2-3); resultado es {0}", 2*3); resultado es {0}", 2/3); te entiendo");

El cual solicita al usuario que inserte uno de los smbolos +-*/ , y con un switch compara los resultados para hacer diferentes acciones dependiendo del valor de s, que es la cadena de caracteres que almacena la eleccin del usuario. El resultado debera de ser algo parecido a esto:
Elige hacer algo con los nmeros 2 y 3 + para sumarlos - para restarlos * para multiplicarlos / para dividirlos (division entera) * El resultado es 6

Como habr notado, al final de todo case siempre hay una sentencia break. Esto no es obligatorio, puede haber en su lugar otra sentencia de salto, como un goto, pero siempre tiene que haber una sentencia de salto, incluso en el default final, a no ser que la sentencia case est vaca. En caso contrario se obtiene un error en tiempo de compilacin. Otros lenguajes, como C/C++ o Java no tienen esta restriccin. La razn de adoptarla en C# es doble: por un lado, elimina muchos errores comunes y en segundo lugar permite al compilador reorganizar las sentencias de los case, y as permitir su optimizacin.

3.1.3. Bucle for


El bucle for de C# es idntico al encontrado en los lenguajes C/C++ y Java. El formato general es
for( inicializacin; condicin; iteracin ) { instrucciones; }

Las sentencias de inicializacin se ejecutan una vez al principio y sirven principalmente para asignar valores a las variables que servirn de contador. Las sentencias de condicin, por su parte, se ejecutan cada vez que el bucle vuelve al principio y sirven para controlar el bucle: ste seguir realizndose siempre y cuando estas codiciones sea true. Las sentencias de iteracin se ejecutan tambin cada vez que se realiza una nuevo

ciclo en el bucle, y sirven para cambiar el estado de las variables que gobiernan las sentencias de condicin. Pero todo esto se entiende mejor con un ejemplo
using System; class BucleFor{ public static void Main() { int i; //el contador for( i = 0; i < 10; i++) { Console.WriteLine( i ); }

} }

Este ejemplo imprime por pantalla los 10 primero enteros positivos. Es un caso muy simple del bucle for. Por cierto, el operador ++ lo que hace es que aade una unidad a la variable a la que acompaa, de forma que, por ejemplo, 9++ es 10. De esta forma, la variable i se incrementa a cada vuelta. En el ejemplo anterior, las sentencias de inicializacin y de iteracin eran nicas, pero esto no tiene porqu ser as, de hecho se pueden utilizar varias sentencias separadas por comas. Por ejemplo, se pueden usar dos variables para controlar el bucle
using System; class BucleFor2{ public static void Main() { int i; int j; for( i=0, j=10; i<j; i++, j--) { Console.WriteLine("( {0} , {1} )", i, j); } } }

Por su parte, la expresin condicionar del bucle for puede ser cualquier expresin que genere un valor booleano. En este caso se ha usado "i>j", pero tambin hubiera sido vlida "i==5", "true" (el bucle se realizar indefinidamente) o "false" (el bucle no se realizar).

3.1.4. Bucle while


El bucle while es un bucle que se realiza hasta que se cumpla determinada condicin. Tiene la forma
while( condicin ) { instrucciones;

Donde la condicintiene que ser un valor booleano. Tiene una estructura muy sencilla, as que vamos a ver directamente un ejemplo.
using System; class BucleWhile{ public static void Main() { int i = 0; while( i<10) { Console.WriteLine( i ); i = i+1; } } }

En el que se realiza lo mismo que en el ejemplo anterior, slo que ahora con un bucle while.

3.1.5. Bucle do-while


Se trata de una ligera variante del bucle anterior, con la diferencia de que ahora primero se ejecutan las instrucciones y luego se evala la condicin, de forma que tiene tiene una estructura:
do{ instrucciones; } while( condicin );

El siguiente ejemplo
class BucleDoWhile{ public static void Main() { string s = ""; do { ); Console.WriteLine( "Introduce si para salir del bucle" s = Console.ReadLine(); } while( s != "si" );

} }

muestra un programa que ejecuta un bucle hasta que el usuario introduce "si". Por cierto, != es lo contrario de ==, es decir, != devuelve true cuando los valores comparados son distintos.

3.1.6. Bucle foreach

El bucle foreach se utiliza para hacer iteraciones sobre elementos de una coleccin, como pueden ser los enteros dentro de un arreglo de enteros. La sintaxis sigue la siguiente estructura:
foreach( tipo in coleccion ) { instrucciones; }

Como hemos comentado, el uso ms inmediato es iterar sobre un arreglo de nmeros:


using System; class BucleForeach{ public static void Main() { int[,] arr = {{1,2},{2,3}}; foreach( int elem in arr ) { Console.WriteLine( elem ); }

} }

Este ejemplo slo imprime los valores de una matriz, pero como se puede comprobar mejora mucho la claridad del cdigo comparndolo con una implementacin con bucles for como esta
using System; class BucleForeach{ public static void Main() { int i, j; //seran los indexadores de la matriz int[,] arr = {{1,2},{2,3}};

} }

for(i = 0; i<2; i++ ) { for( j = 0; j<2; j++ ) { Console.WriteLine( arr[i,j] ); } }

Adems, es posible utilizar el bucle foreach con cualquier tipo que sea una coleccin, no solo con arreglos, como veremos ms adelante.

3.2. Cambiando el rumbo

Existen varias formas de cambiar el rumbo de los programas, mediante sentencias de salto incondicional, como goto, return, as como formas de cambiar el rumbo de bucles, como continue o break

3.2.1. Instruccin goto


La instruccin goto sirve para realizar saltos incondicionales a otras partes del programa. Los programadores siempre advierten de los peligros de usar demasiado esta sentencia (es propensa a escribir cdigo ilegible), aunque el contadas ocasiones puede ser de gran utilidad. Como su propio nombre indica, esta sentencia nos lleva a alguna parte del programa, de forma que habr que marcar con una etiqueta la parte del programa a la que deseemos que nos enve. Estas etiquetas se declaran simplemente con el nombre de la etiqueta y dos puntos. Lo vemos en el siguiente ejemplo
using System; class Goto{ public static void Main() { goto dos; uno: Console.WriteLine("Esto no se ejecutar"); dos: Console.WriteLine("Hemos saltado directamente aqu!"); } }

Es un ejemplo muy simple con dos etiquetas: uno y dos. En la ejecucin normal de un programa, primero se ejecutara uno y despus dos. Sin embargo, la instruccin goto hace que saltemos directamten a la instruccin dos. Seguro que se te ocurren multitud de situaciones en las que es til la instruccin goto, as que no insistiremos ms sobre esto.

3.2.2. Sentencia return


Colocar return en alguna parte del programa provoca que el mtodo termine y devuelva el valor especificado. Si estamos en el mtodo Main() , que por ahora es el nico caso que conocemos, return provocar el final del programa. En el ejemplo
using System; class SentenciaReturn{ public static void Main() { double a; principio: Console.WriteLine("Introduce un numero:"); a = Double.Parse( Console.ReadLine() );

if( a > 10 ) { return; } else { goto principio; } } }

utilizamos tambin la instruccin return para implementar un programa en el que se le pide al usuario que introduzca un nmero y solo termina si el nmero es mayor que 10. Este es un mal ejemplo de uso de goto y return, pus se podra haber conseguido lo mismo con un bucle while, pero por ahora sirve. La importancia de la sentencia return se ver con ms claridad cuando veamos mtodos.

3.2.3. La instruccin continue


Es posible realizar la repeticin temprana de un bucle omitiendo el resto del cdigo que contenga el bucle mediante continue. Su comportamiento es muy sencillo:

using System; class UsoContinue{ public static void Main() { int i; for(i = 0; i<10; i++ ) { continue; Console.WriteLine("Esto nunca se ejecutar!"); } Console.WriteLine("Adios!"); } }

Al compilar el siguiente ejemplo, es posible que el compilador emita una advertencia de que ha detecatado cdigo inalcanzable -esto es, que nunca llegar a ejecutarse. Esto no es problema, pus es justamente lo que queremos. Por lo dems, el ejemplo es muy sencillo, dentro del bucle for lo primero que se hace es ejecutar la instruccin continue, de forma que el bucle se repite sin llegar nunca al siguiente Console.WriteLine().

3.2.4. break para salir de bucles


La instruccin break es el complemento lgico de continue, de forma que si continue repite el bucle, break, lo termina. As, cuando se encuentra una sentencia break dentro de un bucle, ste inmediatamente finaliza y se sigue la ejecucin del programa.
using System;

class UsoBreak{ public static void Main() { int i; for( i = 0; i<20; i++) { if( i> 10 ) { break; } Console.WriteLine( i ); }

} }

Este ejemplo muestra el uso de break para imprimir los enteros de 0 a 10. Si no estuviera la sentencia break mostrara los enteros hasta 20, pero al llegar a 11 se ejcuta la instruccin if que desemboca en un break que hace que la ejecucin salga del bucle.

3.2.5. throw y el manejo de excepciones


La sentencia throw sirve para lanzar excepciones y as modificar el flujo del programa, de mondo que pasa a otra instruccin si se captura la excepcin, o se termina el programa si la excepcin no es capturada. Esta sentencia se ver en el captulo sobre manejo de excepciones

Captulo 4. Operadores 4.1. Operadores


Los operadores son smbolos que permiten realizar operaciones con uno o ms datos, para dar un resultado. El ejemplo clsico y obvio de operador es el smbolo de la suma (+), aunque hay otros muchos. Vamos a hacer un repaso a los tipos de operadores que tenemos en C#:

Operadores Aritmticos: Son la suma (+), resta (-), producto (*), divisin (/) y mdulo (%). stos son bastante inmediatos pus funcionan de la misma manera que en lgebra. Solo hay que tener en cuenta que la divisin entre enteros devuele un entero, de forma que 3/2 devuelve 1 ( el resultado se trunca). Es interesante saber que a las operaciones aritmticas les podemos aadir otros dos operadores, checked y unchecked, para controlar los desbordamientos en las operaciones. La sintaxis es esta:

variable1 = checked (34+4);

o bien
variable1 = unchecked (34+4);

Si en una operacin regida por checked se produce un desbordamiento, dar un error en tiempo de compilacin si los operadores son constantes, o lanzar una excepcin System.OverflowException si son variables. En cambio, si la operacin es unchecked, cuando se produce un desboramiento nos devolver el resultado truncado, para que "quepa" en el resultado esperado.

Operadores Lgicos: Son "and" (&& y &), "or" (|| y |), "not" (!) y "xor" (^). La diferencia entre && y &, y entre || y | es que && y || hacen lo que se llama "evaluacin perezosa": si evaluando slo la primera parte de la operacion se puede deducir el resultado, la parte derecha no se evaluar. Es decir, si tenemos por ejemplo:
false && (otra cosa)

El resultado de esta operacin siempre ser false, y (otra cosa) ni siquiera se evala. De igual forma, si tenemos
true || (otra cosa)

el resultado ser true, y la parte derecha nunca se evaluar.


Operadores relacionales: igualdad (==), desigualdad (!=), mayor que (>), menor que (<), mayor o igual que (>=) y menor o igual que (<=) Operadores de Manipulacin de Bits: Tenemos las siguientes operaciones: and (&), or (|), not (~), xor (^), desplazamiento a la izquierda (<<), y desplazamiento a la derecha (>>). El desplazamiento a la izquierda rellena con ceros. El desplazamiento a la derecha, si se trata de un dato con signo, mantiene el signo. Si no, rellena con ceros. Operadores de Asignacin: El operador bsico de asignacin es =. Adems, tenemos las clsicas abreviaturas +=, -=, *=, /=, &=, |=, ^=, <<= y >>= Estas abreviaturas se usan para evitar tecleo en operaciones como esta:
variable1 = variable1 + variable2;

Se puede escribir de esta forma abreviada:

variable1 += variable2;

Tambin tenemos operadores de incremento (++) y decremento (--), que incrementan en una unidad el valor de la variable sobre la que se aplican. Por tanto, estas tres lneas de cdigo son casi iguales:
variable1 = variable1 + 1; variable1 += 1; variable1++;

El "casi iguales" lo ponemos porque en muchas mquinas, el operador ++ es ms rpido que la operacin "+ 1", ya que el compilador lo traduce a una nica instruccin mquina. Hay que tener en cuenta que no es lo mismo poner variable++ que ++variable. Ambas formas son correctas, pero no significan lo mismo. Lo vemos con un ejemplo:
variable1 = ++variable2; variable1 = variable2++;

En el primer caso, primero se incrementa variable2 y luego se hace la asignacin. En el segundo caso primero se hace la asignacin, y luego el incremento.

Operador Condicional: Es el nico operador de C# que tiene tres operandos. Su sintaxis es esta:
<condicin> ? <expresin1> : <expresin2>

Quiere decir que si la condicin es true, se evala expresin1, y si es falsa, se evala expresin2. Se ve ms claro con un ejemplo:
b = (a>0) ? a : 0;

Esto quiere decir que si a es mayor que 0, la expresin ser b = a, y si a no es mayor que 0, la expresin ser b = 0; Ojo: No confundir con un "if". Este operador devuelve un valor, mientras que el if es slamente una instruccin.

Operadores de Delegados: Para aadir mtodos a un delegado se hace con + y +=, y para quitarselos, con - y -=.

Operadores de Acceso a Objetos: El operador para acceder a los miembros de un objeto es el punto. As esta expresin:
A.metodo1 ();

nos permite acceder al mtodo "metodo1" del objeto A.

Operadores de Punteros: Tenemos varios operadores. Para acceder a la direccin de memoria a la que apunta el puntero, lo hacemos con &puntero. Para acceder al contenido de la direccin de memoria, tenemos *puntero. Si lo que referencia el puntero es un objeto, podemos acceder a sus miembros con puntero>miembro. Operadores de Obtencin de Informacin sobre Tipos: Para averiguar el tipo de una variable, usamos el operador sizeof (variable). Nos devolver un objeto de tipo System.Type. Si queremos hacer una comparacin, usamos algo como esto:
(expresion) is nombreTipo

que, como es lgico, nos devolver un true o un false.

Operadores de Conversin: Para convertir el tipo de un objeto en otro, precedemos el objeto que queremos cambiar con el tipo al que queremos convertir, entre parntesis, de esta forma:
variable1 = (int) variable2;

De esta forma, variable2 ser tratada como si fuera un dato de tipo int, aunque no lo sea.

Captulo 5. Introduccin a las clases 5.1. Introduccin a las clases en C#


Como hemos dicho, C# es un lenguaje orientado objetos. A diferencia de lenguajes como C++ o Python en los que la orientacin a objetos es opcional, en C# es imposible programar sin utilizar esta tcnica. Una prueba de ello es que en C# cualquier mtodo o variable est contenida dentro de un objeto. Por ahora puede asumirse que un objeto y una clase son la misma cosa. Una clase es como una plantilla que describe cmo deben ser las instancias de dicha clase, de forma que cuando creamos una intancia, sta tendr exactamente los mimos mtodos y variables que los que tiene la clase.Los datos y mtodos contenidos en una clase se llaman miembros de la clase y se accede a ellos siempre mediante el operador "." . En el siguiente ejemplo, se definir una clase, Clase1 y en el mtodo Main se crear una instancia de Clase1 llamada MiClase. Una buena idea es jugar un poco con el

cdigo para ver que la instancia de la clase efectivamente tiene los mismos miembros que la clase Clase1 (que sera la plantilla de la que hablbamos antes)
using System; //definimos nuestra clase class Clase1{ public int a = 1; private double b = 3; public char c = 'a'; } //usamos la clase que hemos creado class UsoClase{ public static void Main() { Clase1 MiClase = new Clase1(); // asi creamos una instancia de Clase1 Console.WriteLine( MiClase.c ); //podemos llamar a los tipos que hay dentro de Clase1 } }

los identificadores public delante de los tipos que hay dentro de Clase1 son necesarios para luego poder ser llamados desde otra clase, como en este caso, que estamos llamando a los miembros de una instancia de Clase1 desde UsoClase. Pero en las clases no solo hay variables, tambin podemos incluir mtodos.
using System; //definimos nuestra clase class Clase1{ public int a = 1; public double b = 3; public char c = 'a'; public void Descripcion() { Console.WriteLine("Hola, soy una clase"); }

//usamos la clase que hemos creado class UsoClase{ public static void Main() { Clase1 MiClase = new Clase1(); // asi creamos una instancia de Clase1 Console.WriteLine( MiClase.c ); //podemos usar todos los tipos que hay dentro de Clase1 MiClase.Descripcion(); } }

Podemos hacer ms cosas con las clases, como heredar otras clases o implementar interfaces, pero en este captulo nos centraremos en el uso de mtodos y variables.

5.1.1. Mtodos
Los mtodos, tambin llamados funciones, son trozos de cdigo que reciben unos datos, hacen algo con esos datos, y a veces devuelven algn valor. En C#, todos los mtodos se encuentran contenidas dentro de un objeto. La estructura mnima de un mtodo tiene las siguientes partes:

Tipo devuelto Nombre del mtodo Parmetros (puede ser vaco) Cuerpo del mtodo

de forma que el siguiente mtodo:


double Divide( double a, double b ) { return a/b; }

devuelve un tipo double, tiene por nombre Divide, los parmetos son dos tipo double, y el cuertpo del mtodo es simplemente "return a/2;". Cuando queramos llamar a un mtodo, debemos simplemente poner el nombre del mtodo y sus argumentos dentro de un parntesis separados por comas. Para llamar al mtodo Dive declarado antes, simplemente debemos escribir
Divide(8, 2);

Segn lo que hemos visto, el ejemplo del mtodo Divide() completo neceista tener tener una clase donde definirse y un mtodo Main() donde ejecutarse.
using System; class Metodo{ double Divide( double a, double b ) { return a/b; } } class Principal{ public static void Main() { Metodo m = new Metodo(); Console.WriteLine( m.Divide(8, 2) ); } }

5.1.2. Modificadores public y static

El modificador public lo hemos utilizado anteriormente. Se puede utilizar en la declaracin de cualquier mtodo o variable, y como es de esperar, produce el efecto de que el campo afectado se vuelve &pblico&, esto es, se puede utilizar desde otras clases
using System; class Metodo{ public double Divide( double a, double b ) { return a/b; } } class Principal{ public static void Main() { Metodo m = new Metodo(); Console.WriteLine( m.Divide(8, 2) ); } }

Si por ejemplo intentamos declarar el mtodo Divide sin el modificador public, obtendremos un error en tiempo de compilacin. El modificadro complementario de public es private, que provoca que el mtodo o dato solo sea accesible desde la clase en la que est declarado. Si no se especifica nada, se toma por defecto el modificador private De esta forma podramos separar las clases Metodo y Principal en dos archivos separados, llamados por ejemplo metodo.cs y principal.cs . Para compilar esto, bastar compilar ambos archivos al mismo tiempo, de forma similar a esto: mcs principal.cs metodo.cs Adems, tampoco es necesario crear una instancia de la clase slo para acceder a un mtodo declarado en ella. Para eso debemos anteponer a la declaracin del mtodo el modificador static. Los mtodos estticos se caracterizan por no necesitar una instancia de la clase para cumplir su funcin, pero como contrapartida, no pueden acceder a datos propios de la clase.
using System; class Metodo{ public static double Divide( double a, double b ) { return a/b; } } class Principal{ public static void Main() { Console.WriteLine( Metodo.Divide(8, 2) ); } }

Los mtodos estticos se utilizan en multitud de situaciones. Por ejemplo, el mtodo Console.WriteLine() o las funciones de la librera matemtica estndar no son ms que mtodos estticos de sus respectivas clases

5.1.3. Constructores e instancias de una clase


Como hemos visto, las instancias de una clase se crean con la sintaxis
nombreclase objeto = new nombreclase( argumentos );

donde nombreclase es el nombre que le hemos dado a la definicin de la clase, argumentos es una lista de argumentos posiblemente vaca y objeto es el nombre que queremos darle a la instancia de la clase. Una vez creada una clase, sus miembros se inicializan a sus valores predeterminados ( cero para valores numricos, cadena vaca para el tipo string, etc. ). La siguiente clase representa un punto sobre el plano, de forma que tiene dos valores pblicos X e Y, y un mtodo que calcula la distancia al origen del punto (mdulo)
using System; class Punto{ public double X; public double Y; public double Modulo() { double d; d = Math.Sqrt(X*X + Y*Y); //Sqrt = raiz cuadrada return d; }

class Principal{ public static void Main() { Punto A = new Punto(); A.X = 1; A.Y = -1; Console.WriteLine("El modulo del punto (1,1) es: {0}", A.Modulo() ); } }

Ahora bien, la forma en la que se crea la instancia, es decir, inicializando los datos a cero (ejercicio: comprobar esto), se puede personalizar, de forma que podemos construir nuestro propio constructor que le diga a la clase los valores por defecto que debe tomar. Esto se realiza simplemente escribiendo dentro de la clase un mtodo que tenga el

mismo nombre que la clase y en el que no se especifica el valor devuelto. La clase Par con un constructor sera as:
using System; class Punto{ public double X; public double Y; public Punto() //constructor { X = 1; Y = 1; } public double Modulo() { double d; d = Math.Sqrt(X*X + Y*Y); //Sqrt = raiz cuadrada return d; } }

de forma que ahora al crear una instancia de la clase se crea el punto (1,1) en lugar del (0,0), que era el que se creaba por defecto. De esta forma, al crear la instancia, par ya contendr los valores (1,1) . En la prctica se utilizan mucho constructores con parmetos, de forma que al crear la instancia se le asignan valores segn los parmetros. La siguiente implementacin de Par contiene un constructor que acepta un par de valores, que servirn para inicializar los valores A y B
class Punto{ public Punto( double val1, double val2) { X = val1; Y = val2; } ... }

Tambin tenemos la posibilidad de clarar una clase con varios constructores (cada uno con diferenctes parmetros) Lo que har el compilador de C# es buscar el constructor que se adece a los parmetros que le llegan, y ejecutarlo como si fuera un mtodo ms. Dependiendo de la llamada que se haga en el "new", usaremos un constructor u otro.

5.1.4. Sobrecarga de mtodos


En C#, al igual que en C++ y en Java es posible definir varios mtodos con el mismo nombre pero con distintos parmetros, de forma que el compilador decide a cul se llama dependiedo de los parmetros que le lleguen.

Esto es muy prctico, pus no tienes que renombrar cada funcin segn el tipo de valor que acepta. El siguiente ejemplo implementa un par de mtodos que elevan al cuadrado el valor que reciben, y se implementan para tipos double y para int. En C, que es un lenguaje que no soporta sobrecarga de mtodos, se tendra que haber llamado distinto a ambos mtodos, por ejemplo alcuadrado_double y alcuadrado_int
using System; class Eleva{ public static double AlCuadrado( int a ) { return a*a; } public static double AlCuadrado( double a ) { return a*a; } } class Principal{ public static void Main() { Console.WriteLine("4 al cuadrado es {0}", Eleva.AlCuadrado(4) ); Console.WriteLine("3.2 al cuadrado es {0}", Eleva.AlCuadrado(3.2) ); } }

5.1.5. La palabra reservada this


La palabra reservada this sirve para hacer referencia a miembros de la clase en caso de que se quiera especificar, ya sea por motivos de colisin de nombres o por la claridad del cdigo. Su sitaxis es
this.campo

donde campo es la variable de la clase a la que queremos hacer referencia. En el siguiente ejemplo, declaramos un constructor para la clase Punto, que toma dos argumentos X e Y. Entonces es obligado el uso de this para distinguir entre el X de la clase y el X tomado como parmetro
class Complejo{ double X; double Y; Complejo(double X, double Y) { this.X = X;

this.Y = Y; } }

Captulo 6. Variables y parmetros 6.1. Variables y parmetros


6.1.1. Variables
Las variables representan un espacio donde alojar informacin. Toda variable tiene un tipo que determina qu valor puede ser almacenado en la variabe. Las variables locales son variables que son declaradas dentro de mtodos, propiedades o indexadores. Una variable local queda definida especificando su tipo y una declaracin que especifica el nombre de la variable y un valor inicial opcional, como en:
int a; int b = 1;

pero tambin es posible declarar varias variables locales del mismo tipo de la siguente forma:
int a, b = 1;

La variable debe tener asignado un valor antes de que pueda ser utilizada. El ejemplo:
class Test { static void Main() { int a; int b = 1; int c = a + b; // error, a no tiene valor asignado } }

da como resultado un error en tiempo de compilacin porque intenta usar la variable antes de que sta haya tomado ningn valor. Un campo es una variable asociada a una clase o estructura. Un campo declarado con el modificador static define una variable esttica, esto es, que no necesita que se haya creado una instancia de la clase en la que est contenida, mientras que un campo declarado sin este modificador define una variable instancia. Un campo esttico est asociado a un tipo, mientras que una variable instancia est asociada con una instancia. El ejemplo

class Empleado

{ private static string nombre; public int DNI; public decimal Salario;

muestra la clase Empleado que tiene una variable esttica privada y dos variables instancia pblicas.

6.1.2. Parmetros
La declaracin formal de parmetros tambin define variables. Hay cuatro tipos de parmetros: parmetros por valor, por referencia, parmetros de salida, y arreglos de parmetros.

6.1.2.1. Paso por valor


El paso de parmetros por valor es usado por defecto para pasar parmetros a mtodos. Cuando se pasa un parmetro por valor a una funcin realmente se est pasando una copia de dicho parmetro, por lo que las modificaciones que le hagamos al parmetro dentro del mtodo no afectarn al parmetro original. El ejemplo
using System; class Test { static void F(int p) { p++; Console.WriteLine("p = {0}", p); } static void Main() { int a = 1; Console.WriteLine("pre: a = {0}", a); F(a); Console.WriteLine("post: a = {0}", a); } }

muestra un mtodo F que tiene un parmetro por valor llamado p. El ejemplo produce la salida:
pre: a = 1 p = 2 post: a = 1

aunque el valor del parmetro p haya sido modificado dentro del mtodo.

6.1.2.2. Paso por referencia


El paso de parmetros por referencia es la contraposicin lgica al paso por valor. En el paso por referencia no se realiza ninguna copia del objeto, sino que lo que se le pasa a la funcin es una referencia del objeto, de forma que el parmetro pasa directamente a la funcin y cualquier modificacin sobre el parmetro dentro de la funcin afectar al parmetro original

using System; class Test { static void Swap(ref int a, ref int b) { // intercambia los dos valores int t = a; a = b; b = t; } static void Main() { int x = 1; int y = 2; Console.WriteLine("pre: x = {0}, y = {1}", x, y); Swap(ref x, ref y); Console.WriteLine("post: x = {0}, y = {1}", x, y); } }

muestra un mtodo swap que tiene dos parmetros por referencia. La salida producida es:
pre: x = 1, y = 2 post: x = 2, y = 1

La palabra clave ref debe de ser usada tanto en la declaracin formal de la funcin como en los usos que se hace de sta. El parmetro de salida es similar al parmetro por referencia, salvo que el valor inicial de dicho argumento carece de importancia. Un argumento de salida se declara con el modificador out. El ejemplo
using System; class Test { static void Divide(int a, int b, out int result, out int remainder) { result = a / b; remainder = a % b; } static void Main() { for (int i = 1; i < 10; i++) for (int j = 1; j < 10; j++) { int ans, r; Divide(i, j, out ans, out r); Console.WriteLine("{0} / {1} = {2}r{3}", i, j, ans, r); } } }

muestra un mtodo Divide que incluye dos parmetros de salida. Uno para el resultado de la divisin y otro para el resto.

6.1.3. Arreglo de parmetros

Para los parmetros descritos anteriormente hay una correspondencia unvoca entre los argumentos que puede tomar la funcin y los parmetros que los representan. Un arreglo de parmetros permite guardar una relacin de varios a uno: varios argumentos pueden ser representados por un nico arreglo de parmetros. En otras palabras, los arreglos de parmetros permiten listas de argumentos de tamao variable. Un arreglo de parmetros se declara con el modificador params. Slo puede haber un arreglo de parmetros en cada mtodo, y siempre debe ser el ltimo mtodo especificado. El tipo del arreglo de parmetros siempre es un tipo arreglo unidimensional. Al llamar a la funcin se puede pasar un nico argumento de su tipo o bien cualquier nmero de argumentos de tipo del tipo del arreglo. El ejemplo
using System; class Test { static void F(params int[] args) { Console.WriteLine("n de argumentos: {0}", args.Length); for (int i = 0; i < args.Length; i++) Console.WriteLine("args[{0}] = {1}", i, args[i]); } static void Main() { F(); F(1); F(1, 2); F(1, 2, 3); F(new int[] {1, 2, 3, 4}); } }

muestra un mtodo F que toma un nmero variable de argumentos int, y varias llamadas a este mtodo. La salida es:
n de arguments: 0 n de argumentos: 1 args[0] = 1 n de argumentos: 2 args[0] = 1 args[1] = 2 n de argumentos: 3 args[0] = 1 args[1] = 2 args[2] = 3 n de argumentos: 4 args[0] = 1 args[1] = 2 args[2] = 3 args[3] = 4

La mayora de los ejemplos presentes en esta introduccin utilizan el mtodo WriteLine de la clase Console. El comportamiento para las sustituciones, como muestra el ejemplo
int a = 1, b = 2; Console.WriteLine("a = {0}, b = {1}", a, b);

se consigue usando un arreglo de parmetros. El mtodo WriteLine proporciona varios mtodos sobrecargados para el caso comn en el que se pasan un pequeo nmeros de argumentos, y un mtodo que usa un arreglo de parmetros.
namespace System { public class Console { public static void public static void public static void ... public static void {...} } }

WriteLine(string s) {...} WriteLine(string s, object a) {...} WriteLine(string s, object a, object b) {...} WriteLine(string s, params object[] args)

Captulo 7. Propiedades e indizadores 7.1. Propiedades e indizadores


7.1.1. Propiedades
Las propiedades son una caracterstica de C# que permiten aparentemente el acceso a un miembro de la clase mientras mantiene el control asociado al acceso mediante mtodos. Para los programadores de Java hay que decir que esto no es ms que la formalizacin del patrn de asignacin (setter) y mtodo de lectura (getter) Las propiedades son como mtodos que se declaran dentro de un bloque asociado a una variable mediante las palabras reservadas get (se encarga de devolver algo cuando se llama al tipo que lo contiene ) y set (que hace algo cuando se le asigna un valor a la variable que lo contiene. Este valor viene especificado en la variable value )
using System; class TestProperties { private static string clave; public string Clave { get { Console.WriteLine ("Acceso a la propiedad clave"); return clave; } set { Console.WriteLine ("Cambio del valor de clave"); clave = value;

} } }

class Test { public static void Main () { TestProperties tp = new TestProperties(); string c = "ClaveClave"; tp.Clave = c; Console.WriteLine (tp.Clave); } }

En realidad, lo que se hace es declarar una variable privada de forma que no se puede acceder de forma directa, y se crean dos mtodos ( o uno si solo se requiere acceso de lectura) que permiten acceder al contenido de la variable y tal vez modificarla. Si no queremos que se pueda moficiar la variable, no inclumos el mtodo "set" y ya tendramos propiedades de slo lectura.

7.1.2. Indexadores
Hemos visto, en el apartado en el que tratamos las propiedades, que podemos acceder a una variable privada de una clase a travs de eventos que nos permiten controlar la forma en la que accedemos a dicha variable. Los indexadores nos van a permitir hacer algo parecido. Nos van a permitir acceder a una clase como si se tratara de un arreglo. Lo vemos de forma ms sencilla con un ejemplo:
using System; class PruebaIndexadores { private int[] tabla = {1, 2, 3, 4}; public int this [int indice] { get { Console.WriteLine ("La posicion {0} de la tabla tiene el valor {1}", indice, tabla[indice]); return tabla[indice]; } set { Console.WriteLine ("Escrito el valor {0} en la posicin {1} de la tabla", value, indice); tabla[indice] = value; } } }

Tenemos una clase PruebaIndexadores en la que hay un array llamado "tabla", declarado como privado, por lo que no podremos acceder a l desde fuera de nuestra

clase. Pero hemos declarado tambin un indexador (public int this [int indice]), que nos permitir acceder a l de forma ms controlada. Para probar esta clase, creamos otra clase con un punto de entrada (public static void Main ()), que ser donde hagamos las pruebas. Primero creamos un objeto de la clase PruebaIndexadores:
PruebaIndexadores obj = new PruebaIndexadores ();

Luego accedemos a una posicin del indexador:


int a = obj[3];

Esta lnea lo que hace es llamar al indexador, pasndole como parmetro el ndice, en este caso 3. Al ser una consulta de lectura, se ejecuta el cdigo que haya en la parte "get" del indexador. Una vez ejecutado, lo que nos aparece por pantalla es esto:
La posicion 3 de la tabla tiene el valor 4

Vamos ahora a hacer un cambio en la tabla:


obj[3] = 6;

Lo que se ejecuta ahora es la parte "set" del indexador. Lo que aparecer en pantalla una vez ejecutado esto ser:
Escrito el valor 6 en la posicin 3 de la tabla

Ntese que tenemos que hacer explcitamente el acceso al array (tabla[indice]=value) en el set, ya que el indexador no tiene forma de saber qu variable se supone que tiene que manejar. Si no pusiramos esa lnea, en realidad el indexador no cambiara el valor del array. Para comprobar que realmente se ha hecho el cambio, volvemos a acceder al indexador:
a = obj[3];

Y esta vez nos aparecer esto:


La posicion 3 de la tabla tiene el valor 4.

Captulo 8. Clases (II)


Como hemos dicho, las clases definen nuevos tipos por referencia. Una clase puede heredar otra clase y puede implementar (varias) interfaces (conceptos que se vern en este captulo).

8.1. Modificadores de acceso


Los miembros de una la clase pueden ser constantes, campos, mtodos, propiedades, contructores, destructores, y tipos anidados. Como en la moyora de lenguajes orientados a objetos, cada miembro tiene una accesibilidad asociada, que controla a qu cdigo se le permite el acceso a nuestros miembros. Hay cinco posibles formas de accesibilidad: public, protected, internal y protected internal. Sus caractersticas son las siguientes:

public: Acceso no limitado. Cualquier cdigo puede acceder a un elemento public protected: Acceso limitado desde la propia clase o desde tipos derivados de la propia clase internal: Acceso limitado al propio programa protected internal: Acceso limitado al propio programa o a tipos derivados de la propia clase private: Acceso limitado a la propia clase

Puesto que uno de los pilares principales de la programacin orientada a objetos es la ocultacin de datos, y para mantener una API lo ms simple posible, se recomienda siempre el uso de private salvo cuando est justificado el uso de un modificador distinto. Si no se especifica ningn modificador, la accesibilidad por defecto es la private

8.2. Herencia
La herencia es un concepto fundamentar de la programacin orientada a objetos. Cuando se dice que una cierta clase A hereda otra clase B significa que la clase A contiene todos los miembros de la clase B ms algunos que opcionalmente puede implementar ella misma Las clases en C# soportan herencia simple, de forma que una clase puede derivar de otra, pero no de varias (como si era posible en C++). De hecho, en C# todas las clases derivan implcitamente de la clase object. La sintaxis que se utiliza es la siguiente:
class MiClaseDerivada : MiClaseBase { //miembros }

En el siguiente ejemplo definimos una clase A con un mtodo F(). Posteriormente definimos una clase B que hereda A y adems define un mtodo G(). Finalemente creamos una clase con un mtodo Main() que llamar a los dos mtodos de B, al implementado por B y al heredado

using System; class A{ public void F() { Console.WriteLine("Soy F() de A"); } } class B : A{ public void G() { Console.WriteLine("Soy G() de B"); } } class Principal{ public static void Main() { B clase_heredada = new B(); clase_heredada.F(); clase_heredada.G(); } }

8.2.1. La palabra reservada base


La palabra reservada base sirve para acceder a miembros de la clase heredada de la misma forma que this sirve para acceder a miembros de la propia clase. Su sintaxis es idntica a la de this, esto es:
base.nombre_del_miembro

En el siguiente ejemplo declaramos una clase B que hereda A y que utiliza el mtodo F() de A.
class B : A{ public void H() { base.F(); Console.WriteLine("soy H() de B"); } }

8.2.2. Clases Abstractas


Las clases abstractas son clases que contienen algn mtodo incompleto, esto es, que est definido pero no implementado. Por lo tanto, no se pueden instanciar y su nico propsito es servir de clase base de las que se derivarn otras clases.

Las clases que heredan una clase abstracta deben implementar los mtodos incompletos. Las clases abstractas se declaran con la palabra reservada abstract
using System; abstract class A{ public void F(); //metodo no implementado } class B : A{ //error en tiempo de compilacin, B tiene que definir un mtodo F() }

8.2.3. Miembros virtual


Mtodos, propiedades e indexadores pueden ser virtual, lo que significa que su implementacin puede ser sobreescrita en clases derivadas. El ejemplo
using System; class A { public virtual void F() { Console.WriteLine("A.F"); } } class B: A { public override void F() { base.F(); Console.WriteLine("B.F"); } } class Test { public static void Main() { B b = new B(); b.F(); A a = b; a.F(); } }

muestra una clase A con un mtodo virtual F, y una clase B que sobreescribe F. El mtodo sobreescrito en B contiene una llamada, base.F(), el cual llama al mtodo sobreescrito en A.

8.3. Interfaces
TODO

8.4. Modificadores de Herencia


A continuacin se lista un breve resumen de los modificadores de herencia de C#

abstract: se aplica a clases o a miembros de la clase. Seccin 8.2.2 new: confirma explcitamente la intencin de ocultar un miembro heredado con el mismo nombre override: especifica que el miembro est redefiniendo un mtodo heredado con la misma firma sealed: si se aplica a una clase se indica que esta clase no puede heredarse. Si se aplica a un mtodo heredado junto a override se asegura que el mtodo no es redefinido en clases heredadas virtual: se aplica a mtodos. Permite que las clases derivadas redefinan los mtodos en lugar de ocultarlos

8.5. Algunas clases notables


8.5.1. Tipo arreglo
Los arreglos (de cualquier tipo) no son ms que instancias que derivan de la clase System.Array. Por lo tanto, son clases y se comportan como tales. Esto implica, por ejemplo, que los arreglos son tipos por referencia, y por lo tanto, al ser pasados a un mtodo, no se pasa una copia del objeto, sino una copia de la referencia al objeto. El efecto, por lo tanto, es que el objeto pasa "por referencia". El siguiente ejemplo

using System; class Arreglo{ public static void cambiastring (string[] s) { s[0] = "cambiado"; } public static void Main() { string[] s = new string[] {"sin cambiar"}; cambiastring(s); Console.WriteLine(s[0]); }

muestra cmo al pasar un arreglo a un mtodo y modificar el arreglo dentro del mtodo, el arreglo queda afectado. Como habrs supuesto, la salida del programa es "cambiado" y no "sin cambiar".

8.6. Nuevas caractersticas en C# 2.0 para las clases


8.6.1. Clases "parciales"
En C# 2.0, es posible que las clases estn repartidas en varios archivos. Solamente hay que especificar la palabra partial en la definicin de la clase.

8.6.2. Clases estticas


TODO

Captulo 9. Delegados
Los delegados son objetos que encapsulan mtodos. Son muy similares a los punteros a funciones de C/C++

9.1. Delegados
Los delegados son un tipo especial de clases que derivan de System.Delegate. Los delegados tienen como objetivo almacenar referencias a mtodos de otras clases, de tal forma que, al ser invocados, ejecutan todos estos mtodos almacenados de forma secuencial. Los delegados pueden almacenar mtodos estticos o instanciados indiferentemente. Adems los tipos de estos mtodos son comprobados para evitar errores de programacin. Es decir, un delegado solo almacenar referencias a mtodos compatibles, esto es, que devuelvan el mismo tipo y tome los mismos argumentos. Aparte de eso, a los delegados no les influye cmo sea el mtodo que estn manejando. Veamos esto con un ejemplo. Aqu podemos ver la declaracin de un delegado:
delegate void DelegadoSimple( int i );

Este delegado, por ejemplo, slo podr guardar referencias a mtodos que no devuelvan nada (void) y que reciban como parmetros un entero. Para almacenar mtodos en un delegado, usamos la siguiente sintaxis,
DelegadoSimple d = new DelegadoSimple( F );

, donde F es el mtodo que queremos que almacenen (debemos de haberlo declarado antes). Como ya hemos dicho, los mtodos que almacena un delegado deben de ser compatibles con ste, y cualquier intento de guardar mtodos no compatibles provocar una excepcin. Una vez que tenemos una instancia de nuestro delegado, para que se ejecute la funcin F() simplemente debemos llamar a nuestro delegado, pus encapsula dicha funcin, de forma que
d()

ejecuta la funcin F(). Expuesto as, los delegados parecen una forma absurda de complicar ms las cosas (si queremso llamar a una funcin, pus la llamamos y punto, no hace falta encapsularla en un delegado). Sin embargo, los delegados son fundamentales, pus son la forma de pasar funciones como parmetros a mtodos. Una vez tenemos declarado nuestro delegado, ya podemos crear instancias del mismo. Veamos este sencillo ejemplo: Ejemplo 9-1. Ejemplo simple de uso de delegados
using System; class Ejemplo { delegate void MiDelegado (int a); void Imprime (int entero) { Console.WriteLine ("Llamada a Ejemplo.Imprime({0})", entero); } public static void Main() { Ejemplo ejemplo = new Ejemplo (); MiDelegado foo; foo = new MiDelegado (ejemplo.Imprime); foo (10); } }

Tras crear una instancia de nuestra clase Ejemplo, creamos otra de nuestro delegado. Posteriormente insertamos en el delegado una referencia al mtodo Imprime, que pertenece a la instancia de nuestra clase. Finalmente convocamos al delegado a que ejecute los mtodos que contenga. Si lo compilramos obtendramos esto:
bash$ mcs ejemplo.cs Compilation succeeded bash$ mono ejemplo.exe Llamada a Ejemplo.Imprime(10)

Otra cuestin a tener en cuenta cuando programemos con delegados, es que stos no tienen en cuenta la visibilidad de los mtodos. Esto permite llamar a mtodos privados desde otros si ambos tienen acceso al delegado. Es decir, imaginemos que una clase guarda en un delegado referencia a uno de sus mtodos privados. Si desde otra clase que tenga acceso al delegado (pero no al mtodo privado) se convoca a ste, se ejecutar ese mtodo. En verdad no se est violando la privacidad del mtodo, porque no es la clase quien lo convoca, sino el delegado, que s tiene acceso al mismo.

9.1.1. Llamadas a mltiples mtodos


Hasta el momento hemos visto como hacer que un delegado guarde referencia de un slo mtodo. Sin embargo, existe una clase, System.MulticastDelegate, que deriva de System.Delegate, que se diferencia de esta ltima en que puede tener mltiples mtodos en su lista de invocaciones. Para poder hacer esto usaremos los operadores sobrecargados '+=' y '-=' que, respectivamente, aaden o eliminan a un mtodo de la lista de invocaciones de un delegado. Para intentar asimilar esto mejor, vemoslo con un ejemplo ms completo. Ejemplo 9-2. Ejemplo de uso de delegados
using System; delegate void MiDelegado (string cadena); class Ejemplo { public static MiDelegado delegado; public static void Main () { delegado = new MiDelegado (ClaseA.MetodoEstatico); ClaseA A = new ClaseA(); delegado += new MiDelegado (A.MetodoPublico); ClaseB B = new ClaseB(); // El constructor inserta MetodoPrivado // delegado += new MiDelegado (B.MetodoNoValido); // Excepcin } } class ClaseA { public static void MetodoEstatico (string cad) { Console.WriteLine ("ClaseA.MetodoEstatico ha sido llamado: {0}", cad); } public void MetodoPublico (string cad) { Console.WriteLine ("ClaseA.MetodoPublico ha sido llamado: {0}", cad); } } delegado ("Hola mundo");

class ClaseB { void MetodoPrivado (string cad) { Console.WriteLine ("ClaseB.MetodoPrivado ha sido llamado: {0}", cad); } public void MetodoNoValido (int entero) { Console.WriteLine ("ClaseB.MetodoNoValido ha sido llamado: {0}", entero); } public ClaseB () { Ejemplo.delegado += new MiDelegado (MetodoPrivado); } }

Podemos ver que, en este caso, nuestro delegado slo manipula mtodos que no devuelvan nada y que reciban como nico parmetro una cadena. Si observamos los mtodos que componen ClaseA y ClaseB, el denominado MetodoNoValido no concuerda con el delegado, ya que recibe un entero y no una cadena. Eso implica que no vamos a poder llamarlo desde ninguna instancia del delegado que hemos declarado. Sin embargo, con las otras no tendremos ningn problema. Bien, observemos paso a paso lo que hace el programa. Fijemos nuestra atencin en el mtodo principal (Main). Primero insertamos un mtodo esttico. Como sabemos, para llamar a un mtodo de este tipo, se hace a partir del nombre de la clase y no de una instancia. Bien, hasta aqu nada que no hayamos visto ya, pero ahora insertemos un segundo mdulo en el delegado. Como hemos dicho, hemos usado el operador '+=' para incluir otro mtodo ms en nuestro delegado, en este caso MetodoPublico. Si usaramos de nuevo el operador '=', borraramos la antigua lista de invocaciones y crearamos una nueva con slo una funcin referenciada. Ahora tenemos dos mtodos en la lista de invocaciones de nuestro delegado. Por ltimo, creamos una instancia de ClaseB, la cual en su constructor incluye una referencia ms al delegado, en este caso a MetodoPrivado. Si ahora compilamos y ejecutamos este cdigo, obtendremos esto:
bash$ mcs ejemplo.cs Compilation succeeded bash$ mono ejemplo.exe ClaseA.MetodoEstatico ha sido llamado: Hola mundo ClaseA.MetodoPublico ha sido llamado: Hola mundo ClaseB.MetodoPrivado ha sido llamado: Hola mundo

Como vemos, aunque hemos convocado al delegado desde la clase Ejemplo, que no tiene acceso a MetodoPrivado, ste ha sido ejecutado. Como explicamos, esto es as porque realmente quien lo est haciendo es el delegado y no el mtodo Main.

Por ltimo, una cuestin ms. Hasta el momento hemos visto a delegados que gestionan miembros que no devuelven ningn valor. Pero, qu ocurre cuando los devuelven? En este caso, la ejecucin del delegado no devuelve todos esos valores, slo el que retorne el ltimo mtodo de su lista de invocacin.

Captulo 10. Eventos 10.1. Eventos


Mientras que antiguamente la interaccin entre un programa y el usuario se limitaba a que ste introdujese datos en determinados momentos de la ejecucin del primero en los ltimos aos este modelo est siendo relegado por un crecimiento exponencial de las aplicaciones GUI (con Interfaz Grfica de Usuario). En esta nueva aproximacin conocida como Programacin Orientada a Eventos el programa queda a la espera de que el usuario vaya haciendo tal o cual cosa sin tener casi ningn control sobre el orden en el que se producirn los sucesos o ms an, ni cuales son los que darn. En nuestro caso estamos de suerte porque el lenguaje en s soporta eventos!. Los eventos son una especie de mensajes que lanza el entorno de ejecucin de manera que un objeto pueda avisar de cuando ha sucedido algo de lo que quiera avisar a otros objetos. En .NET se usa un mecanismo conocido como publicacin/subscripcin para manejar eventos, as que lo que tendremos ser una clase que publica un evento, al que se suscriben aquellas clases que quieran ser informadas cuando se lanze el evento. Ya hemos dicho todo lo que hay que decir de momento. Como al principio es un poco lioso trabajar con delegados y eventos (normalmente se llega a esta seccin sin haber practicado lo suficiente con los delegados), haremos una receta del procedimiento general a seguir.

Crear la clase que contendr el evento, la que lo publica (la que lo puede lanzar). Supongamos que el evento que queremos lanzar se llama OnButtonClicked. Si queris podis poner un nombre genrico como MyEvent. Consecuentemente cambiad todos los OnButtonClicked por MyEvent si hacis eso. Definimos el manejador del evento. Es el cdigo que se asocia con el evento en tiempo de ejecucin y que se invoca cuando la clase que se suscribe recibe la notificacin del evento. Es un delegado de tipo void y que recibe dos parmetros: el primero un objeto, el segundo una instancia de la clase que guarda la informacin del evento. Esta clase tiene que derivar de EventArgs.
[modificadores de acceso] delegate void OnButtonClickedEventHandler (object source, OnButtonClickedEventArgs e);

Declaramos el evento con el tipo del delegado antes definido.

[modificadores de acceso] event OnButtonClickedEventHandler OnButtonCliked;

Definimos el mtodo que puede lanzar el evento y establecemos los valores para el objeto que guarda la informacin del evento. Esto es cdigo en la clase que publica el evento y es el cdigo que se encarga de lanzar el evento con la informacin adecuada en el momento adecuado. Creamos la clase que guarda la informacin del evento derivndola de EventArgs:
class OnButtonClickedEventArgs : EventArgs { // cdigo // al menos un constructor y conveniente que tenga propiedades para acceder // a las variables miembro. }

Creamos la clase que se suscribe al evento. Suscribimos la clase con:


ClaseQuePublicaElEvento.OnButtonClicked += new OnButtonClickedEventHandler (callback);

Donde callback es la funcin de devolucin de llamada (retrollamada o callback) que queris que se llame cuando se recibe la notificacin del evento. Esa funcin debe estar en la clase que se subscribe al evento. Como el operador que se usa para las subscripciones es del tipo += podemos subscribir varios manejadores de evento a un mismo evento.
ClaseQuePublicaElEvento.OnButtonClicked += new OnButtonClickedEventHandler (callback2);

Y as aadir tantos callbacks como queramos ya que no se sobreescriben los unos a los otros (lo que pasara si se hubiese usado el operador =) si no que se aaden. Tambin podemos desuscribirnos de un evento mediante el operador -=. Para ello no hay ms que escribir lo mismo pero con un - en vez de un +:
ClaseQuePublicaElEvento.OnButtonClicked -= new OnButtonClickedEventHandler (callback2);

Tenis un ejemplo muy simple en el C# Reference Manual de Anders Hejlsberg y Scott Wiltamuth. Pero tambin he hecho un par de ejemplos a medida un poco ms elaborados. Clase que publica. Guardadla en Dude.cs

// Un tipo tratando de ligarse a una tipa using System; using System.Threading; public class Dude { // Declaramos el delegado que 'envolvera' a las posibles retrollamadas conectadas // al evento SignalEmitted. public delegate void DudeSpeechEventHandler (object s, DudeSpeechEventArgs args); // El evento que emitiremos. public event DudeSpeechEventHandler MessageFromDude; public void StartBrainWashing () { for (int i=0; i < 5; i++) { if (MessageFromDude != null) MessageFromDude (this, new DudeSpeechEventArgs (msgs[i], i)); Thread.Sleep (3000); } } string[] msgs = {"Hey!. Garl!", "What's up, honey?", "Your nick is making me real horny ;)", "Do you have a webcam setup? 8)~", "Uh?", "FUU..."}; } public class DudeSpeechEventArgs : EventArgs { public DudeSpeechEventArgs (string msg, int index) { this.msg = msg; this.index = index; } public string Message { get { return msg; } set { msg = value; } } public int Index { get { return index; } } string msg; int index; }

Clase que se subscribe, guardadla en Chic.cs


// La clase a la que le toca aguantar a los dudes. using System; using System.Threading; public class Chic { public Chic () {

} public void Suscribe (Dude dude) { this.dude = dude; dude.MessageFromDude += new Dude.DudeSpeechEventHandler (message_received); } public void Unsuscribe (Dude dude) { dude.MessageFromDude -= new Dude.DudeSpeechEventHandler (message_received); } args) { private void message_received (object s, DudeSpeechEventArgs

Console.WriteLine ("&lt;dude&gt;: {0}", args.Message); if (args.Index < 3) { Thread.Sleep (4000); Console.WriteLine ("&lt;you&gt;: {0}", msgs[args.Index]); } else { Unsuscribe (dude); Console.WriteLine ("Connection reset by peer..."); } } private string[] msgs = {"hi.", "nothing. Just talking with a friend.", "really?"}; private Dude dude;

Otro ejemplo ms. Esta clase guardadla como Emisor.cs.


// Una clase simple que cada 3 segundos envia una senal using System; using System.Threading; public class Emisor { // Declaramos el delegado que 'envolvera' a las posibles retrollamadas conectadas // al evento SignalEmitted. public delegate void SignalEmittedEventHandler (object s, SignalEmittedEventArgs args); // El evento que emitiremos. public event SignalEmittedEventHandler SignalEmitted; public void Emit () { for (int i=0; i < 4; i++) { Thread.Sleep (3000); string time = DateTime.Now.Ticks.ToString (); if (SignalEmitted != null) SignalEmitted (this, new SignalEmittedEventArgs (time)); } }

} public class SignalEmittedEventArgs : EventArgs { public SignalEmittedEventArgs (string time) { this.time = time; } public string Time { get { return time; } set { time = value; } } string time; }

Mientras que esta la tenis que meter en Satellite.cs


// Una clase que recibe las senales de instancias // de tipo Emisor. using System; using System.Collections; public class Satellite { public Satellite (Emisor emisor) { emisors.Add (emisor); foreach (Emisor e in emisors) e.SignalEmitted += new Emisor.SignalEmittedEventHandler (signal_emitted); } private void signal_emitted (object s, SignalEmittedEventArgs args) { args.Time); } public void AdEmisor (Emisor emisor) { emisors.Add (emisor); } private ArrayList emisors = new ArrayList (); } Console.WriteLine ("Signal emitted at: {0}",

Ya solo os queda tener los experimentos que hacer. Os propongo estos: Experiment1.cs
// Un experimento simple que pone a prueba nuestras clases // Emisor and Satellite. using System; public class Experiment { static void Main () { Emisor emisor = new Emisor (); Satellite satellite = new Satellite (emisor); emisor.Emit ();

} }

y este otro:
// Una tipica charla del IRC using System; public class Experiment { static void Main () { Dude dude = new Dude (); Chic chic = new Chic (); chic.Suscribe (dude); dude.StartBrainWashing (); } }

Estos ejemplos los podis compilar con este makefile:


all: experiment1 experiment2 ############### Very first example of event-driven programming. experiment1: mcs -o experiment1.exe Experiment1.cs Satellite.cs Emisor.cs chmod +x experiment1.exe ############### Another example of event-driven programming. experiment2: mcs -o experiment2.exe Experiment2.cs Dude.cs Chic.cs chmod +x experiment2.exe clean: rm -rf *.exe rm -rf *~

Y eso es todo cuanto necesitis saber de los eventos para poder usarlos con soltura en vuestros programas y en particular para los que queris dar el salto y empezar a hacer aplicaciones GUI en Gtk#, GNOME# o Glade#.

Captulo 11. Programacin multihilo 11.1. Threads -- Programacin multihilo


La programacin con hilos, tambin conocida como multiproceso, tiene la ventaja de poder trabajar de manera asncrona. Esto permite que aquellos procesos que pueden requerir un tiempo ms o menos largo en llevarse a cabo se pongan a trabajar 'paralelamente' al proceso principal, de manera que la aplicacin pueda retomar el control y as el usuario seguir trabajando con ella.

Nota1: la programacin multihilo no es siempre la solucin correcta para todas las aplicaciones e incluso en algunos casos puede relentizar la aplicacin aunque parezca que no es as o cosas an peores como prdida de datos, etc. Nota2: la implementacin que hace Mono de las clases del espacio de nombres System.Threading est basada en los pthreads (los hilos POSIX que tan bien implementados estn en Linux) y es fcil comprobar que el paso de trabajar con unos a trabajar con otros es casi inmediato. Una buena referencia es el libro "Programacin Linux al descubierto" de Kurt Wall, as como la propia pthreads.h. Igualmente el recolector de basura que se usa hasta ahora en Mono (el GC de Bohem puede ser y debe ser compilado pasndole la opcin --enable-threads=pthreads Veamos los conceptos generales:

Hilo: un hilo de ejecucin es una unidad de procesamiento. Multitarea: la ejecucin simultnea de varios hilos.

La multitarea puede ser de dos tipos, uno de los cuales est bastante obsoleto y adems queda fuera de .NET de manera que no podremos usar los hilos de la mquina virtual en sistemas operativos que usen este clase primitiva de multitarea conocida como 'preferente'. El que vamos a usar nosotros es el tipo 'cooperativo'. La diferencia fundamental radica en que en el caso de la multitarea preferente el programador tiene que encargarse de liberar los hilos, etc, mientras que en la multitarea cooperativa el procesador asigna fracciones de tiempo de procesado a cada hilo y salta de hilo en hilo cada tiempo. Nota: los hilos y la forma de trabajar con ellos tal y como lo vamos a hacer aqu no es algo propio de C# sino que es extensible a todo el Framework de .NET (i.e. a cualquier lenguaje en .NET). Si en algn momento se est tratando alguna caracterstica exclusiva de C#, se comentar explictamente. As, quin ya posea conocimientos de Threads en .NET puede saltarse el resto de este tema. Nuestra receta para crear un hilo simple es como sigue:

Metemos el espacio de nombres System.Theading en nuestra clase. Asignamos qu mtodo ejecutar el hilo, para ello usamos un delegado de tipo ThreadStart que encapsule el mtodo. Creamos el hilo pasndole al constructor el delegado anteriormente creado. Ponemos el hilo en ejecucin.

Ya tenemos el procedimiento a seguir para crear una aplicacin multitarea elemental. Veamos el cdigo:
// Incluid esto en un mtodo cualquiera que queris que lance el nuevo // hilo. Por ejemplo en un Main. De hecho podemos hacer que Main solo // haga eso!. // metodo es un mtodo que queremos poner en un hilo aparte. ThreadStart delegadoQueGuardaElMetodo = new ThreadStart (metodo);

// creamos el hilo pasndole el delegado al constructor. Thread nuevoHilo = new Thread (delegadoQueGuardaElMetodo); // Empezamos a ejecutar el hilo. nuevoHilo.Start ();

Otra forma de instanciar un hilo es consiguiendo una referencia al hilo actual de ejecucin, esto se hace sin ms que llamar a la propiedad esttica Thread.CurrentThread.
Thread t = Thread.CurrentThread;

Dejadme un segundo que muestre el equivalente en pthreads de este ejemplo sencillo para que comprobis por vosotros mismos los que he comentado antes de la similitud Threads/pthreads:
#include <stdio.h> #include <stdlib.h>; #include <pthread.h>; void funcion(); int main (int argc, char *argv[]) { pthread_t pthrd1; /* declaramos el hilo */ int ret; /* el valor de retorno para gestionar el /* estado de lacreacin del hilo */ ret = pthread_create (&pthrd1, NULL, (void *) funcion, NULL); if (ret) { perror ("No se pudo crear el primer hilo"); exit (EXIT_FAILURE); } pthread_join (pthrd1, NULL); exit (EXIT_SUCCESS); } void funcion () { /* Ponle lo que quieras hacer aqui */ }

11.1.1. Controlando el tiempo de vida del hilo


Los mtodos fundamentales que se deben conocer si se quiere tener un control absoluto de los hilos en .NET son cinco: Thread.Sleep, Thread.Suspend, Thread.Resume,

Thread.Interrupt y Thread.Abort. Es ms, para casi todas las aplicaciones que vayis a desarrollar, os bastar con conocer Thread.Sleep!. Antes de ver cmo funcionan, presentmoslos:

Thread.Sleep (int time) -- Para el hilo durante 'time' milisegudos. Thread.Interrupt -- Interrumpe el hilo parada para que vuelva a la ejecucin antes de que se acabe 'time'. Thread.Suspend -- El hilo se queda suspendido hasta que otro hilo lo llame con Thread.Resume. Thread.Resume -- Recupera un hilo suspendido. Thread.Abort -- Destruye un hilo.

La utilizacin de esos mtodos es muy sencilla. Thread.Sleep acepta como parmetro el tiempo que se quiere que la hebra (o hilo, es lo mismo) permanezca dormida. Si le decimos Thread.Sleep (5000) se detendr durante cinco segundos o lo que es lo mismo, 5000ms.
// ms codigo por aqu... // Llamada a Thread.Sleep para parar la hebra durante 3 segundos Thread.Sleep (3000); // seguimos poniendo cdigo... // Para ver ejemplos completos mirar la seccin de Eventos de este mismo tutorial.

Si el valor pasado es 0 la hebra devolver devolver el resto del timeslice que le quedaba. Si por el contratio se le pasa Timeout.Infinite, el hilo se nos para indefinidamente hasta que alguna otra hebra llame al metodo Interrupt de la hebra suspendida. La diferencia fundamental entre Thread.Sleep y la otra manera de detener una hebra, llamando a Thread.Suspend, es que este ltimo puede ser invocado desde la hebra actual o desde otra. Adems, en caso de detener una hebra con Suspend, no podremos volver a ponerla en ejecucin hasta que no se haga desde otra con el mtodo Thread.Resume. (Nota: cuando se escriba este prrafo los mtodos Thread.Suspend y Thread.Resume estaban parcialmentemente implementados en Mono y cabe la posibilidad de que lo sigan estando cuando leis esto. Si vis que cdigo que los usa no funciona como debiera,i.e. los hilos no se suspenden cuando debieran, comprobad que no se lanz una excepcin del tipo NotImplementedException o ningn WARNING. Hace poco esos mtodos no hacan nada pero despus de intentar probar estos ejemplos aadimos esos avisos a la clase Thread). Por ltimo nos queda ver Thread.Abort. Thread.Abort es un mtodo un tanto particular. En caso de ser llamado, el CLI (o CLR), aborta el hilo lanzando una excepcin ThreadAbortException que no puede ser recogida. El CLI no permite recoger esa excepcin y lo ms que podremos hacer, si queremos hacer un cleanup, ser llevar a cabo las medidas oportunas dentro de un bloque finally. Hay que tener en cuenta que mono no detendr la ejecucin del hilo inmediatamente. Se esperar alcanzar un punto seguro para hacer esto y ese punto lo escoger mono. Si queris que el hilo deje de ejecutarse inmediatamente, podis hacer una llamada a Thread.Join que siendo una llamada sncrona dentendr el hilo hasta que se finalize la ejecucin.

Captulo 12. Sobrecarga de operadores 12.1. Sobrecarga de operadores


12.1.1. Qu es la sobrecarga de operadores ?
La sobrecarga de operadores es la capacidad para transformar los operadores de un lenguaje como por ejemplo el +, -, etc, cuando se dice transformar se refiere a que los operandos que entran en juego no tienen que ser los que admite el lenguaje por defecto. Mediante esta tecnica podemos sumar dos objetos creados por nosotros o un objeto y un entero, en vez de limitarnos a sumar numeros enteros o reales, por ejemplo. La sobrecarga de operadores ya era posible en c++ y en otros lenguajes, pero sorprendentemente java no lo incorpora asi que podemos decir que esta caracteristica es una ventaja de c# respesto a java, aunque mucha gente esta posibilidad no lo considera una ventaja por que complica el codigo. A la hora de hablar de operadores vamos a distinguir entre dos tipos, los unarios y los binarios. Los unarios son aquellos en que solo se requiere un operando, por ejemplo a+ +, en este caso el operando es 'a' y el operador '++'. Los operadores binarios son aquellos que necesitan dos operadores, por ejemplo a+c , ahora el operador es '+' y los operandos 'a' y 'c'. Es importante esta distincion ya que la programacion se hara de forma diferente Los operadores que podemos sobrecargar son los unarios, +, -, !, ~, ++, --; y los binarios +, -, *, /, %, &, |, ^, <<, >>. Es importante decir que los operadores de comparacion, ==, !=, <, >, <=, >=, se pueden sobrecargar pero con la condicion que siempre se sobrecargue el complementario, es decir si sobrecargamos el == debemos sobrecargar el !=.

12.1.2. Sobrecargando operadores en la practica


Para mostrar la sobrecarga vamos a usar el repetido ejemplo de los numeros complejos, ( aunque tambien valdria el de las coordenadas cartesianas ). Como se sabe los numeros complejos tienen dos partes, la real y la imaginaria, cuando se suma dos numeros complejos su resultado es la suma de las dos partes, para ello se va a crear una clase llamada ComplexNum que contendra ambas partes. Sin esta tcnica no se podria sumar dos objetos de este tipo con este practico mtodo, ya que esta clase no es vlida como operando de los operadores de c#. Empecemos con el cdigo de la clase de numeros imaginarios.
public class ComplexNum{ private float _img; private float _real;

public ComplexNum(float real, float img) { _img = img; _real = real; } public ComplexNum() { _img = 0; _real = 0; } public float getReal(){ return this._real; } public float getImg() { return this._img; } public String toString() { if (_img >= 0 ) return _real + "+" + _img +"i"; else return _real + "" + _img + "i"; } }

En el ejemplo hemos puesto la clase, con un par de constructores , dos getters para obtener los datos privados de la clase y un metodo que nos transfoma el numero complejo a cadena para que se pueda visualizarlo facilmente, a esta clase la iremos aadiendo mtodos para que tenga capacidad de usar operadores sobrecargados.

12.1.2.1. Operadores binarios


Para empezar vamos a sobrecargar el operador suma('+') para que al sumar dos objetos de la clase ComplexNum, es decir dos numeros complejos obtengamos otro numero complejo que sera la suma de ambas partes. Cabe destacar que los prototipos para sobrecargar operadores seran:
public static Operando operator+(Operando a, Operando b)

Este es el prototipo para el operador +, el resto de operadores binarios van a seguir el mismo patron. Por tanto el cdigo del mtodo de sobrecarga ser:
public static ComplexNum operator+(ComplexNum a, ComplexNum

b) {

return new ComplexNum(a.getReal() + b.getReal(), a.getImg() + b.getImg()); }

Este mtodo sobrecarga el operador suma para que podamos sumar dos numeros complejos. Un dato a tener en cuenta es que los mtodos que sobrecargan operadores deben ser static. Como se ve en el cdigo los operandos son 'a' y 'b', que se reciben como parametro y el resultado de la operacion es otro numero complejo que es el que retorna el mtodo. Por tanto se limita a crear un nuevo numero complejo con ambas partes operadas. De la misma forma podemos crear la sobrecarga del operador resta('-') para que lleve a cabo la misma funcin
public static ComplexNum operator-(ComplexNum a, ComplexNum

b) {

return new ComplexNum(a.getReal() - b.getReal(), a.getImg() - b.getImg()); }

Como vemos el metodo es identico solo q sustituyendo los + por -. En este caso el trabajo que hacemos dentro del metodo es trivial pero podria ser tan complejo como se quiera.

12.1.2.2. Operadores Unarios


En esta seccin se vera como sobrecargar los operadores unarios, es decir aquellos que toman un solo operando, como por ejemplo a++. El prototipo de los mtodos que van a sobrecargar operadores unarios ser:
public static Operando operator++(Operando a)

Como antes sustituyendo el ++ por cualquier operador unario. El ejemplo dentro de nuestra clase de numeros complejos sera:
public static ComplexNum operator++(ComplexNum a) { float auximg = a.getImg(); float auxreal = a.getReal(); return new ComplexNum(++auxreal, ++auximg); }

A primera vista puede quedar la duda si estamos sobrecargando la operacion ++a o a++. Este aspecto se encarga el compilador de resolverlo, es decir, se sobrecarga la operacion ++ y el compilador se encarga de sumar y asignar o asignar y sumar. Este problema no ocurria en C++, cosa que teniamos que manejar nosotros Como hemos dicho antes la operacion que hagamos dentro del metodo que sobrecarga el operador es totalmente libre, se puede poder el ejemplo de multiplicar dos matrices lo que es mas complejo que sumar dos numeros complejos

Captulo 13. Tratamiento de ficheros 13.1. Tratamiento de ficheros


13.1.1. La primera clase: System.IO.File
Esta clase estatica nos provee de las operaciones basicas a realizar con ficheros a nivel externo. Es una clase sellada, por lo que ninguna clase puede derivar de ella. Es una clase que hace los tests de permisos y seguridad en cada invocacion.

13.1.1.1. Metodo System.IO.File.AppendText()


StreamReader System.IO.File.AppendText(string camino)

Este metodo devuelve un StreamWriter (Explicado mas adelante) que nos permite aadir texto en formato UTF-8 al fichero especificado en la cadena"camino"

13.1.1.2. Metodo System.IO.File.Copy()


void System.IO.File.Copy(string org, string dest); void System.IO.File.Copy(string org, string dest, bool sobreescribe);

Este metodo nos permite copiar un fichero a otro lugar, el fichero org se copia en dest, el tercer parametro es si se debe sobreescribir o no el fichero destino

13.1.1.3. Metodo System.IO.File.Create()


TextWriter System.IO.File.Create(string camino); TextWriter System.IO.File.Create(string camino; int buffer);

Este metodo devuelve un TextWriter, crea o sobreescribe el fichero identificado por camino, el segundo parametro especifica el tamao del buffer a usar en el TextWriter creado

13.1.1.4. System.IO.File.CreateText()
StreamWriter System.IO.File.CreateText(string camino);

Este metodo devuelve un StreamWriter usando la codificacion UTF-8.

13.1.1.5. System.IO.File.Delete()
void System.IO.File.Delete(string camino);

Este metodo borra el fichero especificado en camino.

13.1.1.6. System.IO.File.Exists()
bool System.IO.File.Exists(string camino);

Este metodo borra el fichero especificado en camino.

13.1.1.7. System.IO.File.GetAttributes()
FileAttributes System.IO.File.GetAttributes(string ruta);

Este metodo devuelve la enumeracion FileAttributes y -1 si no existe la ruta.

13.1.1.8. System.IO.File.GetCreationTime()
DateTime System.IO.File.GetCreationTime(string ruta)

Devuelve un tipo DateTime que contiene la ficha del fichero asociado a esa ruta

13.1.1.9. System.IO.File.GetLastAccessTime()
DateTime System.IO.File.GetLastAccessTime(string ruta);

Devuelve un DateTime que contiene la fecha del ultimo acceso al fichero asociado a la ruta

13.1.1.10. System.IO.File.GetLastWriteTime()
DateTime System.IO.File.GetLastAccessTime(string ruta);

Devuelve un DateTime que contiene la fecha del ultimo acceso al fichero asociado a la ruta

13.1.1.11. System.IO.File.Move()
void System.IO.File.Move(string origen, string destino);

Mueve el fichero identificado por la cadena origen a destino.

13.1.1.12. System.IO.File.Open()
FileStream FileStream FileAccess FileStream System.IO.File.Open(string ruta, FileMode modo); System.IO.File.Open(string ruta, FileMode modo, modo_a); System.IO.File.Open(string ruta, FileMode modo,

FileAccess modo_a, FileShare modo_s);

Abre el fichero especificado por ruta, devuelve un FileStream asociado a el en los modos especificados

13.1.1.13. System.IO.File.OpenRead()
FileStream System.IO.File.OpenRead(string ruta);

Abre el fichero especificado para lectura y devuelve un FileStream asociado a el

13.1.1.14. System.IO.File.OpenText()
StreamReader System.IO.File.OpenText(string ruta);

Abre el fichero especificado para lectura y devuelve un StreamReader asociado a el.

13.1.1.15. System.IO.File.OpenWrite()
FileStream System.IO.File.OpenWrite(stream ruta);

Abre un fichero para escritura y devuelve un FileStream asociado a el.

13.1.1.16. System.IO.File.SetAttributes()
void System.IO.File.SetAttributes(string ruta,FileAttributes atribs);

Pone los atributos especificados en atribs al fichero especificado por la ruta.

13.1.1.17. System.IO.File.SetCreationTime()
void System.IO.File.SetCreationTime(string ruta, DateTime cr_tm);

Pone la fecha de creacion del archivo especificado en ruta a lo especificado en cr_tm

13.1.1.18. System.IO.File.SetLastAccessTime()
void System.IO.File.SetLastAccessTime(string ruta, DateTime la_tm);

Pone la fecha de ultimo acceso especificada en la_tm al fichero asociado a ruta.

13.1.1.19. System.IO.File.SetLastWriteTime()
void System.IO.File.SetLastWriteTime(string ruta, DateTime lw_tm);

Pone la fecha de la ultima escritura del archivo identificado en ruta, al valor especificado en lw_tm

13.1.1.20. Ejemplo de uso de la clase System.IO.File


TODO

13.1.2. Obteniendo informacion sobre archivos: System.IO.FileInfo


Una de las primeras cosas que interesa conseguir de un archivo es la informacion que el sistema operativo puede proveernos, tamao, localizacion, fechas de creacion, modificacion, acceso...; para ello la BCL nos provee de una clase (System.IO.FileInfo) que nos permite obtener informacion sobre un archivo.

Captulo 14. Interoperabilidad con cdigo nativo 14.1. Uso de Platform Invoke
14.1.1. Que es Platform Invoke ?
Platform Invoke o su abreviatura PInvoke es un metodo que tenemos en C# para poder llamar a funciones de otras librerias desde nuestros programas, como por ejemplo gtk+ en el caso de gtk# o a la propia api de windows desde un programa en C# para windows. El metodo que usa PInvoke es importar la funcion de la libreria donde reside declarandola dentro de nuestro programa y usando nuestros parametros de C#

14.1.2. Usando Platform Invoke


Para usar PInvoke primeramente como hemos dicho debemos importar la funcion, para ello usaremos la siguente sintaxis
[DllImport("libreria desde la que importamos la funcion")] -- Declaracion de la funcion --;

La forma de uso es sencilla y se ve que mediante la llamada DllImport indicamos la libreria donde se encuentra la funcion q pasamos a declarar para su siguiente uso

14.1.3. Ejemplo de uso


Para ver como funciona lo mas facil es ver un ejemplo
[DllImport("glade-2.0")] static extern IntPtr glade_xml_new(string fname, string root, string domain);

En el ejemplo lo que se hace es importar de la libreria glade-2.0 la funcion glade_xml_new. Como hemos dicho antes declaramos la funcion para nuestro uso, mientras que el prototipo original de la funcion dentro de libglade es
GladeXML* glade_xml_new (const char *fname, const char *root, const char *domain)

Con PInvoke lo declaramos para su uso en C# asi const char se convierte en string y el puntero a GladeXML en un puntero general en c#. Tambien es importante notar que la funcion la definimos como static y extern, denotando que puede ser llamada sin definir una clase y que esta definida externamente al codigo del programa Finalmente vamos a ver un ejemplo de importacion y llamada
[DllImport("gtk-x11-2.0")] static extern IntPtr gtk_button_new_with_mnemonic(string public Button(string label) { Raw = gtk_button_new_with_mnemonic(label); }

label);

El ejemplo esta tomado de la clase Button de la libreria Gtk#. Como vemos el metodo que se define es un constructor al que le pasamos el nombre que llevara el propio boton, dentro de gtk+ usamos la funcion gtk_button_new_with_mnemonic, por lo tanto la importamos desde la libreria gtk para llamarlo posteriormente. Al igual que antes los parametros cambian y el const gchar * que recibe la funcion en gtk+ lo cambiamos por el tipo string Una vez que tenemos importada la funcion y declarada en nuestro entorno el siguiente paso natural es usarla. Para ello en el ejemplo dentro del constructor llamamos a la funcion importada con el parametro que nos pasan.

14.1.4. Conclusiones

Para terminar es importante resaltar la gran utilidad que tiene este prodecimiento dentro de C# ya que podemos llamar a funciones dentro de otras librerias que estan escritas en otro lenguaje de programacion ( realmente no importa cual ). Esto es de una gran utilidad dentro de librerias que hacen de wrappers como es el caso de gtk# y gtk+

Captulo 15. Introspeccin 15.1. Introspeccin: El ojo que todo lo ve


Cdigo gestionado (managed code), la nueva palabra de moda dentro del mundo de la programacin, hace referencia a un nuevo tipo de cdigo que se ejecuta bajo el escrutinio de una mquina virtual, al cual nos permite conocer muchas cosas sobre ese cdigo, saber que va a hacer, de que cosas depende y muchas otras cosas. En realidad todos estos conceptos ya los tenamos en Java, por lo que se podra decir que el cdigo Java tambin es cdigo gestionado. Vamos a ver en esta seccin del tutorial de C# como se nos abren grandes posibilidades con este tipo de cdigo, que vamos a poder relacionarlo de forma sencilla con otras herramientas o que incluso vamos a poder modificar el cdigo que se ejecuta en funcin del contexto de ejecucin en el que se encuentre el programa. Lo primero que vamos a realizar es la presentacin de algunos conceptos que vamos a utilizar dentro de la seccin, para luego ir buceando en todos ellos.

15.1.1. Metadatos
El primer concepto con el que vamos a jugar es con el de metadatos, que se refiere al conjunto de descripciones que se hacen sobre los datos, lo que muchas veces se llama "los datos sobre los datos". En nuestro caso, los datos que vamos a describir con metadatos son el cdigo de nuestra aplicacin. Vamos a ir aadiendo al cdigo caractersticas que enriquezcan la interpretacin posterior y lo que se puede hacer con ese cdigo posteriormente. Los detalles sobre los datos, metadatos, tambin pueden ser detallados con otras descripciones, con lo que tenemos otro nivel de metadatos, es decir, "meta"-"metadatos". Como vemos el concepto de metadatos es algo abstracto pero vamos a comenzar a ver ejemplos reales que nos permitan tocar el suelo, y ver su gran utilidad.

15.1.2. Atributos
Los atributos son el pilar de los metadatos en C#. Con ellos vamos a poder especificar caractersticas de diferentes partes del cdigo C#. Segn donde situemos el atributo, se aplicar a una zona u otra (clase, mtodo, ensamblado ...). Tenemos atributos que ya

estn predefinidos dentro de C#, otros dentro de .NET, otros dentro de Mono y otros que nos podemos crear nosotros mismos. Los atributos no dejan de ser objetos de C#.

15.1.3. Cdigo gestionado: Integracin 15.1.4. Reflexin 15.1.5. Ejemplo prctico: rboles de Mono

Captulo 16. Manipulacin de archivos XML


Cuando Micrsoft lanz las primeras versiones de su plataforma .NET, nos sorprendi a todos por su apuesta por los estndares, lo cual constrastaba claramente con prcticas anteriores. El estndar ms importante adoptado en la plataforma .NET es sin duda XML. XML es una tecnologa tan integrada en .NET, que la propia plataforma utiliza XML internamente para sus archivos de configuracin y para su propia documentacin. XML es, por lo tanto, una tecnologa con una importancia fundamental en .NET.

16.1. Algunos conceptos de XML


XML es un lenguaje para estructurar datos. Sirve, por ejemplo, para almacenar en un archivo de texto una hoja de clculo, una libreta de direcciones o un dibujo vectorial. . XML hace mucho ms fcil al ordenador el proceso de generar datos, leer los datos y asegurarse de que la estructura de los datos no es ambigua. A su vez, contiene caractersticas que aseguran su validez durante mucho tiempo: es ampliable, independiente de plataforma, no pertenece a ninguna firma concreta de software y soporta internacionalizacin. El aspecto de un archivo XML es muy similar al de un archivo HTML, con texto encerrado entre etiquetas. Las etiquetas no son ms que palabras rodeadas por < y >. El siguiente podra ser un ejemplo de archivo XML que describe a la persona que escribe ste tutorial.
<?xml version="1.0"?> <persona> <nombre>Fabian</nombre> <apellido>Seoane</apellido>

<organizacion>Mono Hispano</organizacion> <pagina>http://fseoane.net</pagina> </persona>

La diferencia fundamental con HTML es que XML no tiene etiquetas predefinidas, sino que stas dependen de la implementacin. Por ejemplo, en el archivo que acabamos de ver, las etiquetas disponibles podran ser persona, nombre, appellido, ..., mientras que en un archivo XML que describa una librera, las etiquetas podran ser ensamblado, clase, metodo, etc. Todo sto podra parecer un lo increible si no se dispusiera de un mecanismo para traducir entre los diversos formatos XML, por ejemplo, entre el archivo persona y un archivo HTML que muestra la informacin sobre la persona. Por fortuna, esto existe, se llaman hojas XSL y la librera de clases dispone de mtodos para transformar entre XML a partir de hojas XSL. Si quieres saber ms sobre XML te sugiero que mires las siguientes pginas: http://w3.org/XML/, http://xml.com

16.2. Archivos XML


16.2.1. Escribir un archivo XML
Comenzaremos por escribir un sencillo archivo XML. En ste caso ser el ejemplo que acabamos de utilizar. El cdigo siguiente crea un documento llamado ejemplo.xml con un documento xml como el del ejemplo anterior.
using System; using System.Xml; class EjemploXml{ public static void Main() { XmlTextWriter writer = new XmlTextWriter("ejemplo.xml", System.Text.Encoding.UTF8); //Usa indentacin por legibilidad writer.Formatting = Formatting.Indented; //Escribe la declaracin del XML writer.WriteStartDocument(); //Escribe el elemento raiz writer.WriteStartElement("persona");

Hispano");

//Escribe los elementos dentro de sus etiquetas writer.WriteElementString("nombre", "Fabian"); writer.WriteElementString("apellido", "Seoane"); writer.WriteElementString("organizacion", "Mono

writer.WriteElementString("pagina", "http://fseoane.net"); writer.WriteEndElement(); writer.Flush(); writer.Close();

} }

Captulo 17. Creacin y uso de libreras


Usando las opciones correctas en la compilacin, C# genera libreras con sufijo dll que se pueden acceder directamente desde una aplicacin cliente.

17.1. Compilando para una librera


Esto es muy sencillo, simplemente especifcale al compilador la opcin -targe:library y te generar un archivo dll. Supongamos que nuestra librera es un archivo MisMetodos.cs con el siguiente cdigo:
namespace MisMetodos{ public class Mates { public static int Factorial( int n ) { int fact = n; for( int i = n-1; i> 0; i-- ) { fact = fact*i; } return fact; } } }

que simplemente contiene una funcin para calcular el factorial de un entero. Lo compilamos ahora con
mcs MisMetodos.cs -target:library

y obtendremos nuestra librera MisMetodos.dll

17.2. Usando nuestra libreria

Ahora nos falta construir una aplicacin cliente que utilize los mtodos definidos en nuestra librera. El cdigo de esta aplicacin podra ser la seguiente (supongamos que est en un archivos llamado MiApliCliente.cs):
using System; using MisMetodos; class MiApliCliente { public static void Main() { int n = Mates.Factorial(5); Console.WriteLine("5! = {0}", n ); } }

Ahora para compilar ste archivo debemos de referenciar la librera que acabamos de compilar. Referenciar una librea siempre se consigue dndole al compilador la opcin -r:ruta_a_la_libreria.dll. El nuestro caso sera algo as:
mcs MiApliCliente.cs -r:MisMetodos.dll

y cuando lo ejecutemos (mono MiAplicliente o ./MiApliCliente ) debera de producir la siguiente salida


5! = 120

Captulo 18. Autores


Para la versin 0.6 (octubre-2004):

Fabian Seoane, (fseoane), <fabian@fseoane.net>

Para la versin 0.5 (agosto-2004):

Fabian Seoane, (fseoane), <fabian@fseoane.net>

En versiones anteriores han colaborado las siguientes personas


Alejando Snchez, <raciel@x0und.net> Alvaro del Castillo, <acs@barrapunto.com> Eduardo Garca Cebollero, <kiwnix@yahoo.es> Csar Garca Tapia, <tapia@eitig.com> Sergio Gmez Bachiller, <Sergio.Gomez@consejo-eps.uco.es> Roberto Prez Cubero, <hylian@jazzfree.com> Jaime Anguiano Olarra, <jaime@gnome.org>

Bibliografa
Libros
Herbert Schild, Mc Graw Hill, Manual de referencia C#. Ecma-International, Estndar Ecma-334.

Artculos
Dare Obsanjo, MSDN, Understanding XML.

Das könnte Ihnen auch gefallen