Está en la página 1de 70

Estructuras de control

Hay dos maneras de cambiar el rumbo de ejecucin de un programa, estos pueden ser saltos incondicionales y saltos condicionales. En este captulo se describen algunas de estas sentencias. 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. [editar]Saltos incondicionales

Las instrucciones de un programa se ejecutan sentencia por sentencia empezando desde el mtodo o funcin principal llamado Main() hasta terminar con el programa. El programa sin embargo, tomar otros rumbos incondicionalmente en dos oportunidades: 1. Cuando encuentre la llamada a otros mtodos (Ejemplo 4.1) y 2. Con el uso de las palabras claves como goto, break, continue, return y throw las cuales se discutirn ms adelante. Ejemplo 4.1 - Salto incondicional a otra funcin using System; namespace Ejemplos{ class Ejemplo4_1{ static void Main(){ Console.WriteLine ("Esta parte se ejecuta primero"); LlamadaOtraFuncion(); Console.WriteLine ("Esta parte se ejecuta al final"); }

static void LlamadaOtraFuncion(){ Console.WriteLine ("Ha salido del mtodo Main()"); } } }

En el ejemplo anterior el programa ejecuta sentencia por sentencia el mtodo principal Main() hasta que encuentra la llamada a otro mtodo. Despus de que el mtodo llamado haya terminado el mtodo Main continuar con la ejecucin de las sentencias restantes. [editar]La sentencia goto En los inicios de los lenguajes de programacin la sentencia goto fue la ms popular para ir de un lugar a otro dentro del programa. Sin embargo esto creaba una tremenda confusin al momento de disear la aplicacin. Si el programador quera hacer un esquema de como funcionaba dicha aplicacin, se vea con un laberinto tipo espagueti de lneas y smbolos conectados entre si. Es por esto que esta sentencia es un poco "problemtica" y fuera de "moda" entre los lenguajes de programacin modernos. C# sin embargo soporta esta sentencia. Os recomendamos no utilizarla a menos que sea necesario o si os sents cmodos hacindolo, pero cuando os cree un laberinto difcil de depurar, no digis que no os advertimos de no utilizarla. Hay muchas otras mejores maneras de cumplir con el mismo propsito (la sentencia while por ejemplo es una de ellas), las cuales son ms elegantes y ms sencillas de depurar. La sentencia goto funciona de la siguiente manera: Primero se crea una etiqueta al inicio de cierto bloque de cdigo y despus en otro lugar podemos saltar hacia esa etiqueta usando la palabra clave goto. El siguiente ejemplo ilustra la sentencia goto: using System; namespace Ejemplos { class Ejemplo4_2 { static void Main() { int contador=0; REPETIR: Console.WriteLine ("Esta lnea se repetir 100 veces, esta es la linea numero: {0}", contador); if (contador++ < 100)

goto REPETIR; Console.WriteLine ("Despues de que el contador sea igual o mayor que 100 se imprimir esta lnea"); } } } Esta sentencia es un ejemplo de salto incondicional ya que por si solo saltar a la etiqueta seleccionada incondicionalmente. [editar]Saltos condicionales

Los saltos condicionales sirven para ejecutar cierto cdigo solamente si se cumple con alguna condicin. Entre otros tenemos: [editar]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 ) { instrucciones; ... } else { instrucciones; ... } 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 convertirla en un tipo numrico double, de forma que 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 condicionales, 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" Nota: Hay que tener mucho cuidado que el simbolo = no es igual a ==, el primero sirve para asignar un valor a una variable y el segundo sirve para comparar si dos trminos son iguales. [editar]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 ifelse-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( " + para sumarlos" ); - para restarlos" ); * para multiplicarlos" );

Console.WriteLine( "

/ para dividirlos (division entera)" );

s = Console.ReadLine();

switch(s){ case "+": Console.WriteLine("El resultado es {0}", 2+3); break; case "-": Console.WriteLine("El resultado es {0}", 2-3); break; case "*": Console.WriteLine("El resultado es {0}", 2*3); break; case "/": Console.WriteLine("El resultado es {0}", 2/3); break; default: Console.WriteLine("No te entiendo"); break; } } } 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 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 inclusive en el caso default. Siempre se deber tener un break o un goto en cada caso a menos que la sentencia est vaca. En esta situacin se ejecutar el siguiente caso que viene en la lista. Si no se toma en cuenta sto 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. Ejemplo: using System;

class InstruccionSwitch{ public static void Main() { int voto; Console.WriteLine( "Qu tipo de musica te gusta ms"); Console.WriteLine( "1 - Rock" ); Console.WriteLine( "2 - Clsica (clasica cuenta como instrumental)" ); Console.WriteLine( "3 - Instrumental" ); Console.WriteLine( "4 - Alternativa (alternativo cuenta como Rock)" );

voto = Int32.Parse(Console.ReadLine());

switch(voto){ case 1: Console.WriteLine("Has votado por Rock o Alternativo"); break; case 2: //Debido a que no tiene ni un goto ni break y est vaca va al siguiente caso case 3: Console.WriteLine("Has votado por Clsica o Instrumental"); break; case 4: goto case 1; default: Console.WriteLine("No te entiendo"); break; } } } Como bien se puede notar en el ejemplo, en el case 4, se utiliza la instruccin goto, indicando que se vaya al case 1, ya que segn la lgica del ejemplo, es igual elegir 1 o 4. Ntese que no es necesario usar break; en el case 4 ya que se utiliz goto. [editar]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 condiciones sean 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 por qu 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 condicional 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). [editar]Bucle while El bucle while es un bucle que se realiza mientras se cumpla determinada condicin. Tiene la forma while( condicin ) { instrucciones; } Donde la condicin tiene 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. [editar]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

using System;

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. [editar]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. [editar]Usando continue y break continue y break son dos palabras clave que nos permiten saltar incondicionalmente al inicio de un bucle (continue) o fuera de un bucle (break) cuando se necesite. Por ejemplo: using System;

class continueBreak { public static void Main() { for(int i = 0; i<10; i++ ) { if (i==5) continue; if (i==9) break; Console.Write("{0},",i); } } }

Este pequeo programa entrar en un bucle for que har que la variable i tome los valores del 1 al 10, pero al llegar al nmero 5 el bucle saltar incondicionalmente al inicio del bucle sin ejecutar las lneas que siguen ms adelante por lo que no ejecutar la lnea que imprime en la pantalla el nmero 5. Cosa similar sucede cuando llega al nmero 9: el bucle ser detenido por el salto incondicional break que romper el bucle cuando encuentre esta palabra. El resultado ser el siguiente: 0,1,2,3,4,6,7,8, El bucle salt la lnea que imprime 5 y termin cuando lleg a 9 gracias a las palabras clave continue y break.

SEGUNDO TUTORIAL
Versin para imprimir esta pagina Contenido [ocultar] 1 Introduccin a las clases en C# 1.1 Mtodos 1.2 Pasando valores a los mtodos 1.2.1 Parmetros 1.2.2 Paso por valor 1.2.3 Paso por referencia 1.2.4 Parmetro de salida 1.2.5 Arreglo de parmetros 1.3 Modificadores public y static 1.4 Constructores e instancias de una clase 1.5 Sobrecarga de mtodos 1.6 La palabra reservada this

2 Propiedades e indizadores 2.1 Propiedades 2.2 Indexadores [editar]Introduccin a las clases en C#

Como hemos dicho, C# es un lenguaje orientado a objetos. A diferencia de lenguajes como C++ o Python en los que la orientacin a objetos es opcional, en C# y al igual que en Java, la orientacin a objetos es ineludible, de hecho cualquier mtodo o variable est contenida dentro de un objeto. Y el concepto fundamental en torno a la orientacin a objetos es la clase.

Una clase es como una plantilla que describe cmo deben ser las instancias de dicha clase, de forma que cuando creamos una instancia, sta tendr exactamente los mismos 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. [editar]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 contenidos 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 a y b, ambos del tipo double, y el cuerpo del mtodo es simplemente "return a/b;". 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 Divide declarado antes, simplemente debemos escribir Divide(8, 2);

Segn lo que hemos visto, el ejemplo del mtodo Divide() completo necesita tener una clase donde definirse y un mtodo Main() donde ejecutarse. 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) ); } } [editar]Pasando valores a los mtodos [editar]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. [editar]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, ste parmetro solamente tena una copia del valor del parmetro a que pasamos al mtodo; por lo que cuando imprimimos el parmetro a vemos que ste parmetro ha mantenido su valor original. [editar]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. [editar]Parmetro de salida 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 num1, int num2, out int result, out int resid) { result = num1 / num2; resid = num1 % num2; } static void Main() { int valor1 = 10; int valor2 = 3; int respuesta, residuo; Divide(valor1, valor2, out respuesta, out residuo); Console.WriteLine("La divisin de {0} para {1} = {2} con un residuo de {3}", valor1, valor2, respuesta, residuo); } }

muestra un mtodo Divide que incluye dos parmetros de salida. Uno para el resultado (variable result) de la divisin y otro para el resto (variable resid). Vemos que estos resultados son asignados a las variables respuesta y residuo respectivamente. [editar]Arreglo de parmetros Habr ocasiones que necesitemos pasar varios parmetros a un mtodo (o funcin) pero no sabremos con anticipacin cuantos parmetros tendremos que pasar; para esto podremos usar un arreglo de parmetros. 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 parmetro especificado. El tipo del arreglo de parmetros debe ser siempre un tipo arreglo unidimensional. Al llamar a la funcin se puede pasar uno o varios argumentos 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 argumentos: 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 este captulo 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 pasa un pequeo nmero de argumentos, y un mtodo que usa un arreglo de parmetros. using System;

namespace System { public class Console { public static void WriteLine(string s) {...} public static void WriteLine(string s, object a) {...} public static void WriteLine(string s, object a, object b) {...} ... public static void WriteLine(string s, params object[] args) {...} }

} [editar]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 modificador 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. [editar]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 Punto 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 declarar una clase con varios constructores (cada uno con diferentes 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. [editar]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 dependiendo de los parmetros que le lleguen. Esto es muy prctico, pues 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) ); } } [editar]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 sintaxis 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; } } [editar]Propiedades e indizadores

[editar]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 modificar la variable, no inclumos el mtodo "set" y ya tendramos propiedades de slo lectura. [editar]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 6.

TERCER TUTORIAL
Herencia

La herencia es un concepto fundamental 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(). Finalmente 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(); } }

[editar]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"); } } [editar]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() } [editar]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.

[editar]Problemas propuestos Por escribir. Puedes colaborar escribiendo estos problemas. <<- Anterior (Captulo 5) | (Captulo 7) Siguiente->>

Versin para imprimir esta pagina Este cdigo me pareci interesante de compartir, una modesta recreacin del efecto matrix, escrita en C#. define readkey using System; namespace m7tr1x { class Program { static void Main(string[] args) { Console.Title = "tH3 M7tr1x 3ff3<t"; Console.ForegroundColor = ConsoleColor.DarkGreen; Console.WindowLeft = Console.WindowTop = 0; Console.WindowHeight = Console.BufferHeight = Console.LargestWindowHeight; Console.WindowWidth = Console.BufferWidth = Console.LargestWindowWidth; if readkey Console.WriteLine("H1T 7NY K3Y T0 C0NT1NU3 =/"); Console.ReadKey(); endif Console.CursorVisible = false; int width, height; int[] y; int[] l; Initialize(out width, out height, out y, out l);

int ms; while (true) { DateTime t1 = DateTime.Now; MatrixStep(width, height, y, l); ms = 10 - (int)((TimeSpan)(DateTime.Now t1)).TotalMilliseconds; if (ms> 0) System.Threading.Thread.Sleep(ms); if (Console.KeyAvailable) if (Console.ReadKey().Key == ConsoleKey.F5) Initialize(out width, out height, out y, out l); } } static bool thistime = false; private static void MatrixStep(int width, int height, int[] y, int[] l) { int x; thistime = !thistime; for (x = 0; x <width; ++x) { if (x % 11 == 10) { if (!thistime) continue;

Console.ForegroundColor = ConsoleColor.White; } else { Console.ForegroundColor = ConsoleColor.DarkGreen; Console.SetCursorPosition(x, inBoxY(y[x] - 2 - (l[x] / 40 * 2), height)); Console.Write(R); Console.ForegroundColor = ConsoleColor.Green; } Console.SetCursorPosition(x, y[x]); Console.Write(R); y[x] = inBoxY(y[x] + 1, height); Console.SetCursorPosition(x, inBoxY(y[x] - l[x], height)); Console.Write(' '); } } private static void Initialize(out int width, out int height, out int[] y, out int[] l) { int h1; int h2 = (h1 = (height = Console.WindowHeight) / 2) / 2; width = Console.WindowWidth - 1; y = new int[width]; l = new int[width]; int x;

Console.Clear(); for (x = 0; x <width; ++x) { y[x] = r.Next(height); l[x] = r.Next(h2 * ((x % 11 != 10) ? 2 : 1), h1 * ((x % 11 != 10) ? 2 : 1)); } } static Random r = new Random(); static char R { get { int t = r.Next(10); if (t <= 2) return (char)('0' + r.Next(10)); else if (t <= 4) return (char)('a' + r.Next(27)); else if (t <= 6) return (char)('A' + r.Next(27)); else return (char)(r.Next(32, 255)); } } public static int inBoxY(int n, int height)

{ n = n % height; if (n <0) return n + height; else return n; } } }

CUARTO TUTORIAL
Sobrecarga de operadores

[editar]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 tcnica podemos sumar dos objetos creados por nosotros o un objeto y un entero, en vez de limitarnos a sumar nmeros enteros o reales, por ejemplo. La sobrecarga de operadores ya era posible en c++ y en otros lenguajes, pero sorprendentemente java no lo incorpora, as que podemos decir que esta caracterstica es una ventaja de c# respecto a java, aunque mucha gente, esta posibilidad, no lo considera una ventaja porque complica el cdigo. A la hora de hablar de operadores vamos a distinguir entre dos tipos, los unarios y los binarios. Los unarios son aquellos que solo requieren 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 distincin ya que la programacin se har de forma diferente. Los operadores que podemos sobrecargar son los unarios, +, -, !, ~, + +, --; y los binarios +, -, *, /, %, &, |, ^, <<, >>. Es importante decir que los operadores de comparacin, ==, !=, <, >, <=, >=, se pueden sobrecargar pero con la condicin que siempre se sobrecargue el complementario, es decir, si sobrecargamos el == debemos sobrecargar el !=. [editar]Sobrecargando operadores en la prctica

Para mostrar la sobrecarga vamos a usar el repetido ejemplo de los numeros complejos, ( aunque tambin valdra el de las coordenadas cartesianas ). Como se sabe, los nmeros 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 contendr ambas partes. Sin esta tcnica no se podra sumar dos objetos de este tipo con este prctico mtodo, ya que esta clase no es vlida como operando de los operadores de c#. Empecemos con el cdigo de la clase de nmeros complejos. public class ComplexNum { private float img; private float real;

// constructor de la clase public ComplexNum(float real, float img) { this.real = real; this.img = img;

// propiedad Real public float Real{ get{ return real; } set{ real = value; } }

// propiedad Img public float Img{ get{ return img; } set{ img = value; } }

// Sobrescribimos el miembro ToString heredado de Object override public string ToString() {

if ( img >= 0 ) return real + "+" + img +"i"; else return real + "" + img + "i"; }

public static ComplexNum operator+(ComplexNum a, ComplexNum b) { return new ComplexNum(a.real + b.real, a.img + b.img); }

} En el ejemplo hemos puesto la clase, con un constructor , dos propiedades para obtener los datos privados de la clase y un mtodo que nos transfoma el nmero complejo a una cadena de caracteres para que se pueda visualizar fcilmente. Finalmente hemos sobrecargado el operador '+', de forma que podremos sumar dos nmeros complejos como si se tratara de nmeros usuales. [editar]Operadores binarios

Para empezar vamos a sobrecargar el operador suma('+') para que al sumar dos objetos de la clase ComplexNum, es decir dos nmeros complejos obtengamos un nmero complejo que ser la suma de ambas partes. Cabe destacar que los prototipos para sobrecargar operadores sern:

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 patrn. Por tanto el cdigo del mtodo de sobrecarga ser el siguiente:

public static ComplexNum operator+(ComplexNum a, ComplexNum b) { return new ComplexNum(a.Real + b.Real, a.Img + b.Img); }

Este mtodo sobrecarga el operador suma para que podamos sumar dos nmeros 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 parmetro y el resultado de la operacin es otro nmero complejo que es el que retorna el mtodo. Por tanto se limita a crear un nuevo nmero 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.Real - b.Real, a.Img - b.Img); }

Como vemos el mtodo es idntico solo que sustituyendo los + por -. En este caso el trabajo que hacemos dentro del mtodo es trivial pero podra ser tan complejo como se quisiera. [editar]Operadores Unarios

En esta seccin se ver cmo 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 nmeros complejos sera:

public static ComplexNum operator++(ComplexNum a) {

float auximg = a.Img; float auxreal = a.Real;

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 operacin ++ y el compilador se encarga de "sumar y asignar" o "asignar y sumar". Este problema no ocurra en C++, cosa que tenamos que manejar nosotros. Como hemos dicho antes, la operacin que hagamos dentro del mtodo que sobrecarga el operador es totalmente libre, se puede poner el ejemplo de multiplicar dos matrices lo que es mas complejo que sumar dos nmeros complejos.

<<- Anterior (Captulo 6) | (Captulo 8) Siguiente->> Versin para imprimir esta pagina Categora: C sharp NET

QUINTO TUTORIAL
Estructuras

La lista de similitudes entre clases y estructuras es larga: las estructuras pueden implementar interfaces, y pueden tener el mismo tipo de miembros que las clases. Sin embargo, las estructuras difieren de las clases en algunos puntos importantes: las estructuras son tipos por valor en lugar de tipos por referencia, y no permiten la herencia. Los valores de las estructuras quedan almacenados "en la pila" o "alineados". Los programadores cuidadosos pueden a veces mejorar el rendimiento mediante un uso meditado de las estructuras. Por ejemplo, el uso de una estructura ms bien que una clase para un Punto puede producir una gran diferencia en el nmero de asignaciones producidas en memoria en tiempo de ejecucin. El siguiente programa crea e inicializa un arreglo de 100 puntos. Con Punto implementado como clase, 101 objetos separados son inicializados ( uno para el vector y uno para cada uno de los 100 elementos ) class Punto { public int x, y; public Punto(int x, int y) { this.x = x; this.y = y; }

} class Test { static void Main() { Punto[] Puntos = new Punto[100]; for (int i = 0; i < 100; i++) { Puntos[i] = new Punto(i, i*i); } } }

Si Punto fuera implementado como una estructura, como en struct Punto { public int x, y; public Punto(int x, int y) { this.x = x; this.y = y; } }

nicamente un objeto es inicializado: el elemento del arreglo. Las instancias de Punto se almacenan de forma alineada en el arreglo. Esta optimizacin puede ser mal usada. Usar estructuras en lugar de clases tambin puede hacer que una aplicacin funcione ms lento o utilice

ms memoria, pues pasar una instancia de estructura por valor provoca que una copia de esa estructura sea creada. [editar]Rendimiento

Como hemos dicho, la principal ventaja por la que se usan en determinadas circunstancias estructuras y no clases es que en circunstancias particulares stas demuestran mucho mejor rendimiento. Escrito por: XXX TODO: ejemplo que lo demuestre

SEXTO TUTORIAL
Definicin

Una Interfaz es una coleccin de miembros abstractos relacionados semnticamente. Una interfaz representa un comportamiento que una clase dada puede soportar. El nmero de miembros de una interfaz dependen del comportamiento que queramos soportar, por ejemplo todos los objetos que sean mviles podran querer soportar los mtodos acelerar y frenar. Segn la interfaz de C# una interfaz sera: public interface IMovil { bool Acelerar(int n); bool Frenar(int n); } Tambin podramos declarar dentro de la interfaz una propiedad que nos permita leer y/o escribir la velocidad que queremos que tome nuestro objeto. public interface IMovil

{ bool Velocidad{get; set;} } Dado que una interfaz es una coleccin de miembros abstractos cualquier clase o estructura que quiera implementar una interfaz est obligada a implementar cada uno de los mtodos que se declaran en la interfaz. De esta forma se consigue un cierto tipo de polimorfismo ya que si varias clases implementan la misma estructura tenemos la posibilidad de tratar con todas ellas de la misma forma. Seguramente alguien se preguntara por que usar interfaces pudiendo usar una clase base abstracta definiendo los mtodos anteriores como abstractos, la primera razn es simplicidad, una clase base abstracta suele hacer ms que definir una coleccin de mtodos, es capaz de definir mtodos pblicos, privados, protegidos y tambin metodos concretos (estticos) a los que pueden acceder todas las clases que deriven de ella mientras que una interfaz se limita a definir una coleccin de mtodos sin ninguna implementacin. La segunda razn es que C# solamente soporta herencia simple, pero sin embargo podemos hacer que una clase implemente mltiples interfaces. He aqu como haramos para heredar de una clase base e implementar una interfaz, teniendo en cuenta que VehiculoDeMotor sera nuestra clase base e IMovil nuestra interfaz. public class CocheDeportivo : VehiculoDeMotor, IMovil { //Implementacin de los mtodos abstractos de vehculo

bool Acelerar(int n) { //implementacin de Acelerar } bool Frenar(int n)

{ //implementacin de Frenar } } Hay que tener en cuenta que siempre hay que poner la clase base antes de las interfaces. Ahora nuestra clase CocheDeportivo as como cualquier otra clase que implemente IMovil podra acelerar y frenar, hay que tener en cuenta que si implementamos IMovil tendremos que implementar absolutamente todos sus mtodos. [editar]Obteniendo Referencias a la Interfaz

Si hemos creado la clase CocheDeportivo podemos querer saber si ste soporta el comportamiento de IMovil de modo que podemos hacer un cast explcito: CocheDeportivo coche1 = new CocheDeportivo(); IMovil movil = (IMovil) coche1; movil.Acelerar(30); En caso de que nuestro objeto implemente la interfaz podramos operar sobre l con todos los mtodos de la misma, pero en caso de que no la soporte tendramos un error en tiempo de ejecucin, con lo cual la forma correcta de hacerlo es: CocheDeportivo coche1 = new CocheDeportivo(); try{ IMovil movil = (IMovil) coche1; movil.Acelerar(30); } catch(InvalidCastException e){

//gestin del error } Otra forma de hacerlo sin tener que recurrir a la gestin de excepciones sera utilizando la palabra reservada as de C#: CocheDeportivo coche1 = new CocheDeportivo(); IMovil movil; movil = coche1 as IMovil; if (movil != null) movil.Frenar(10); else //otro tratamiento La palabra reservada as pone la variable de tipo interfaz a null si la interfaz dada no est soportada por el objeto. Por ltimo tambin podemos usar la palabra reservada is de C# para descubrir si un objeto implementa o no una interfaz: CocheDeportivo coche1 = new CocheDeportivo(); if (coche1 is IMovil) coche1.Acelerar(10); else //otra gestin [editar]Pasar interfaces como parmetros

Las interfaces son tipos de datos fuertemente tipados (valga la redundancia) de modo que se pueden pasar como parmetros a mtodos y se pueden usar tambin como valores de retorno. Hemos creado la interfaz IGiro de la siguiente manera: public interface IGiro

{ void GirarDerecha(int grados); void GirarIzquierda(int grados); } Y queremos que nuestro coche deportivo pueda girar a izquierda y derecha: public class CocheDeportivo : VehiculoDeMotor, IMovil, IGiro { //Implementacin de los mtodos abstractos de vehculo

bool Acelerar(int n) { //Implementacin de Acelerar } bool Frenar(int n) { //Implementacin de frenar } void GirarDerecha(int grados) { //Implementacin de GirarDerecha } void GirarIzquierda(int grados) { //Implementacin de GirarIzquierda

} } Como hemos visto para soportar otra interfaz simplemente la aadimos al final despus de una ",". Ahora supongamos que queremos hacer un mtodo que nos provea de utilidades para el giro por ejemplo hacer trompos, le podramos pasar una interfaz IGiro de la siguiente forma public class UtilsGiro { public static void Trompo(IGiro giro) { giro.GirarIzquierda(360); } } [editar]Implementacin Explcita de una Interfaz

Siguiendo con nuestro ejemplo de los coches definimos una nuevas interfaces: public interface IAltaVelocidad { void Turbo(bool activar); //resto de metodods } Como se puede ver nuestra interfaz implementa un mtodo Turbo. Qu pasara si una clase heredase a su vez de la clase Formula Uno que tambin implemente el metodo void Turbo (bool)? Bueno vamos a verlo:

public class Campeon : Formula1, IAltaVelocidad { public override void Turbo(bool activar) { //gestion del turbo } } Esto en un principio sera correcto pero qu pasa si hacemos lo siguiente: Campeon miCampeon = new Campeon(); miCampeon.Turbo(true);

IAltaVelocidad iav = (IAltaVelocidad) miCampeon; iav.Turbo(true); Ambas veces se llamara al mismo mtodo, el definido en la clase Formula1, pero como haramos si quisiramos tener dos Turbos diferentes? la respuesta es hacer que los mtodos definidos en la interfaz sean slo accesibles desde una referencia a la interfaz, esto es lo que se llama implementacin explcita de una interface. public class Campeon : Formula1, IAltaVelocidad { public override void Turbo(bool activar) { //gestin del turbo }

void IAltaVelocidad.Turbo(bool activar)

{ //gestin del turbo } } El segundo mtodo slo podr ser llamado si usamos una referencia de tipo IAltaVelocidad mientras que el primero podr ser llamado usando una referencia a Campeon o a Formula1 (su clase base). Existen algunas reglas extra al hacer esto, por ejemplo no podemos usar modificadores de accesibilidad (public, private, protected) ya que si intentamos que slo se pueda acceder al mtodo desde una referencia a la interfaz hacerlo sera contraproducente. Tambin hay que tener en cuenta que pueden haber colisiones de nombres entre clases base e interfaces y entre interfaces entre si, tcnicamente no existe ninguna diferencia y todas pueden ser tratadas como hemos explicado arriba. [editar]Jerarquas de interfaces

Las interfaces pueden servir de base para otras interfaces al igual que las clases, e igual que en stas la idea es que vayamos de lo general a lo particular. Por ejemplo: interface IVehiculo { void Acelerar(); void Frenar(); } interface IVehiculoGasolina : IVehiculo { void CambiarVelocidadInyeccion(int velocidad);

} interface IVehiculo4x4: IVehiculoGasolina { void Activar4x4(bool activar); } Al implementar una de estas interfaces en nuestra clase tenemos que implementar todos los mtodos de esta interfaz y de sus ancestros. public class CocheDeJuguete : IVehiculo { void IVehiculo.Acelerar(int n) { //Gestin del acelerado } void IVehiculo.Frenar(int n) { //Gestin del frenado } } public class CocheNormal:IVehiculoGasolina { void IVehiculo.Acelerar(int n) { //Gestin del acelerado } void IVehiculo.Frenar(int n)

{ //Gestin del frenado } void IVehiculoGasolina.CambiarVelocidadInyeccion(int velocidad) { //Gestin de la inyeccion } } public class TodoTerreno:IVehiculo4x4 {

void IVehiculo.Acelerar(int n) { //Gestin del acelerado } void IVehiculo.Frenar(int n) { //Gestin del frenado } void IVehiculoGasolina.CambiarVelocidadInyeccion(int velocidad) { //Gestin de la inyeccion } void IVehiculo4x4.Activar4x4(bool activar) {

//Gestin de 4x4 } } Y lgicamente las llamadas a los mtodos seran: TodoTerreno miTodoTerreno = new TodoTerreno(); ((IVehiculo4x4)miTodoTerreno).Acelerar(20); ((IVehiculo4x4)miTodoTerreno).Frenar(20); ((IVehiculo4x4)miTodoTerreno).CambiarVelocidadInyeccion(1000); ((IVehiculo4x4)miTodoTerreno).Activar4x4(true); <<- Anterior (Captulo 8) | (Captulo 10) Siguiente->> Versin para imprimir esta pagina Categora: C sharp NET

SEPTIMO TUTORIAL

También podría gustarte