Estructuras de control

Hay dos maneras de cambiar el rumbo de ejecución de un programa, estos pueden ser saltos incondicionales y saltos condicionales. En este capítulo 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 más específicas. [editar]Saltos incondicionales

Las instrucciones de un programa se ejecutan sentencia por sentencia empezando desde el método o función 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 métodos (Ejemplo 4.1) y 2. Con el uso de las palabras claves como goto, break, continue, return y throw las cuales se discutirán más adelante. Ejemplo 4.1 - Salto incondicional a otra función 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 método Main()"); } } }

En el ejemplo anterior el programa ejecuta sentencia por sentencia el método principal Main() hasta que encuentra la llamada a otro método. Después de que el método llamado haya terminado el método Main continuará con la ejecución de las sentencias restantes. [editar]La sentencia goto En los inicios de los lenguajes de programación la sentencia goto fue la más popular para ir de un lugar a otro dentro del programa. Sin embargo esto creaba una tremenda confusión al momento de diseñar la aplicación. Si el programador quería hacer un esquema de como funcionaba dicha aplicación, se veía con un laberinto tipo espagueti de líneas y símbolos conectados entre si. Es por esto que esta sentencia es un poco "problemática" y fuera de "moda" entre los lenguajes de programación modernos. C# sin embargo soporta esta sentencia. Os recomendamos no utilizarla a menos que sea necesario o si os sentís cómodos haciéndolo, pero cuando os cree un laberinto difícil de depurar, no digáis que no os advertimos de no utilizarla. Hay muchas otras mejores maneras de cumplir con el mismo propósito (la sentencia while por ejemplo es una de ellas), las cuales son más elegantes y más sencillas de depurar. La sentencia goto funciona de la siguiente manera: Primero se crea una etiqueta al inicio de cierto bloque de código y después 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 línea 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 línea"); } } } 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 código solamente si se cumple con alguna condición. Entre otros tenemos: [editar]Instrucción if Esta sentencia sirve para ejecutar unas instrucciones en caso de que se cumpla determinada condición. La forma completa de la instrucción if es if( condición ) { instrucciones; ... } else { instrucciones; ... } donde la cláusula else es opcional. Si la condición es verdadera, se ejecutarán 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;

if( d>0 ) { Console.ReadLine() ).ReadLine() estamos leyendo lo que el usuario introduce por pantalla.Parse( Console. que es una cadena de caractéres. de forma que tendrá el valor del número que introduzcamos por la consola. Console. con Console. tal vez requiera algo de explicación adicional. d). Las intrucciones if se pueden anidar. y existe también una extensión de la . En realidad. La sentencia d = Double. } else { Console. y con Double.class InstruccionIf{ public static void Main() { double d.WriteLine("Introduce un numero"). d). d = Double.Parse( Console.WriteLine("El numero {0} es negativo". } } } te pide que introduzcas un número y dependiendo de si se cumple que dicho número es mayor que cero (condición).WriteLine("El numero {0} es positivo".Parse lo que hacemos es interpretar esa cadena de caractéres y convertirla en un tipo numérico double. se ejecuta un bloque u otro.ReadLine() ).

La última instrucción else actúa como condición predeterminada. se ejecutará la última instrucción else. . class IfElseIf{ public static void Main() { string opcion. se realiza esta última instrucción. si no funciona ninguna de las otras pruebas condicionales. Su formato es el siguiente: if( condicion1 ) { instrucciones. la sentencia if-else-if. Si no existe esta instrucción else final y el resto de de las condiciones son falsas. Tan pronto como se encuentra una condición true. entonces no se realizará ninguna acción. else { instrucciones. se ejecuta la instrucción asociada con ella..sentencia if.. El siguiente ejemplo using System. es decir. } . Si ninguna de las condiciones es true. } Las instrucciones condicionales se evalúan de arriba a abajo. y el resto de la escalera se omite. } else if( condicion2 ) { instrucciones.

Funciona de la siguiente manera: el valor de una expresión se prueba sucesivamente con una lista de constantes. } else if( opcion=="no" ) { Console. 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 ==. entonces se ejecuta la sentencia else por defecto. } } } le pide al usuario que elija una opción si/no y la procesa usando una estructura if-else-if. Cuando se encuentra una coincidencia. [editar]Instrucción switch La instrucción switch es muy parecida a la estructura if-else-if. opcion = Console. if( opcion=="si" ) { Console. Si la opción no es ni "si" ni "no". ha elegido si" ).WriteLine("No entiendo lo que ha escrito").WriteLine( "Ha elegido no" ). sólo que permite seleccionar entre varias alternativas de una manera más cómoda.WriteLine( "Muy bien.WriteLine("Elija una opción (si/no)"). } else{ Console. La forma general de la instrucción switch es la siguiente: . se ejecuta la secuencia de instrucciones asociada con esa coincidencia.Console. el primero sirve para asignar un valor a una variable y el segundo sirve para comparar si dos términos son iguales.ReadLine().

WriteLine( " + para sumarlos" ). default: instrucciones. case constante2: instrucciones. Sin más. . . break.WriteLine( " Console.para restarlos" ).WriteLine( "Elige hacer algo con los números 2 y 3"). * para multiplicarlos" ).. break. } La sentencia default se ejecutará sólo si ninguna constante de las que siguen a case coincide con expresión. vamos a por un ejemplo using System. .. class InstruccionSwitch{ public static void Main() { string s.switch( expresión ){ case constante1: instrucciones. break. Console. Es algo similar al else final de la instrucción ifelse-if.WriteLine( " Console. Console.

WriteLine("No te entiendo").WriteLine( " / para dividirlos (division entera)" ). default: Console. que es la cadena de caracteres que almacena la elección del usuario. 2+3). case "*": Console.Console. case "-": Console. break.WriteLine("El resultado es {0}". 2/3).ReadLine(). El resultado debería ser algo parecido a esto: . } } } El cual solicita al usuario que inserte uno de los símbolos +-*/ .WriteLine("El resultado es {0}". switch(s){ case "+": Console. break.WriteLine("El resultado es {0}". break. break. y con un switch compara los resultados para hacer diferentes acciones dependiendo del valor de s. break. case "/": Console.WriteLine("El resultado es {0}". 2*3). 2-3). s = Console.

class InstruccionSwitch{ public static void Main() { int voto. En esta situación se ejecutará el siguiente caso que viene en la lista. Si no se toma en cuenta ésto se obtiene un error en tiempo de compilación.WriteLine( "Qué tipo de musica te gusta más").para restarlos * para multiplicarlos / para dividirlos (division entera) * El resultado es 6 Como habrá notado. Console.WriteLine( "1 . como C/C++ o Java no tienen esta restricción.Elige hacer algo con los números 2 y 3 + para sumarlos .WriteLine( "2 .Alternativa (alternativo cuenta como Rock)" ).Rock" ). y así permitir su optimización. al final de todo case siempre hay una sentencia break. . Console. Console.WriteLine( "4 .Clásica (clasica cuenta como instrumental)" ). elimina muchos errores comunes y en segundo lugar permite al compilador reorganizar las sentencias de los case. Esto no es obligatorio. Console. La razón de adoptarla en C# es doble: por un lado. puede haber en su lugar otra sentencia de salto como un goto inclusive en el caso default.WriteLine( "3 . Console. Otros lenguajes. Siempre se deberá tener un break o un goto en cada caso a menos que la sentencia esté vacía.Instrumental" ). Ejemplo: using System.

} } } Como bien se puede notar en el ejemplo.WriteLine("No te entiendo"). default: Console.WriteLine("Has votado por Rock o Alternativo"). en el case 4 ya que se utilizó goto. break. switch(voto){ case 1: Console. case 2: //Debido a que no tiene ni un goto ni break y está vacía va al siguiente caso case 3: Console. break. indicando que se vaya al case 1. ya que según la lógica del ejemplo. iteración ) . [editar]Bucle for El bucle for de C# es idéntico al encontrado en los lenguajes C/C++ y Java. se utiliza la instrucción goto. es igual elegir 1 o 4. en el case 4. Nótese que no es necesario usar break.Parse(Console. condición. break.voto = Int32. case 4: goto case 1.WriteLine("Has votado por Clásica o Instrumental"). El formato general es for( inicialización.ReadLine()).

de forma que. se pueden usar dos variables . de hecho se pueden utilizar varias sentencias separadas por comas. Es un caso muy simple del bucle for. class BucleFor{ public static void Main() { int i. Por cierto. 9++ es 10. Pero todo esto se entiende mejor con un ejemplo using System. Las sentencias de iteración se ejecutan también 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 condición. por su parte. se ejecutan cada vez que el bucle vuelve al principio y sirven para controlar el bucle: éste seguirá realizándose siempre y cuando estas condiciones sean true. } } } Este ejemplo imprime por pantalla los 10 primero enteros positivos. Las sentencias de condición. Por ejemplo. la variable i se incrementa a cada vuelta.WriteLine( i ). //el contador for( i = 0. i++) { Console. pero esto no tiene por qué ser así. En el ejemplo anterior.{ instrucciones. De esta forma. las sentencias de inicialización y de iteración eran únicas. } Las sentencias de inicialización se ejecutan una vez al principio y sirven principalmente para asignar valores a las variables que servirán de contador. el operador ++ lo que hace es que añade una unidad a la variable a la que acompaña. por ejemplo. i < 10.

para controlar el bucle using System. i. int j. Tiene la forma while( condición ) { instrucciones. i++. Tiene una estructura muy sencilla. class BucleFor2{ public static void Main() { int i. j--) { Console. "true" (el bucle se realizará indefinidamente) o "false" (el bucle no se realizará). En este caso se ha usado "i<j". [editar]Bucle while El bucle while es un bucle que se realiza mientras se cumpla determinada condición. i<j. } Donde la condición tiene que ser un valor booleano. la expresión condicional del bucle for puede ser cualquier expresión que genere un valor booleano. así que vamos a ver directamente un ejemplo. {1} )". for( i=0. } } } Por su parte. j). j=10. .WriteLine("( {0} . pero también hubiera sido válida "i==5".

[editar]Bucle do-while Se trata de una ligera variante del bucle anterior.using System. class BucleWhile{ public static void Main() { int i = 0. . sólo que ahora con un bucle while. El siguiente ejemplo using System. } } } En el que se realiza lo mismo que en el ejemplo anterior.WriteLine( i ). con la diferencia de que ahora primero se ejecutan las instrucciones y luego se evalúa la condición. while( i<10) { Console. i = i+1. de forma que tiene tiene una estructura: do{ instrucciones. } while( condición ).

!= es lo contrario de ==. como pueden ser los enteros dentro de un arreglo de enteros. . s = Console. } } muestra un programa que ejecuta un bucle hasta que el usuario introduce "si".class BucleDoWhile{ public static void Main() { string s = "".WriteLine( "Introduce si para salir del bucle" ). } while( s != "si" ). La sintaxis sigue la siguiente estructura: foreach( tipo in coleccion ) { instrucciones. Por cierto. es decir. el uso más inmediato es iterar sobre un arreglo de números: using System. do { Console. != devuelve true cuando los valores comparados son distintos. } Como hemos comentado. [editar]Bucle foreach El bucle foreach se utiliza para hacer iteraciones sobre elementos de una colección.ReadLine().

class BucleForeach{ public static void Main() { int i. foreach( int elem in arr ) { Console. pero como se puede comprobar mejora mucho la claridad del código comparándolo con una implementación con bucles for como esta using System.3}}. i++ ) { for( j = 0. for(i = 0.2}. j.] arr = {{1.class BucleForeach{ public static void Main() { int[.{2. //seran los indexadores de la matriz int[. j++ ) { . } } } Este ejemplo sólo imprime los valores de una matriz. i<2.] arr = {{1.2}.3}}.{2. j<2.WriteLine( elem ).

Console. } } } .j] ). Por ejemplo: using System. no solo con arreglos. [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. } } } } Además. como veremos más adelante. class continueBreak { public static void Main() { for(int i = 0.WriteLine( arr[i.".Console.i). if (i==9) break. es posible utilizar el bucle foreach con cualquier tipo que sea una colección.Write("{0}. i<10. i++ ) { if (i==5) continue.

2 Paso por valor 1.1.2.5 Sobrecarga de métodos 1.6. El bucle saltó la línea que imprime 5 y terminó cuando llegó a 9 gracias a las palabras clave continue y break.4 Constructores e instancias de una clase 1.2.8.5 Arreglo de parámetros 1. SEGUNDO TUTORIAL Versión para imprimir esta pagina Contenido [ocultar] 1 Introducción a las clases en C# 1.Este pequeño programa entrará en un bucle for que hará que la variable i tome los valores del 1 al 10.1 Parámetros 1.3. El resultado será el siguiente: 0.3 Paso por referencia 1.3 Modificadores public y static 1.7.2 Pasando valores a los métodos 1.2.2.6 La palabra reservada this .4 Parámetro de salida 1. Cosa similar sucede cuando llega al número 9: el bucle será detenido por el salto incondicional break que romperá el bucle cuando encuentre esta palabra. pero al llegar al número 5 el bucle saltará incondicionalmente al inicio del bucle sin ejecutar las líneas que siguen más adelante por lo que no ejecutará la línea que imprime en la pantalla el número 5.2.2.1 Métodos 1.4.

2 Propiedades e indizadores 2.1 Propiedades 2.2 Indexadores [editar]Introducción 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 orientación a objetos es opcional, en C# y al igual que en Java, la orientación a objetos es ineludible, de hecho cualquier método o variable está contenida dentro de un objeto. Y el concepto fundamental en torno a la orientación a objetos es la clase.

Una clase es como una plantilla que describe cómo deben ser las instancias de dicha clase, de forma que cuando creamos una instancia, ésta tendrá exactamente los mismos métodos y variables que los que tiene la clase. Los datos y métodos 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 método Main se creará una instancia de Clase1 llamada MiClase. Una buena idea es jugar un poco con el código para ver que la instancia de la clase efectivamente tiene los mismos miembros que la clase Clase1 (que sería la plantilla de la que hablábamos 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, también podemos incluir métodos. 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(); }

En C#. La estructura mínima de un método tiene las siguientes partes: * Tipo devuelto * Nombre del método * Parámetros (puede ser vacío) * Cuerpo del método de forma que el siguiente método: double Divide( double a. Para llamar al . son trozos de código que reciben unos datos. hacen algo con esos datos. ambos del tipo double. pero en este capítulo nos centraremos en el uso de métodos y variables. Cuando queramos llamar a un método. tiene por nombre Divide. y a veces devuelven algún valor.".} Podemos hacer más cosas con las clases. y el cuerpo del método es simplemente "return a/b. double b ) { return a/b. debemos simplemente poner el nombre del método y sus argumentos dentro de un paréntesis separados por comas. } devuelve un tipo double. los parámetos son a y b. también llamados funciones. todos los métodos se encuentran contenidos dentro de un objeto. como heredar otras clases o implementar interfaces. [editar]Métodos Los métodos.

class Metodo{ public double Divide( double a. 2) ).método Divide declarado antes. } } class Principal{ public static void Main() { Metodo m = new Metodo().WriteLine( m. double b ) { return a/b. 2).Divide(8. using System. } } [editar]Pasando valores a los métodos [editar]Parámetros . Console. simplemente debemos escribir Divide(8. el ejemplo del método Divide() completo necesita tener una clase donde definirse y un método Main() donde ejecutarse. Según lo que hemos visto.

y arreglos de parámetros. Console. por lo que las modificaciones que le hagamos al parámetro dentro del método no afectarán al parámetro original. Console. por referencia. Cuando se pasa un parámetro por valor a una función realmente se está pasando una copia de dicho parámetro. } static void Main() { int a = 1. El ejemplo using System.La declaración formal de parámetros también define variables. a). a).WriteLine("p = {0}". F(a).WriteLine("pre: a = {0}". class Test { static void F(int p) { p++. p). parámetros de salida.WriteLine("post: a = {0}". } } . Hay cuatro tipos de parámetros: parámetros por valor. Console. [editar]Paso por valor El paso de parámetros por valor es usado por defecto para pasar parámetros a métodos.

muestra un método F que tiene un parámetro por valor llamado p. El ejemplo produce la salida: pre: a = 1 p=2 post: a = 1 aunque el valor del parámetro p haya sido modificado dentro del método. class Test { static void Swap(ref int a. por lo que cuando imprimimos el parámetro a vemos que éste parámetro ha mantenido su valor original. éste parámetro solamente tenía una copia del valor del parámetro a que pasamos al método. En el paso por referencia no se realiza ninguna copia del objeto. sino que lo que se le pasa a la función es una referencia del objeto. de forma que el parámetro pasa directamente a la función y cualquier modificación sobre el parámetro dentro de la función afectará al parámetro original using System. . [editar]Paso por referencia El paso de parámetros por referencia es la contraposición lógica al paso por valor. ref int b) { // intercambia los dos valores int t = a. a = b.

x. y = 1 La palabra clave ref debe de ser usada tanto en la declaración formal de la función como en los usos que se hace de ésta. x. Un argumento de salida se declara con el modificador out. [editar]Parámetro de salida El parámetro de salida es similar al parámetro por referencia. y = {1}". y). Swap(ref x. y = 2 post: x = 2. } } muestra un método swap que tiene dos parámetros por referencia.WriteLine("post: x = {0}. y). y = {1}".WriteLine("pre: x = {0}. } static void Main() { int x = 1. ref y). int y = 2. Console. . Console. La salida producida es: pre: x = 1.b = t. salvo que el valor inicial de dicho argumento carece de importancia. El ejemplo using System.

int num2. valor2. Un arreglo de . } } muestra un método Divide que incluye dos parámetros de salida. Divide(valor1.WriteLine("La división de {0} para {1} = {2} con un residuo de {3}".class Test { static void Divide(int num1. [editar]Arreglo de parámetros Habrá ocasiones que necesitemos pasar varios parámetros a un método (o función) pero no sabremos con anticipación cuantos parámetros tendremos que pasar. valor1. Console. out int result. Uno para el resultado (variable result) de la división y otro para el resto (variable resid). int valor2 = 3. int respuesta. out respuesta. respuesta. resid = num1 % num2. } static void Main() { int valor1 = 10. residuo). out residuo). para esto podremos usar un arreglo de parámetros. residuo. out int resid) { result = num1 / num2. valor2. Vemos que estos resultados son asignados a las variables respuesta y residuo respectivamente.

los arreglos de parámetros permiten listas de argumentos de tamaño variable. i. for (int i = 0. Un arreglo de parámetros se declara con el modificador params. i++) Console. args. En otras palabras. Sólo puede haber un arreglo de parámetros en cada método. . } static void Main() { F().Length).Length.WriteLine("args[{0}] = {1}". i < args. 2). F(1. F(1).parámetros permite guardar una relación de varios a uno: varios argumentos pueden ser representados por un único arreglo de parámetros.WriteLine("nº de argumentos: {0}". El ejemplo using System. Al llamar a la función se puede pasar uno o varios argumentos del tipo del arreglo. class Test { static void F(params int[] args) { Console. El tipo del arreglo de parámetros debe ser siempre un tipo arreglo unidimensional. args[i]). y siempre debe ser el último parámetro especificado.

2. 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 . } } muestra un método F que toma un número variable de argumentos int.F(1. F(new int[] {1. 3. 2. 3). 4}). y varias llamadas a este método.

..WriteLine("a = {0}.. object a. public static void WriteLine(string s.} . se consigue usando un arreglo de parámetros. namespace System { public class Console { public static void WriteLine(string s) {. El comportamiento para las sustituciones. b = 2.} public static void WriteLine(string s. El método WriteLine proporciona varios métodos sobrecargados para el caso común en el que se pasa un pequeño número de argumentos..La mayoría de los ejemplos presentes en este capítulo utilizan el método WriteLine de la clase Console...} } . params object[] args) {. b = {1}". object b) {. object a) {.. y un método que usa un arreglo de parámetros.. a. Console.. b). como muestra el ejemplo int a = 1.. using System.} public static void WriteLine(string s.

} [editar]Modificadores public y static El modificador public lo hemos utilizado anteriormente. Console.Divide(8. double b ) { return a/b. y como es de esperar. esto es. 2) ). Se puede utilizar en la declaración de cualquier método o variable. } } class Principal{ public static void Main() { Metodo m = new Metodo(). } } Si por ejemplo intentamos declarar el método Divide sin el . class Metodo{ public double Divide( double a. produce el efecto de que el campo afectado se vuelve público. se puede utilizar desde otras clases using System.WriteLine( m.

using System.cs Además. obtendremos un error en tiempo de compilación. El modificador complementario de public es private. llamados por ejemplo metodo. pero como contrapartida.cs . Los métodos estáticos se caracterizan por no necesitar una instancia de la clase para cumplir su función. que provoca que el método o dato solo sea accesible desde la clase en la que está declarado. Para eso debemos anteponer a la declaración del método el modificador static.cs y principal. Si no se especifica nada.modificador public. double b ) { return a/b. } } class Principal{ . no pueden acceder a datos propios de la clase. bastará compilar ambos archivos al mismo tiempo. class Metodo{ public static double Divide( double a. de forma similar a esto: mcs principal.cs metodo. tampoco es necesario crear una instancia de la clase sólo para acceder a un método declarado en ella. se toma por defecto el modificador private De esta forma podríamos separar las clases Metodo y Principal en dos archivos separados. Para compilar esto.

el método Console. las instancias de una clase se crean con la sintaxis nombreclase objeto = new nombreclase( argumentos ). Por ejemplo.WriteLine( Metodo. de forma que tiene dos valores públicos X e Y. } } Los métodos estáticos se utilizan en multitud de situaciones.WriteLine() o las funciones de la librería matemática estándar no son más que métodos estáticos de sus respectivas clases. Una vez creada una clase. etc. ). sus miembros se inicializan a sus valores predeterminados ( cero para valores numéricos. 2) ). [editar]Constructores e instancias de una clase Como hemos visto. donde nombreclase es el nombre que le hemos dado a la definición de la clase. y un método que calcula la distancia al origen del punto (módulo) using System. . La siguiente clase representa un punto sobre el plano.Divide(8.public static void Main() { Console. cadena vacía para el tipo string. argumentos es una lista de argumentos posiblemente vacía y objeto es el nombre que queremos darle a la instancia de la clase.

d = Math. A.X = 1. Console.class Punto{ public double X.Sqrt(X*X + Y*Y).Y = 1. public double Y. public double Modulo() { double d.1) es: . A.WriteLine("El modulo del punto (1. } } class Principal{ public static void Main() { Punto A = new Punto(). //Sqrt = raiz cuadrada return d.

de forma que podemos construir nuestro propio constructor que le diga a la clase los valores por defecto que debe tomar. } public double Modulo() . class Punto{ public double X.Modulo() ). se puede personalizar. A. } } Ahora bien. La clase Punto con un constructor sería así: using System. Y = 1. es decir. la forma en la que se crea la instancia.{0}". inicializando los datos a cero (ejercicio: comprobar esto). public Punto() //constructor { X = 1. public double Y. Esto se realiza simplemente escribiendo dentro de la clase un método que tenga el mismo nombre que la clase y en el que no se especifica el valor devuelto.

d = Math. } . } También tenemos la posibilidad de declarar una clase con varios constructores (cada uno con diferentes parámetros) Lo que hará el compilador de C# es buscar el constructor . que era el que se creaba por defecto. double val2) { X = val1. En la práctica se utilizan mucho constructores con parámetos. par ya contendrá los valores (1. Y = val2. } } de forma que ahora al crear una instancia de la clase se crea el punto (1. de forma que al crear la instancia se le asignan valores según los parámetros. //Sqrt = raiz cuadrada return d.1) en lugar del (0.. De esta forma.0). La siguiente implementación de Par contiene un constructor que acepta un par de valores.. al crear la instancia. que servirán para inicializar los valores A y B class Punto{ public Punto( double val1.1) .Sqrt(X*X + Y*Y).{ double d.

que se adecúe a los parámetros que le llegan. [editar]Sobrecarga de métodos En C#. pues no tienes que renombrar cada función según el tipo de valor que acepta. al igual que en C++ y en Java es posible definir varios métodos con el mismo nombre pero con distintos parámetros. se tendría que haber llamado distinto a ambos métodos. El siguiente ejemplo implementa un par de métodos que elevan al cuadrado el valor que reciben. . y ejecutarlo como si fuera un método más. usaremos un constructor u otro. } public static double AlCuadrado( double a ) { return a*a. Esto es muy práctico. class Eleva{ public static double AlCuadrado( int a ) { return a*a. por ejemplo alcuadrado_double y alcuadrado_int using System. Dependiendo de la llamada que se haga en el "new". que es un lenguaje que no soporta sobrecarga de métodos. y se implementan para tipos double y para int. de forma que el compilador decide a cuál se llama dependiendo de los parámetros que le lleguen. En C.

En el siguiente ejemplo. Eleva. } } [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.AlCuadrado(3.2) ).WriteLine("4 al cuadrado es {0}".AlCuadrado(4) ).WriteLine("3. Console. que toma dos argumentos X e Y.2 al cuadrado es {0}".} } class Principal{ public static void Main() { Console.campo donde campo es la variable de la clase a la que queremos hacer referencia. ya sea por motivos de colisión de nombres o por la claridad del código. Entonces es obligado el uso de this para distinguir entre el X de la clase y el X tomado como parámetro . declaramos un constructor para la clase Punto. Su sintaxis es this. Eleva.

Para los programadores de Java hay que decir que esto no es más que la formalización del patrón de asignación (setter) y método de lectura (getter) Las propiedades son como métodos 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. Complejo(double X. double Y. Este valor viene especificado en la variable value ) .Y = Y. this.X = X. } } [editar]Propiedades e indizadores [editar]Propiedades Las propiedades son una característica de C# que permiten aparentemente el acceso a un miembro de la clase mientras mantiene el control asociado al acceso mediante métodos.class Complejo { double X. double Y) { this.

class TestProperties { private static string clave.WriteLine ("Cambio del valor de clave").WriteLine ("Acceso a la propiedad clave"). return clave. } set { Console. } } } class Test { public static void Main () { TestProperties tp = new TestProperties(). clave = value.using System. . public string Clave { get { Console.

Console. Si no queremos que se pueda modificar la variable.Clave = c.Clave). no incluímos el método "set" y ya tendríamos propiedades de sólo lectura. class PruebaIndexadores { private int[] tabla = {1. 4}. 3. } } En realidad. Los indexadores nos van a permitir hacer algo parecido.string c = "ClaveClave". Lo vemos de forma más sencilla con un ejemplo: using System. . 2. que podemos acceder a una variable privada de una clase a través de eventos que nos permiten controlar la forma en la que accedemos a dicha variable. en el apartado en el que tratamos las propiedades.WriteLine (tp. Nos van a permitir acceder a una clase como si se tratara de un arreglo. tp. [editar]Indexadores Hemos visto. y se crean dos métodos ( o uno si solo se requiere acceso de lectura) que permiten acceder al contenido de la variable y tal vez modificarla. lo que se hace es declarar una variable privada de forma que no se puede acceder de forma directa.

por lo que no podremos acceder a él desde fuera de nuestra clase. que será donde hagamos las pruebas.WriteLine ("La posicion {0} de la tabla tiene el valor {1}". Pero hemos declarado también un indexador (public int this [int indice]). return tabla[indice]. que nos permitirá acceder a él de forma más controlada. Primero creamos un objeto de la clase PruebaIndexadores: . } set { Console. } } } Tenemos una clase PruebaIndexadores en la que hay un array llamado "tabla". tabla[indice] = value. declarado como privado.public int this [int indice] { get { Console.WriteLine ("Escrito el valor {0} en la posición {1} de la tabla". Para probar esta clase. creamos otra clase con un punto de entrada (public static void Main ()). indice. tabla[indice]). value. indice).

Al ser una consulta de lectura. en este caso 3. se ejecuta el código que haya en la parte "get" del indexador. 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. pasándole como parámetro el índice. Lo que aparecerá en pantalla una vez ejecutado esto será: Escrito el valor 6 en la posición 3 de la tabla . Una vez ejecutado. Esta línea lo que hace es llamar al indexador. Luego accedemos a una posición del indexador: int a = obj[3].PruebaIndexadores obj = new PruebaIndexadores ().

La sintaxis que se utiliza es la siguiente: class MiClaseDerivada : MiClaseBase . Y esta vez nos aparecerá esto: La posicion 3 de la tabla tiene el valor 6. ya que el indexador no tiene forma de saber qué variable se supone que tiene que manejar. Si no pusiéramos esa línea. de forma que una clase puede derivar de otra.Nótese que tenemos que hacer explícitamente el acceso al array (tabla[indice]=value) en el set. en C# todas las clases derivan implícitamente de la clase object. en realidad el indexador no cambiaría el valor del array. 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 más algunos que opcionalmente puede implementar ella misma Las clases en C# soportan herencia simple. De hecho. Para comprobar que realmente se ha hecho el cambio. TERCER TUTORIAL Herencia La herencia es un concepto fundamental de la programación orientada a objetos. pero no de varias (como si era posible en C++). volvemos a acceder al indexador: a = obj[3].

} } class B : A{ public void G() { Console. Posteriormente definimos una clase B que hereda A y además define un método G(). } } .{ //miembros } En el siguiente ejemplo definimos una clase A con un método F(). Finalmente creamos una clase con un método Main() que llamará a los dos métodos de B.WriteLine("Soy G() de B"). class A{ public void F() { Console. al implementado por B y al heredado using System.WriteLine("Soy F() de A").

Su sintaxis es idéntica a la de this. } } [editar]Clases Abstractas .F().class Principal{ public static void Main() { B clase_heredada = new B().F(). esto es: base.nombre_del_miembro En el siguiente ejemplo declaramos una clase B que hereda A y que utiliza el método F() de A. } } [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. Console. clase_heredada.G().WriteLine("soy H() de B"). clase_heredada. class B : A{ public void H() { base.

Las clases que heredan una clase abstracta deben implementar los métodos incompletos. class A { public virtual void F() { Console.WriteLine("A. B tiene que definir un método F() } [editar]Miembros virtual Métodos. lo que significa que su implementación puede ser sobreescrita en clases derivadas. Por lo tanto. El ejemplo using System. que está definido pero no implementado. propiedades e indexadores pueden ser virtual.F"). no se pueden instanciar y su único propósito es servir de clase base de las que se derivarán otras clases. } . Las clases abstractas se declaran con la palabra reservada abstract using System. //metodo no implementado } class B : A{ //error en tiempo de compilación. abstract class A{ public void F(). esto es.Las clases abstractas son clases que contienen algún método incompleto.

El método sobreescrito en B contiene una llamada. y una clase B que sobreescribe F.Anterior (Capítulo 5) | (Capítulo 7) Siguiente->> . base.F(). b. <<. Console. } } class Test { public static void Main() { B b = new B(). a. A a = b.F"). } } muestra una clase A con un método virtual F.F().WriteLine("B.F(). [editar]Problemas propuestos Por escribir. Puedes colaborar escribiendo estos problemas.} class B: A { public override void F() { base.F(). el cual llama al método sobreescrito en A.

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

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

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

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

Mediante esta técnica podemos sumar dos objetos creados por nosotros o un objeto y un entero. } } } 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 +. por ejemplo. en este caso el operando es 'a' y el operador '++'. A la hora de hablar de operadores vamos a distinguir entre dos tipos. así que podemos decir que esta característica es una ventaja de c# respecto a java. no lo considera una ventaja porque complica el código. por ejemplo a++. en vez de limitarnos a sumar números enteros o reales. esta posibilidad. else return n. Los unarios son aquellos que solo requieren un operando. pero sorprendentemente java no lo incorpora. Los operadores binarios son aquellos que necesitan dos . -. 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. La sobrecarga de operadores ya era posible en c++ y en otros lenguajes. if (n <0) return n + height. aunque mucha gente.{ n = n % height. los unarios y los binarios. etc.

Los operadores que podemos sobrecargar son los unarios. Es importante decir que los operadores de comparación. los números complejos tienen dos partes. ahora el operador es '+' y los operandos 'a' y 'c'. &. ==. [editar]Sobrecargando operadores en la práctica Para mostrar la sobrecarga vamos a usar el repetido ejemplo de los numeros complejos. --. >=. ya que esta clase no es válida como operando de los operadores de c#. ~. la real y la imaginaria. public class ComplexNum { private float img. + +. this. // constructor de la clase public ComplexNum(float real. y los binarios +. ^. ( aunque también valdría el de las coordenadas cartesianas ). Empecemos con el código de la clase de números complejos. .operadores. >>. <=. es decir. cuando se suma dos numeros complejos su resultado es la suma de las dos partes. se pueden sobrecargar pero con la condición que siempre se sobrecargue el complementario. Es importante esta distinción ya que la programación se hará de forma diferente. Sin esta técnica no se podría sumar dos objetos de este tipo con este práctico método.real = real. *. float img) { this. por ejemplo a+c . +. Como se sabe. -. !. !=. %.img = img. >. -. <. private float real. <<. para ello se va a crear una clase llamada ComplexNum que contendrá ambas partes. si sobrecargamos el == debemos sobrecargar el !=. |. /.

} set{ img = value.} // propiedad Real public float Real{ get{ return real. } set{ real = value. } } // propiedad Img public float Img{ get{ return img. } } // Sobrescribimos el miembro ToString heredado de Object override public string ToString() { .

ComplexNum b) { return new ComplexNum(a. Finalmente hemos sobrecargado el operador '+'.real + b. dos propiedades para obtener los datos privados de la clase y un método que nos transfoma el número complejo a una cadena de caracteres para que se pueda visualizar fácilmente. [editar]Operadores binarios Para empezar vamos a sobrecargar el operador suma('+') para que al sumar dos objetos de la clase ComplexNum. Operando b) . es decir dos números complejos obtengamos un número complejo que será la suma de ambas partes. con un constructor .if ( img >= 0 ) return real + "+" + img +"i".img).img + b. de forma que podremos sumar dos números complejos como si se tratara de números usuales. } public static ComplexNum operator+(ComplexNum a.real. Cabe destacar que los prototipos para sobrecargar operadores serán: public static Operando operator+(Operando a. } } En el ejemplo hemos puesto la clase. a. else return real + "" + img + "i".

} Como vemos el método es idéntico solo que sustituyendo los + por -. De la misma forma podemos crear la sobrecarga del operador resta('-') para que lleve a cabo la misma función: public static ComplexNum operator-(ComplexNum a. Un dato a tener en cuenta es que los métodos que sobrecargan operadores deben ser static. Por tanto se limita a crear un nuevo número complejo con ambas partes operadas. el resto de operadores binarios van a seguir el mismo patrón.Real.Img .Real . Por tanto el código del método de sobrecarga será el siguiente: public static ComplexNum operator+(ComplexNum a. ComplexNum b) { return new ComplexNum(a.Img + b.Img). ComplexNum b) { return new ComplexNum(a. Como se ve en el código los operandos son 'a' y 'b'.Real + b.b. que se reciben como parámetro y el resultado de la operación es otro número complejo que es el que retorna el método.Img). [editar]Operadores Unarios .Real.b. } Este método sobrecarga el operador suma para que podamos sumar dos números complejos. a. a.Este es el prototipo para el operador +. En este caso el trabajo que hacemos dentro del método es trivial pero podría ser tan complejo como se quisiera.

return new ComplexNum(++auxreal.En esta sección se verá cómo sobrecargar los operadores unarios. es decir aquellos que toman un solo operando.Real. Este problema no ocurría en C++. la operación que hagamos dentro del método que sobrecarga el operador es totalmente libre. ++auximg). como por ejemplo a++. float auxreal = a. . es decir. El prototipo de los métodos que van a sobrecargar operadores unarios será: public static Operando operator++(Operando a) Como antes sustituyendo el ++ por cualquier operador unario. cosa que teníamos que manejar nosotros. } A primera vista puede quedar la duda si estamos sobrecargando la operacion ++a o a++.Img. Este aspecto se encarga el compilador de resolverlo. Como hemos dicho antes. El ejemplo dentro de nuestra clase de números complejos sería: public static ComplexNum operator++(ComplexNum a) { float auximg = a. se puede poner el ejemplo de multiplicar dos matrices lo que es mas complejo que sumar dos números complejos. se sobrecarga la operación ++ y el compilador se encarga de "sumar y asignar" o "asignar y sumar".

public Punto(int x. 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. this.<<. y pueden tener el mismo tipo de miembros que las clases. int y) { this.x = x. Los programadores cuidadosos pueden a veces mejorar el rendimiento mediante un uso meditado de las estructuras. Los valores de las estructuras quedan almacenados "en la pila" o "alineados".y = y. 101 objetos separados son inicializados ( uno para el vector y uno para cada uno de los 100 elementos ) class Punto { public int x. El siguiente programa crea e inicializa un arreglo de 100 puntos. el uso de una estructura más bien que una clase para un Punto puede producir una gran diferencia en el número de asignaciones producidas en memoria en tiempo de ejecución. Por ejemplo.Anterior (Capítulo 6) | (Capítulo 8) Siguiente->> Versión para imprimir esta pagina Categoría: C sharp NET QUINTO TUTORIAL Estructuras La lista de similitudes entre clases y estructuras es larga: las estructuras pueden implementar interfaces. Sin embargo. Con Punto implementado como clase. y.

} class Test { static void Main() { Punto[] Puntos = new Punto[100]. Las instancias de Punto se almacenan de forma alineada en el arreglo. for (int i = 0. } } } Si Punto fuera implementado como una estructura.x = x. i*i). public Punto(int x. this. Usar estructuras en lugar de clases también puede hacer que una aplicación funcione más lento o utilice . int y) { this.y = y. i < 100. } } únicamente un objeto es inicializado: el elemento del arreglo. y. como en struct Punto { public int x. Esta optimización puede ser mal usada. i++) { Puntos[i] = new Punto(i.

pues pasar una instancia de estructura por valor provoca que una copia de esa estructura sea creada. } También podríamos 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 . El número de miembros de una interfaz dependen del comportamiento que queramos soportar.más memoria. [editar]Rendimiento Como hemos dicho. por ejemplo todos los objetos que sean móviles podrían querer soportar los métodos acelerar y frenar. 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. Una interfaz representa un comportamiento que una clase dada puede soportar. Según la interfaz de C# una interfaz sería: public interface IMovil { bool Acelerar(int n). Escrito por: XXX TODO: ejemplo que lo demuestre SEXTO TUTORIAL Definición Una Interfaz es una colección de miembros abstractos relacionados semánticamente. bool Frenar(int n).

Seguramente alguien se preguntara por que usar interfaces pudiendo usar una clase base abstracta definiendo los métodos anteriores como abstractos. protegidos y también metodos concretos (estáticos) a los que pueden acceder todas las clases que deriven de ella mientras que una interfaz se limita a definir una colección de métodos sin ninguna implementación. IMovil { //Implementación de los métodos abstractos de vehículo bool Acelerar(int n) { //implementación de Acelerar } bool Frenar(int n) . es capaz de definir métodos públicos. la primera razón es simplicidad.{ bool Velocidad{get. pero sin embargo podemos hacer que una clase implemente múltiples interfaces. una clase base abstracta suele hacer más que definir una colección de métodos. teniendo en cuenta que VehiculoDeMotor sera nuestra clase base e IMovil nuestra interfaz. La segunda razón es que C# solamente soporta herencia simple. public class CocheDeportivo : VehiculoDeMotor. privados.} } Dado que una interfaz es una colección de miembros abstractos cualquier clase o estructura que quiera implementar una interfaz está obligada a implementar cada uno de los métodos que se declaran en la interfaz. He aquí como haríamos para heredar de una clase base e implementar una 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. set.

Acelerar(30).Acelerar(30). movil. IMovil movil = (IMovil) coche1.{ //implementación de Frenar } } Hay que tener en cuenta que siempre hay que poner la clase base antes de las interfaces. try{ IMovil movil = (IMovil) coche1. Ahora nuestra clase CocheDeportivo así como cualquier otra clase que implemente IMovil podra acelerar y frenar. En caso de que nuestro objeto implemente la interfaz podríamos operar sobre él con todos los métodos de la misma. con lo cual la forma correcta de hacerlo es: CocheDeportivo coche1 = new CocheDeportivo(). [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 explícito: CocheDeportivo coche1 = new CocheDeportivo(). hay que tener en cuenta que si implementamos IMovil tendremos que implementar absolutamente todos sus métodos. pero en caso de que no la soporte tendríamos un error en tiempo de ejecución. movil. } catch(InvalidCastException e){ .

if (movil != null) movil. Hemos creado la interfaz IGiro de la siguiente manera: public interface IGiro .Acelerar(10). IMovil movil. Por último también podemos usar la palabra reservada is de C# para descubrir si un objeto implementa o no una interfaz: CocheDeportivo coche1 = new CocheDeportivo(). movil = coche1 as IMovil.Frenar(10). if (coche1 is IMovil) coche1. 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. else //otra gestión [editar]Pasar interfaces como parámetros Las interfaces son tipos de datos fuertemente tipados (valga la redundancia) de modo que se pueden pasar como parámetros a métodos y se pueden usar también como valores de retorno.//gestión del error } Otra forma de hacerlo sin tener que recurrir a la gestión de excepciones sería utilizando la palabra reservada as de C#: CocheDeportivo coche1 = new CocheDeportivo().

IMovil. IGiro { //Implementación de los métodos abstractos de vehículo bool Acelerar(int n) { //Implementación de Acelerar } bool Frenar(int n) { //Implementación de frenar } void GirarDerecha(int grados) { //Implementación de GirarDerecha } void GirarIzquierda(int grados) { //Implementación de GirarIzquierda . void GirarIzquierda(int grados).{ void GirarDerecha(int grados). } Y queremos que nuestro coche deportivo pueda girar a izquierda y derecha: public class CocheDeportivo : VehiculoDeMotor.

} } Como hemos visto para soportar otra interfaz simplemente la añadimos al final después de una ". } } [editar]Implementación Explícita de una Interfaz Siguiendo con nuestro ejemplo de los coches definimos una nuevas interfaces: public interface IAltaVelocidad { void Turbo(bool activar).".GirarIzquierda(360). Ahora supongamos que queremos hacer un método que nos provea de utilidades para el giro por ejemplo hacer trompos. //resto de metodods } Como se puede ver nuestra interfaz implementa un método Turbo. ¿Qué pasaría si una clase heredase a su vez de la clase Formula Uno que también implemente el metodo void Turbo (bool)? Bueno vamos a verlo: . le podríamos pasar una interfaz IGiro de la siguiente forma public class UtilsGiro { public static void Trompo(IGiro giro) { giro.

pero como haríamos si quisiéramos tener dos Turbos diferentes? la respuesta es hacer que los métodos definidos en la interfaz sean sólo accesibles desde una referencia a la interfaz. el definido en la clase Formula1.Turbo(bool activar) . Ambas veces se llamaría al mismo método. IAltaVelocidad { public override void Turbo(bool activar) { //gestión del turbo } void IAltaVelocidad. miCampeon.public class Campeon : Formula1. iav. esto es lo que se llama implementación explícita de una interface. public class Campeon : Formula1. IAltaVelocidad { public override void Turbo(bool activar) { //gestion del turbo } } Esto en un principio sería correcto pero qué pasa si hacemos lo siguiente: Campeon miCampeon = new Campeon().Turbo(true). IAltaVelocidad iav = (IAltaVelocidad) miCampeon.Turbo(true).

técnicamente no existe ninguna diferencia y todas pueden ser tratadas como hemos explicado arriba. Existen algunas reglas extra al hacer esto. void Frenar(). por ejemplo no podemos usar modificadores de accesibilidad (public. Por ejemplo: interface IVehiculo { void Acelerar(). e igual que en éstas la idea es que vayamos de lo general a lo particular. } interface IVehiculoGasolina : IVehiculo { void CambiarVelocidadInyeccion(int velocidad). private. protected) ya que si intentamos que sólo se pueda acceder al método desde una referencia a la interfaz hacerlo sería contraproducente. También hay que tener en cuenta que pueden haber colisiones de nombres entre clases base e interfaces y entre interfaces entre si.{ //gestión del turbo } } El segundo método sólo 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). . [editar]Jerarquías de interfaces Las interfaces pueden servir de base para otras interfaces al igual que las clases.

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

Frenar(int n) { //Gestión del frenado } void IVehiculoGasolina.Activar4x4(bool activar) { .CambiarVelocidadInyeccion(int velocidad) { //Gestión de la inyeccion } void IVehiculo4x4.CambiarVelocidadInyeccion(int velocidad) { //Gestión de la inyeccion } } public class TodoTerreno:IVehiculo4x4 { void IVehiculo.Acelerar(int n) { //Gestión del acelerado } void IVehiculo.{ //Gestión del frenado } void IVehiculoGasolina.

((IVehiculo4x4)miTodoTerreno).Acelerar(20).Anterior (Capítulo 8) | (Capítulo 10) Siguiente->> Versión para imprimir esta pagina Categoría: C sharp NET SEPTIMO TUTORIAL .//Gestión de 4x4 } } Y lógicamente las llamadas a los métodos serían: TodoTerreno miTodoTerreno = new TodoTerreno().CambiarVelocidadInyeccion(1000).Frenar(20). ((IVehiculo4x4)miTodoTerreno). ((IVehiculo4x4)miTodoTerreno).Activar4x4(true). ((IVehiculo4x4)miTodoTerreno). <<.

Sign up to vote on this title
UsefulNot useful