You are on page 1of 222

1.3.

Cmo probar este programa _____________________________________________________________________ 19


1.3.1. Cmo probarlo con Mono en Linux ______________________________________________________ 19
1.3.2. Cmo probarlo con Mono en Windows __________________________________________________ 24
1.3.3. Otros editores ms avanzados para Windows ___________________________________________ 33

Revisin actual: 0.99zz

Revisin 0.99zz Pgina 1

Para cualquier sugerencia, no dude en contactar conmigo a travs de mi web.

cualquier error que encuentre.

Aun as, mi intencin es que resulte til, as que le rogara que me comunique

Este texto se distribuye "tal cual", sin garanta de ningn tipo, implcita ni explcita.

puede crear obras derivadas.

autor, no se puede hacer uso comercial (no se puede "vender" este curso), no se

sale a equivaler a una licencia Creative Commons BY-NC-ND: reconocimiento del

libremente, siempre y cuando no se modifique. Si le gustan los formalismos, esto

Este texto es de libre distribucin ("gratis"). Se puede distribuir a otras personas

www.nachocabanes.com

versin, estar en mi pgina web:

Este texto ha sido escrito por Nacho Cabanes. Si quiere conseguir la ltima

Revisin 0.99zz Pgina 2

2.2. Estructuras repetitivas____________________________________________________________________________ 63


2.2.1. while ____________________________________________________________________________________ 63
2.2.2. do ... while _______________________________________________________________________________ 65
2.2.3. for _______________________________________________________________________________________ 67
2.2.4. Bucles sin fin ____________________________________________________________________________ 69

2.1. Estructuras alternativas __________________________________________________________________________ 47


2.1.1. if ________________________________________________________________________________________ 47
2.1.2. if y sentencias compuestas ______________________________________________________________ 48
2.1.3. Operadores relacionales: <, <=, >, >=, ==, != _____________________________________________ 49
2.1.4. if-else____________________________________________________________________________________ 50
2.1.5. Operadores lgicos: &&, ||, ! ____________________________________________________________ 52
2.1.6. El peligro de la asignacin en un "if" _____________________________________________________ 54
2.1.7. Introduccin a los diagramas de flujo ____________________________________________________ 55
2.1.8. Operador condicional: ? _________________________________________________________________ 58
2.1.9. switch ___________________________________________________________________________________ 60

2. Estructuras de control ________________________________________________________________ 47

1.11. Escribir sin avanzar de lnea ____________________________________________________________________ 45

1.10. using System ______________________________________________________________________________________ 44

1.9. Datos por el usuario: ReadLine __________________________________________________________________ 43

1.8. Comentarios ________________________________________________________________________________________ 41

1.7. Identificadores _____________________________________________________________________________________ 40

1.6. Introduccin a las variables: int _________________________________________________________________ 36


1.6.1. Definicin de variables: nmeros enteros _______________________________________________ 36
1.6.2. Asignacin de valores ___________________________________________________________________ 37
1.6.3. Mostrar el valor de una variable en pantalla _____________________________________________ 38

1.5. Operaciones aritmticas bsicas ________________________________________________________________ 34


1.5.1. Operadores _____________________________________________________________________________ 34
1.5.2. Orden de prioridad de los operadores ___________________________________________________ 35
1.5.3. Introduccin a los problemas de desbordamiento _______________________________________ 36

1.4. Mostrar nmeros enteros en pantalla __________________________________________________________ 34

1.2. Escribir un texto en C# ____________________________________________________________________________ 17

evitar que un exceso de teora en los primeros temas haga el texto pesado de

seguir.

1.1. Qu es C #? Qu entorno usaremos? __________________________________________________________ 16

"convencionales", procurando incluir ejercicios prcticos lo antes posible, para

1. Toma de contacto con C# ____________________________________________________________ 16

0.4. Pseudocdigo_______________________________________________________________________________________ 14

0.3. Ensambladores, compiladores e intrpretes ___________________________________________________ 11

0.2. Lenguajes de alto nivel y de bajo nivel ___________________________________________________________ 9

0.1. Programa y lenguaje _______________________________________________________________________________ 9

0. Conceptos bsicos sobre programacin ____________________________________________ 9

Contenido _________________________________________________________________________________ 2

Contenido

Introduccin a la programacin con C#, por Nacho Cabanes

Est organizado de una forma ligeramente distinta a los libros de texto

lenguaje C#.

Este texto es una introduccin a la programacin de ordenadores, usando el

Introduccin a la programacin
con C#

Introduccin a la programacin con C#, por Nacho Cabanes

6.3. Proyectos a partir de varios fuentes __________________________________________________________ 191


6.4. La herencia _______________________________________________________________________________________ 205

4. Arrays, estructuras y cadenas de texto ___________________________________________ 113

4.1. Conceptos bsicos sobre arrays o tablas _____________________________________________________ 113


4.1.1. Definicin de un array y acceso a los datos _____________________________________________ 113
4.1.2. Valor inicial de un array ________________________________________________________________ 114
4.1.3. Recorriendo los elementos de una tabla ________________________________________________ 115
4.1.4. Operaciones habituales con arrays: buscar, aadir, insertar, borrar ____________________ 118
4.1.5. Constantes _____________________________________________________________________________ 121

Revisin 0.99zz Pgina 3

4.4. Cadenas de caracteres __________________________________________________________________________ 128


4.4.1. Definicin. Lectura desde teclado ______________________________________________________ 128
4.4.2. Cmo acceder a las letras que forman una cadena _____________________________________ 130

4.3. Estructuras o registros __________________________________________________________________________ 125


4.3.1. Definicin y acceso a los datos _________________________________________________________ 125
4.3.2. Arrays de structs _______________________________________________________________________ 126
4.3.3. structs anidados ________________________________________________________________________ 127

4.2. Arrays bidimensionales _________________________________________________________________________ 122

6.2. Objetos y clases en C#___________________________________________________________________________ 186

3.5. Los valores "booleanos" ________________________________________________________________________ 111

Revisin 0.99zz Pgina 4

7.5. La palabra "this": el objeto actual _____________________________________________________________ 232

7.4. Llamando a un mtodo de la clase "padre" __________________________________________________ 229

7.3. Funciones virtuales. La palabra "override" __________________________________________________ 225

7.2. Arrays de objetos ________________________________________________________________________________ 221

7.1. La palabra "static" _______________________________________________________________________________ 219

7. Utilizacin avanzada de clases ____________________________________________________ 219

6.8. Orden de llamada de los constructores _______________________________________________________ 216

6.7. Polimorfismo y sobrecarga _____________________________________________________________________ 215

6.6. Constructores y destructores __________________________________________________________________ 212

6.5. Visibilidad _________________________________________________________________________________________ 208

6.1. Por qu los objetos? ____________________________________________________________________________ 180

3.4. Toma de contacto con las cadenas de texto _________________________________________________ 110

5.11. Parmetros y valor de retorno de "Main" ___________________________________________________ 177

6. Programacin orientada a objetos ________________________________________________ 180

5.10. Recursividad ____________________________________________________________________________________ 174

5.9. Algunas funciones tiles ________________________________________________________________________ 170


5.9.1. Nmeros aleatorios ____________________________________________________________________ 170
5.9.2. Funciones matemticas ________________________________________________________________ 171
5.9.3. Pero hay muchas ms funciones ______________________________________________________ 174

5.8. El orden no importa _____________________________________________________________________________ 169

5.7. Modificando parmetros _______________________________________________________________________ 167

5.6. Los conflictos de nombres en las variables __________________________________________________ 165

5.5. Variables locales y variables globales _________________________________________________________ 163

5.4. Valor devuelto por una funcin. El valor "void" _____________________________________________ 160

5.3. Parmetros de una funcin ____________________________________________________________________ 158

5.2. Conceptos bsicos sobre funciones ___________________________________________________________ 156

5.1. Diseo modular de programas: Descomposicin modular _________________________________ 156

5. Introduccin a las funciones _______________________________________________________ 156

4.8. Otros editores ms avanzados: Notepad++ y Geany ________________________________________ 151

4.7. Ordenaciones simples ___________________________________________________________________________ 145

4.6. Ejemplo completo________________________________________________________________________________ 140

3.3. Tipo de datos carcter __________________________________________________________________________ 107


3.3.1. Leer y mostrar caracteres ______________________________________________________________ 107
3.3.2. Secuencias de escape: \n y otras________________________________________________________ 108

3.2. Tipo de datos real __________________________________________________________________________________ 97


3.2.1. Coma fija y coma flotante _______________________________________________________________ 97
3.2.2. Simple y doble precisin _________________________________________________________________ 98
3.2.3. Pedir nmeros reales al usuario ________________________________________________________ 100
3.2.4. Conversin de tipos (typecast) __________________________________________________________ 102
3.2.5. Formatear nmeros ____________________________________________________________________ 103
3.2.6. Cambios de base _______________________________________________________________________ 105

3.1. Tipo de datos entero ______________________________________________________________________________ 92


3.1.1. Tipos de datos para nmeros enteros ___________________________________________________ 92
3.1.2. Conversiones de cadena a entero _______________________________________________________ 93
3.1.3. Incremento y decremento _______________________________________________________________ 94
3.1.4. Operaciones abreviadas: += _____________________________________________________________ 96
3.1.5. Asignaciones mltiples __________________________________________________________________ 96

3. Tipos de datos bsicos _______________________________________________________________ 92

2.7. Una alternativa para el control errores: las excepciones ____________________________________ 88

2.6. Recomendacin de uso para los distintos tipos de bucle _____________________________________ 86

2.5. foreach ______________________________________________________________________________________________ 85

2.4. Ms sobre diagramas de flujo. Diagramas de Chapin _________________________________________ 83

2.3. Saltar a otro punto del programa: goto _________________________________________________________ 82

4.4.3. Longitud de la cadena __________________________________________________________________ 130


4.4.4. Extraer una subcadena _________________________________________________________________ 131
4.4.5. Buscar en una cadena __________________________________________________________________ 132
4.4.6. Otras manipulaciones de cadenas ______________________________________________________ 133
4.4.7. Descomponer una cadena en fragmentos ______________________________________________ 135
4.4.8. Comparacin de cadenas _______________________________________________________________ 137
4.4.9. Una cadena modificable: StringBuilder _________________________________________________ 138

2.2.5. Bucles anidados _________________________________________________________________________ 69


2.2.6. Repetir sentencias compuestas __________________________________________________________ 70
2.2.7. Contar con letras ________________________________________________________________________ 71
2.2.8. Declarar variables en un "for" ___________________________________________________________ 72
2.2.9. Las llaves son recomendables ___________________________________________________________ 74
2.2.10. Interrumpir un bucle: break ____________________________________________________________ 75
2.2.11. Forzar la siguiente iteracin: continue __________________________________________________ 77
2.2.12. Equivalencia entre "for" y "while" _______________________________________________________ 78
2.2.13. Ejercicios resueltos sobre bucles _______________________________________________________ 80
4.5. Recorriendo arrays y cadenas con "foreach" ________________________________________________ 139

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

11.2. Una pila en C# __________________________________________________________________________________ 312


11.3. Una cola en C# __________________________________________________________________________________ 314
11.4. Las listas _________________________________________________________________________________________ 316
11.4.1. ArrayList ______________________________________________________________________________ 316
11.4.2. SortedList _____________________________________________________________________________ 319

8. Manejo de ficheros _________________________________________________________________ 242

8.1. Escritura en un fichero de texto _______________________________________________________________ 242

8.2. Lectura de un fichero de texto _________________________________________________________________ 244

8.3. Lectura hasta el final del fichero ______________________________________________________________ 245

12.4. El entorno. Llamadas al sistema______________________________________________________________ 347


12.5. Datos sobre "el entorno" ______________________________________________________________________ 348
12.6. Algunos servicios de red. ______________________________________________________________________ 349

13. Otras caractersticas avanzadas de C# _________________________________________ 354


13.1. Espacios de nombres ___________________________________________________________________________ 354
13.2. Operaciones con bits ___________________________________________________________________________ 356

13.4. Propiedades _____________________________________________________________________________________ 360


13.5. Introduccin a las expresiones regulares. __________________________________________________ 361
13.6. El operador coma _______________________________________________________________________________ 364

9.3. Empleando clases auxiliares ___________________________________________________________________ 277

9.4. Volcando a un fichero de texto ________________________________________________________________ 283

10. Acceso a bases de datos relacionales ___________________________________________ 289

10.1. Nociones mnimas de bases de datos relacionales ________________________________________ 289

10.2. Nociones mnimas de lenguaje SQL __________________________________________________________ 289


10.2.1. Creando la estructura _________________________________________________________________ 289
10.2.2. Introduciendo datos __________________________________________________________________ 290
10.2.3. Mostrando datos ______________________________________________________________________ 291

10.3. Acceso a bases de datos con SQLite __________________________________________________________ 292

10.4. Un poco ms de SQL: varias tablas ___________________________________________________________ 297


10.4.1. La necesidad de varias tablas _________________________________________________________ 297
10.4.2. Las claves primarias ___________________________________________________________________ 298
10.4.3. Enlazar varias tablas usando SQL ______________________________________________________ 298
10.4.4. Varias tablas con SQLite desde C# _____________________________________________________ 301

Revisin 0.99zz Pgina 5

10.8 Un ejemplo completo con C# y SQLite ________________________________________________________ 306

10.7 Grupos ____________________________________________________________________________________________ 305

10.6. Operaciones matemticas con los datos ____________________________________________________ 304

10.5. Borrado y modificacin de datos _____________________________________________________________ 303

12.3. Lectura de directorios _________________________________________________________________________ 344

9.2. Creando un objeto "serializable" ______________________________________________________________ 275

Revisin 0.99zz Pgina 6

14.3. Prueba de programas __________________________________________________________________________ 372

14.2. Depurando desde Visual Studio ______________________________________________________________ 369

14.1. Conceptos bsicos sobre depuracin ________________________________________________________ 369

14. Depuracin, prueba y documentacin de programas __________________________ 369

13.9. Lo que no vamos a ver... _______________________________________________________________________ 368

13.8. Contacto con LINQ _____________________________________________________________________________ 366

13.7. Variables con tipo implicito ___________________________________________________________________ 365

13.3. Enumeraciones _________________________________________________________________________________ 358

12.2. Ms posibilidades de la "consola" ____________________________________________________________ 340

9.1. Por qu la persistencia? _______________________________________________________________________ 274

12.1. Fecha y hora. Temporizacin _________________________________________________________________ 337

12. Algunas bibliotecas adicionales de uso frecuente _____________________________ 337

11.9. Los punteros en C# _____________________________________________________________________________ 329


11.9.1. Qu es un puntero? __________________________________________________________________ 329
11.9.2. Zonas "inseguras": unsafe _____________________________________________________________ 330
11.9.3. Uso bsico de punteros _______________________________________________________________ 331
11.9.4. Zonas inseguras _______________________________________________________________________ 332
11.9.5. Reservar espacio: stackalloc ___________________________________________________________ 333
11.9.6. Aritmtica de punteros ________________________________________________________________ 334
11.9.7. La palabra "fixed" _____________________________________________________________________ 335

11.8. Introduccin a los "generics" _________________________________________________________________ 326

11.7. Cmo "imitar" una pila usando "arrays" ____________________________________________________ 324

11.6. Los "enumeradores" ___________________________________________________________________________ 322

9. Persistencia de objetos_____________________________________________________________ 274

8.16. Leer y escribir en un mismo fichero binario ________________________________________________ 271

8.15. Escribir en un fichero binario _________________________________________________________________ 267

8.14. Ejemplo completo: leer informacin de un fichero BMP __________________________________ 263

8.13. Leer datos nativos ______________________________________________________________________________ 261

8.12. La posicin en el fichero _______________________________________________________________________ 259

8.11. Leer bloques de datos de un fichero binario ________________________________________________ 258

8.10. Leer hasta el final de un fichero binario ____________________________________________________ 256

8.9. Leer un byte de un fichero binario ____________________________________________________________ 253

8.8. Conceptos bsicos sobre ficheros _____________________________________________________________ 253

8.7. Ms comprobaciones de errores: excepciones _______________________________________________ 250

8.6. Saber si un fichero existe _______________________________________________________________________ 249

8.5. Ficheros en otras carpetas _____________________________________________________________________ 248

11.5. Las "tablas hash" _______________________________________________________________________________ 320

11.1. Por qu usar estructuras dinmicas? _______________________________________________________ 311

7.7. Proyectos completos propuestos ______________________________________________________________ 239

8.4. Aadir a un fichero existente __________________________________________________________________ 247

10.9. Nociones mnimas de acceso desde un entorno grfico __________________________________ 310

11. Punteros y gestin dinmica de memoria ______________________________________ 311

7.6. Sobrecarga de operadores ______________________________________________________________________ 237

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 7

ndice alfabtico _______________________________________________________________________ 439

Revisiones de este texto ______________________________________________________________ 437

Ap5.6. Dibujando con Windows Forms _____________________________________________________________ 434

Ap5.5. Otros componentes visuales ________________________________________________________________ 433

Ap5.4. Una aplicacin con dos ventanas ___________________________________________________________ 430

Ap5.3. Usando ventanas predefinidas _____________________________________________________________ 428

Ap5.2. Cambios de apariencia. Casillas de texto para sumar dos nmeros ___________________ 424

Ap5.1. Creacin de formularios, botones y etiquetas ____________________________________________ 420

Apndice 5. Contacto con los entornos grficos ____________________________________ 420

Ap4.9. Por dnde seguir? ___________________________________________________________________________ 418

Ap4.8. Imgenes PNG y JPG __________________________________________________________________________ 417

Ap4.7. Colisiones simples ____________________________________________________________________________ 413

Ap4.6. Escribir texto __________________________________________________________________________________ 411

Ap4.5. Un fuente ms modular: el "bucle de juego" ______________________________________________ 409

Ap4.4. Simplificando con clases auxiliares ________________________________________________________ 405

Ap4.3. Una imagen que se mueve con el teclado _________________________________________________ 403

Ap4.2. Mostrar una imagen esttica _______________________________________________________________ 400

Ap4.1. Juegos con Tao.SDL ___________________________________________________________________________ 400

Apndice 4. SDL ________________________________________________________________________ 400

Ap3.4. Representacin interna de los enteros negativos ________________________________________ 397

Ap3.3. Sistema hexadecimal ________________________________________________________________________ 395

Ap3.2. Sistema octal __________________________________________________________________________________ 393

Ap3.1. Sistema binario _______________________________________________________________________________ 391

Apndice 3. Sistemas de numeracin. _______________________________________________ 391

Apndice 2. El cdigo ASCII ___________________________________________________________ 389

Ap1.2. Unidades de medida empleadas en informtica (2): los bits ____________________________ 386

Ap1.1. bytes, kilobytes, megabytes... ______________________________________________________________ 385

Apndice 1. Unidades de medida y sistemas de numeracin _____________________ 385

14.4. Documentacin bsica de programas _______________________________________________________ 377


14.4.1. Consejos para comentar el cdigo_____________________________________________________ 378
14.4.2. Generacin de documentacin a partir del cdigo fuente. _____________________________ 381

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 8

Introduccin a la programacin con C#, por Nacho Cabanes

a cambio, hacen ms fcil descubrir errores (ya veremos por qu):


Revisin 0.99zz Pgina 9

ciertas cosas como el nombre del programa o dnde empieza y termina ste, pero,

Otros lenguajes, como Pascal, nos obligan a ser algo ms estrictos y detallar

PRINT "Hola"

lenguaje, escribir el texto Hola en pantalla, sera tan sencillo como usar la orden

Uno de los lenguajes de alto nivel ms sencillos es el lenguaje BASIC. En este

comparar con lenguajes de bajo nivel, que son los ms cercanos al ordenador.

Vamos a ver en primer lugar algn ejemplo de lenguaje de alto nivel, para despus

0.2. Lenguajes de alto nivel y de bajo nivel

ayudar al programador en ms tareas, pero a la vez, los programas sencillos se

Revisin 0.99zz Pgina 10

ejemplo, escribir Hola en lenguaje ensamblador de un ordenador equipado con

control del ordenador que a veces no se puede alcanzar con otros lenguajes. Por

optimizar al mximo la velocidad (si sabemos cmo), e incluso llegar a un nivel de

que los fallos sean ms difciles de descubrir y corregir, a cambio de que podemos

los lenguajes humanos. Eso hace que sean ms difciles de aprender y tambin

Por el contrario, los lenguajes de bajo nivel son ms cercanos al ordenador que a

print("Hello")

lenguaje Python haramos:

sencillas de programar. Por ejemplo, para escribir algo en pantalla usando el

regla, y algunos se han diseado de forma que las tareas simples sean (de nuevo)

vuelven ms complicados. Afortunadamente, no todos los lenguajes siguen esta

Como se puede observar, a medida que los lenguajes evolucionan, son capaces de

muy parecidos al idioma ingls, aunque siguen unas reglas mucho ms estrictas.

public class Saludo


{
public static void Main()
{
System.Console.WriteLine("Hola");
}
}

veremos, cada programa ser "una clase":

En C# hay que dar todava ms pasos para conseguir lo mismo, porque, como

int main(()
{
printf(("Hola");
return 0;
}

#include <stdio.h>

(incluso cuando todo ha ido bien):

en C suelen necesitar incluir bibliotecas externas y devolver cdigos de error

El equivalente en lenguaje C resulta algo ms difcil de leer, porque los programas

begin
write('Hola');
end.

program Saludo;

Introduccin a la programacin con C#, por Nacho Cabanes

al lenguaje humano, llamados "lenguajes de alto nivel". Normalmente, estos son

Prcticamente ilegible. Por eso, en la prctica se emplean lenguajes ms parecidos

0011 1110 0000 0010 0011 1010 0001 0000

80, basada en el procesador Z80 de 8 bits, sera as en cdigo mquina:

de memoria 1 de un ordenador sencillo, con una arquitectura propia de los aos

Por ejemplo, un programa que simplemente guardara un valor "2" en la posicin

(especialmente) en el momento de corregir algn fallo o mejorar lo que se hizo.

mquina") es un trabajo duro, tanto a la hora de crear el programa como

utiliza internamente el ordenador (llamado "lenguaje mquina" o "cdigo

empleamos habitualmente para hablar. Escribir programas en el lenguaje que

resultan difciles para nosotros, porque son muy distintos de los que nosotros

El problema es que los lenguajes que realmente entienden los ordenadores

de comprender.

Estas rdenes se le deben dar en un cierto lenguaje, que el ordenador sea capaz

Un programa es un conjunto de rdenes para un ordenador.

0.1. Programa y lenguaje

0. Conceptos bsicos sobre programacin

Introduccin a la programacin con C#, por Nacho Cabanes

ax,4C00h
21h

ah,9
dx,offset saludo
21h

ax,@data
ds,ax

Revisin 0.99zz Pgina 11

complicada, y a veces implicar tambin recopilar varios fuentes distintos o incluir

Cuando el lenguaje que hemos empleado es de alto nivel, la traduccin es ms

encargan unas herramientas llamadas ensambladores (en ingls Assembler).

abreviado como Asm), la traduccin es sencilla, y de hacer esa traduccin se

Si elegimos un lenguaje de bajo nivel, como el ensamblador (en ingls Assembly,

(obteniendo un "programa ejecutable").

como "programa fuente") deben convertirse a lo que el ordenador comprende

Como hemos visto, las rdenes que nosotros hemos escrito (lo que se conoce

0.3. Ensambladores, compiladores e intrpretes

entornos de programacin, para que nos sea ms fcil descubrir ciertos errores).

(Nota: los colores de los ejemplos anteriores son una ayuda que nos dan algunos

1000 0011 1101 1000 1011 0100 0000 1001

convertiran a lo siguiente:

las rdenes "mov ds, ax" y "mov ah, 9" (en cuyo significado no vamos a entrar) se

realmente es capaz de comprender son secuencias de ceros y unos. Por ejemplo,

entiende, aunque tiene una equivalencia casi directa. Lo que el ordenador

Resulta bastante ms difcil de seguir. Pero eso todava no es lo que el ordenador

mov
int
main endp
end main

mov
mov
int

.code
main proc
mov
mov

.data
,0dh,0ah,'$'
saludo db 'Hola',

dosseg
.model small
.stack 100h

de

realizar

todo

esto

son

los

Revisin 0.99zz Pgina 12

".java", que se compilan a ficheros ".class". Estos ficheros ".class" se podran llevar

es la idea que se aplica en Java: los fuentes son ficheros de texto, con extensin

exista una "mquina virtual" capaz de entender esos ejecutables genricos. Esta

funcionar en distintos tipos de ordenadores, a condicin de que en ese ordenador

para un ordenador concreto, sino a un ejecutable "genrico", que es capaz de

compilador y un intrprete. Existen lenguajes que no se compilan a un ejecutable

Actualmente existe una alternativa ms, algo que parece intermedio entre un

correspondiente pgina web.

analizados y puestos en funcionamiento en el momento en el que se solicita la

Python, y que estos programas no se conviertan a un ejecutable, sino que sean

servidor web es habitual crear programas usando lenguajes como PHP, ASP o

Los intrpretes siguen siendo muy frecuentes hoy en da. Por ejemplo, en un

orden, justo en el momento en que hay que procesar cada una de las rdenes.

escrito en lenguaje de alto nivel a su equivalente en cdigo mquina, orden por

funcionamiento, el intrprete se encarga de convertir el programa que hemos

entenderlo, o no le servir de nada. Cuando ponemos el programa en

deberemos entregarle el programa fuente y tambin el intrprete que es capaz de

"por s solo", de modo que si queremos distribuir nuestro programa a alguien,

que en los intrpretes no se crea ningn "programa ejecutable" capaz de funcionar

Un intrprete es una herramienta parecida a un compilador, con la diferencia de

(por ejemplo, Linux o Mac OS X).

Eso s, no funcionara en otro ordenador que tuviera un sistema operativo distinto

operativo, aunque dicho ordenador no tenga un compilador de Pascal instalado.

capaz de funcionar en cualquier otro ordenador que tuviera el mismo sistema

Pascal. En cambio, despus de compilarlo obtendramos un fichero SALUDO.EXE,

fichero no servira de nada en un ordenador que no tuviera un compilador de

en lenguaje Pascal, tendramos un fichero fuente llamado SALUDO.PAS. Este

Por ejemplo, en el caso de Windows (y de MsDos), y del programa que nos saluda

ensamblador.

sin necesidad de que ese otro ordenador tenga instalado el compilador o el

hacer funcionar en otro ordenador similar al que habamos utilizado para crearlo,

El programa ejecutable obtenido con el compilador o el ensamblador se podra

compiladores.

encargadas

nosotros.

como

herramientas

posibilidades que se encuentran en otras bibliotecas que no hemos preparado

el sistema operativo MsDos y con un procesador de la familia Intel x86 sera algo
Las

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

el apartado 0.1. (Nota: nuevamente, no es necesario realizar este ejercicio


para seguir adelante con el curso).

a cualquier ordenador que tenga instalada una "mquina virtual Java" (las hay para

la mayora de sistemas operativos).

que nosotros empleamos, es habitual no usar ningn lenguaje de programacin


concreto cuando queremos plantear iniciamente los pasos necesarios para
resolver un problema, sino emplear un lenguaje de programacin ficticio, no tan
estricto, muchas veces incluso en espaol. Este lenguaje recibe el nombre de
pseudocdigo.

ejecutables que funcionarn en cualquier ordenador que tenga instalada dicha

"plataforma .Net", algo que suele ocurrir en las versiones recientes de Windows y

que se puede conseguir de forma un poco ms artesanal en plataformas Linux y

Mac, gracias a un "clon" de la "plataforma .Net" que es de libre distribucin,

conocido como "proyecto Mono".

Revisin 0.99zz Pgina 13

navegador web, y prueba el quinto programa de ejemplo que se ha visto en

Linux) o busca en Internet "try Python web" para probarlo desde tu

(0.3.4) Descarga un intrprete de Python (ya estar preinstalado si usas

equipo software que despus quiz no vuelvas a utilizar).

seguir adelante con el curso; puedes omitirlo si no quieres instalar en tu

visto en el apartado 0.1. (Nota: no es necesario realizar este ejercicio para

encuentre ya instalado) y prueba el tercer programa de ejemplo que se ha

utilizando (si es Linux o alguna otra versin de Unix, es fcil que se

(0.3.3) Localiza un compilador de C para el sistema operativo que ests

no vayas a seguir utilizando).

puedes omitirlo si no quieres instalar en tu ordenador software que luego

no es necesario realizar este ejercicio para seguir adelante con el curso;

el segundo programa de ejemplo que se ha visto en el apartado 0.1. (Nota:

su versin para el sistema operativo que ests utilizando, instlalo y prueba

(0.3.2) Localiza en Internet el compilador de Pascal llamado Free Pascal, en

encuentras ningn intrprete de BASIC).

este ejercicio para seguir adelante con el curso; puedes omitirlo si no

muchos BASIC modernos, como Basic256. (Nota: no es necesario realizar

usar cualquier "ordenador clsico" (de principios de los aos 80) y otros

programa de ejemplo que se ha visto en el apartado 0.1. Tambin puedes

su versin para el sistema operativo que ests utilizando y prueba el primer

(0.3.1) Localiza en Internet el intrprete de BASIC llamado Bywater Basic, en

Revisin 0.99zz Pgina 14

prueba escribir el siguiente programa. (Nota: no es necesario realizar este

(0.4.1) Localiza en Internet el intrprete de Pseudocdigo llamado PseInt y

Ejercicios propuestos

individuales en cualquier lenguaje de programacin.

ejemplo, ese "conectar con central de cobros" correspondera a varias rdenes

buscando concretar las ideas ms que la forma real de llevarlas a cabo. Por

lenguaje de programacin "real" y expresar las acciones de forma ms general,

Como se ve en este ejemplo, el pseudocdigo suele ser menos detallado que un

Leer banda magntica de la tarjeta


Conectar con central de cobros
Si hay conexin y la tarjeta es correcta:
Pedir cdigo PIN
Si el PIN es correcto
Comprobar saldo_existente
Si saldo_existente >= importe_compra
Aceptar la venta
Descontar importe del saldo.
Fin Si
Fin Si
Fin Si

con tarjeta de crdito, escrito en pseudocdigo, podra ser:

Por ejemplo, un algoritmo que controlase los pagos que se realizan en una tienda

programacin.

programa de ordenador es un algoritmo expresado usando un lenguaje de

algoritmo debe estar formado por un nmero finito de pasos. Por tanto, un

algoritmo. Realmente es algo un poco ms estricto que eso: por ejemplo, un

Esa secuencia de pasos para resolver un problema es lo que se conoce como

A pesar de que los lenguajes de alto nivel se acercan al lenguaje natural (ingls),

programas que creemos con herramientas como Visual Studio sern unos

Ejercicios propuestos

0.4. Pseudocdigo

llamada "Dot Net Framework" (algo as como "plataforma punto net"): los

Esta misma idea se sigue en el lenguaje C#, que se apoya en una mquina virtual

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

Proceso EjemploDeSuma
Escribir 2+3
FinProceso

Revisin 0.99zz Pgina 15

instalar en tu equipo software que luego no vayas a seguir utilizando).

ejercicio para seguir adelante con el curso; puedes omitirlo si no te apetece

Introduccin a la programacin con C#, por Nacho Cabanes

Lanzar el fichero ejecutable.


x

nuestros programas, dnde localizarlo y cmo instalarlo.

Revisin 0.99zz Pgina 16

Tras el siguiente apartado veremos un ejemplo de entorno desde el que realizar

depuramos en caso de que exista algn fallo.

nico entorno, en el que escribimos nuestros programas, los compilamos, y los

La mayora de los compiladores actuales permiten dar todos estos pasos desde un

Compilarlo, con nuestro compilador. Esto crear un "fichero ejecutable".

de textos.

Escribir el programa en lenguaje C# (fichero fuente), con cualquier editor


x

Los pasos que seguiremos para crear un programa en C# sern:

MonoDevelop, que tambin comentaremos.

Studio Express Edition). Existen otros entornos alternativos, como SharpDevelop o

desarrollo muy avanzado, y est disponible tambin en una versin gratuita (Visual

que requiere un ordenador ms potente pero a cambio incluye un entorno de

conceptos bsicos estn asentados, pasaremos a emplear Visual C#, de Microsoft,

los primeros temas, junto con un editor de texto para programadores. Cuando los

Nosotros comenzaremos por usar Mono como plataforma de desarrollo durante

que est disponible para Windows, Linux, Mac OS X y otros sistemas operativos.

existe una implementacin alternativa de "cdigo abierto", el "proyecto Mono",

plataforma .NET, pero fue estandarizado posteriormente por ECMA y por ISO, y

Se trata de un lenguaje creado por Microsoft para realizar programas para su

difcil cometer errores.

con C, pero a cambio la productividad del programador es mucho mayor y es ms

Java. Los programas creados con C# no suelen ser tan rpidos como los creados

moderno, evolucionado a partir de C y C++, y con una sintaxis muy similar a la de

C# es un lenguaje de programacin de ordenadores. Se trata de un lenguaje

1.1. Qu es C #? Qu entorno usaremos?

1. Toma de contacto con C#

Introduccin a la programacin con C#, por Nacho Cabanes

: Las rdenes relacionadas con el

class

Ejemplo_01_02a

De

momento

pensaremos

que

quiere decir "class" y por qu debe ser "public".

obligatorio. Nuevamente, aplazamos para ms tarde los detalles sobre qu

no tiene por qu ser tan "rebuscado"), y eso de "public class" ser

deber existir tambin siempre en nuestros programas (aunque el nombre

"Ejemplo_01_02a" es el nombre de nuestro programa. Una lnea como esa

public

del nombre del bloque que comienza (el "estilo Java"), as:

Revisin 0.99zz Pgina 18

llaman el "estilo C". La segunda forma habitual es situndola a continuacin

aclarando ms tarde. De momento, deberemos memorizar que sa ser la

Revisin 0.99zz Pgina 17

encima de la llave de cierre correspondiente. Esto es lo que muchos autores

void" y de por qu se pone despus un parntesis vaco los iremos

public class Ejemplo_01_02c {


public static void Main(){
System.Console.WriteLine("Hola");

el primer ejemplo: situar la llave de apertura en una lnea, sola, y justo

bloque "Main". Los detalles de por qu hay que poner delante "public static

forma correcta de escribir "Main".

comienzo, y yo usar ambas indistintamente. Una es como hemos hecho en

como veremos ms adelante). Todos los programas tienen que tener un

De hecho, hay dos formas especialmente frecuentes de colocar la llave de

public class Ejemplo_01_02b {


public
static
void Main() { System.Console.WriteLine("Hola"); }

no es aconsejable, porque puede resultar menos legible):

motivo, el programa anterior se podra haber escrito tambin as (aunque

y donde empieza la siguiente son los puntos y coma y las llaves. Por ese

espacios entre medias. Lo que realmente indica donde termina una orden

rdenes en una misma lnea, u rdenes separadas por varias lneas o

C# es un lenguaje de formato libre, de modo que puede haber varias

Cada orden de C# debe terminar con un punto y coma (;)

parte principal (un programa puede estar dividido en varios fragmentos,

Slo un par de cosas ms antes de seguir adelante:

(por ejemplo, "Hola, Nacho").

Ejercicio propuesto (1.2.1): Crea un programa en C# que te salude por tu nombre

bsicos de programacin.

limitaremos a "rellenar" el cuerpo del programa para entender los conceptos

detallando el por qu de "public", de "static", de "void", de "class"... Por ahora nos

para nosotros. Debemos creernos que "se debe hacer as". Poco a poco iremos

Como se puede ver, mucha parte de este programa todava es casi un "acto de fe"

Introduccin a la programacin con C#, por Nacho Cabanes

public static void Main() : Main indica cual es "el cuerpo del programa", la

caso, se trata del bloque principal del programa (Main).

Las llaves { y } se usan para delimitar un bloque de programa. En nuestro

manejo de consola (Console) pertenecen a la categora de sistema (System).

System.Console.WriteLine("Hola");

modo texto del sistema operativo).

porque es una orden de manejo de la "consola" (la pantalla "negra" en

Console.WriteLine("Hola"); : WriteLine siemprp ir precedido de "Console."

pantalla.

es la orden encargada de escribir (Write) una lnea (Line) de texto en

WriteLine("Hola"); : "Hola" es el texto que queremos escribir, y WriteLine

dentro hacia fuera:

detalles los aplazaremos para ms adelante. En este primer anlisis, iremos desde

"Hola", de modo vamos a comentarlas antes de proseguir, aunque muchos de los

Esto escribe "Hola" en la pantalla. Pero hay muchas "cosas raras" alrededor de ese

public class Ejemplo_01_02a


{
public static void Main()
{
System.Console.WriteLine("Hola");
}
}

detalle:

de este programa la vimos en el tema anterior. Vamos a analizarlo ahora con ms

de los que "hacen algo til". Se trata de escribir un texto en pantalla. La apariencia

Vamos con un primer ejemplo de programa en C#, posiblemente el ms sencillo

1.2. Escribir un texto en C#

Introduccin a la programacin con C#, por Nacho Cabanes

versin 17 Cinnamon) como entorno de desarrollo:

Revisin 0.99zz Pgina 19

En este caso, yo comentar los pasos necesarios para usar Linux Mint (en su

instalar Linux en esa mquina virtual.

VirtualBox, crear una nueva mquina virtual y "cargar esa imagen de CD" para

instalacin de algn Linux que sea reciente y razonablemente amigable, arrancar

As, podemos instalar VirtualBox, descargar la imagen ISO del CD o DVD de

"ordenador virtual" sin interferir con nuestro sistema operativo habitual.

permite tener un "ordenador virtual" dentro del nuestro, e instalar Linux en ese

forma simple, usando software de virtualizacin gratuito, como VirtualBox, que

coexistir con nuestro sistema operativo habitual, hoy en da puede realizarse de

La instalacin de Linux, que podra tener la dificultad de crear particiones para

lenguajes ya preinstalados, y otros son fciles de instalar en unos pocos clics.

resultar justo al contrario, porque Linux tiene compiladores e intrpretes de varios

necesariamente es as, y, de hecho, para un aprendiz de programador puede

Revisin 0.99zz Pgina 20

enorme lista de software que podemos instalar. En esta lista, aparece una casilla

momento de instalar Linux), y aparecer la pantalla principal de Synaptic, con una

Se nos pedir nuestra contrasea de usuario (la que hayamos utilizado en el

Synaptic":

puede sonar a que se trata de algo apto slo para expertos. Eso no

(como es el caso de Mint 17 Cinnamon), suele ser un tal "Gestor de paquetes

Para alguien acostumbrado a sistemas como Windows o Mac OS, hablar de Linux

que para las versiones de Linux Mint basadas en escritorios derivados de Gnome

En primer lugar, deberemos entrar al instalador de software de nuestro sistema,

Introduccin a la programacin con C#, por Nacho Cabanes

1.3.1. Cmo probarlo con Mono en Linux

1.3. Cmo probar este programa

reconocida, pero "writeLine", "WRITELINE" o "Writeline" no lo son.

entre maysculas y minsculas, por lo que "WriteLine" es una palabra

en ingls o abreviaturas de stas, pero hay que tener en cuenta que C# distingue

La gran mayora de las rdenes que encontraremos en el lenguaje C# son palabras

tiende a resultar ms legible).

poco menos de espacio; en los primeros fuentes usaremos el "estilo C", que

estemos trabajando con fuentes de mayor tamao, para que ocupe un

(esta es la forma que se emplear preferentemente en este texto cuando

Introduccin a la programacin con C#, por Nacho Cabanes

ejemplo, en esta versin de Linux encontraremos un editor de textos llamado


"gedit" dentro del apartado de accesorios:

de texto llamada "Filtro rpido", en la que podemos teclear "mcs" para que nos

aparezca directamente nuestro compilador Mono:

Revisin 0.99zz Pgina 21

editor de texto, pero eso es algo que viene preinstalado en cualquier Linux. Por

que el ordenador entienda. Para teclear nuestros programas necesitaremos un

Ya tenemos instalado el compilador, que convertir nuestros programas en algo

nos avisar de que se han aplicado todos los cambios:

Se descargarn los ficheros necesarios, se instalarn y al cabo de un instante se

ya podremos pulsar el botn "Aplicar":

Revisin 0.99zz Pgina 22

letras negras sobre fondo blanco:

hacer doble clic se nos avisar en el caso (habitual) de que

haya que instalar algn otro paquete adicional y entonces

En este editor podemos teclear nuestro programa, que inicialmente se ver con

descripcin se nos dir que es el "Mono C# Compiler". Al

Entre otros paquetes, posiblemente veremos uno llamado "mono-mcs", en cuya

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

fichero).

Revisin 0.99zz Pgina 23

maysculas y minsculas tal y como las hayas escrito en el nombre del

http://www.mono-project.com/

Revisin 0.99zz Pgina 24

Comenzaremos por descargar Mono desde su pgina oficial:

Despus lanzaremos el compilador con la orden "mcs" seguida del nombre

del fuente: "mcs ejemplo01.cs" (recuerda que en Linux debes respetar las

(inicialmente) un editor de texto mucho ms pobre que el de Linux.

responder a ms preguntas durante la instalacin. Adems, tendremos

complicado que para Linux, pero deberemos descargarlo desde su pgina oficial y

tienes mucho trabajo adelantado. Instalar Mono para Windows no es mucho ms

Si (utilices Linux o no) has ledo las instrucciones para compilar usando Linux,

1.3.2. Cmo probarlo con Mono en Windows

escriba en pantalla "Bienvenido a Linux".

Ejercicio propuesto (1.3.1.1): Desde Linux, crea y prueba un programa en C# que

anteriores de forma correcta y si tu fuente est bien tecleado.

ser entrar a esa carpeta con la orden "cd Documentos".

Si hemos guardado el fuente en la carpeta "Documentos", el primer paso

probar el programa:

En esa "pantalla negra" ya podemos teclear las rdenes necesarias para compilar y

estar accesible en la parte inferior de la pantalla:

Para compilar y lanzar el programa usaremos un "terminal", que habitualmente

(terminado en ".exe"): "mono ejemplo01.exe", as:

Si alguno de los pasos ha fallado, tendrs que comprobar si has dado los pasos

ejecutable, con la orden "mono" seguida del nombre del programa

en un color que nos ayude a saber la misin de esa palabra:

Si no aparece ningn mensaje de error, ya podemos lanzar el programa

Cuando lo guardemos con un nombre terminado en ".cs" (como "ejemplo01.cs"), el

editor sabr que se trata de un fuente en lenguaje C# y nos mostrar cada palabra

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

primero se nos muestra el mensaje de bienvenida:

Revisin 0.99zz Pgina 25

posiblemente nos mostrar Windows, y comenzar la instalacin, en la que

doble clic en el fichero recibido, aceptaremos el aviso de seguridad que

Se trata de un fichero de cerca de 100 Mb. Cuando termine la descarga, haremos

numeracin para Mac y realmente en Windows corresponde a la 3.2.3).

Windows (la 3.4.0 en el momento de escribir este texto, aunque esa es la

Revisin 0.99zz Pgina 26

El siguiente paso es elegir qu componentes queremos instalar (Mono, Gtk#, XSP):

podemos cambiarla por otra carpeta o incluso por otra unidad de disco:

queremos nuestro Mono. Nosotros descargaremos la versin ms reciente para

habitual, se nos propone que sea dentro de "Archivos de programa", pero

nos lleva a una nueva pgina en la que debemos elegir la plataforma para la que

de informacin y se nos pregunta en qu carpeta queremos instalar. Como es

Deberemos aceptar el acuerdo de licencia y despus se nos muestra una ventana

Introduccin a la programacin con C#, por Nacho Cabanes

En la parte superior derecha aparece el enlace para descargar ("download"), que

Introduccin a la programacin con C#, por Nacho Cabanes

quede el acceso a Mono:

Revisin 0.99zz Pgina 27

Despus deberemos indicar en qu carpeta del men de Inicio queremos que

ordenador, as que puede ser razonable no instalarlo por ahora:

ahora, y que adems instalara un "listener" que ralentizara ligeramente el

cuenta para profundizar. El servidor web XSP es algo claramente innecesario por

texto, pero aun as puede ser interesante para quien quiera investigar por su

interfaces de usuario con Gtk# queda fuera del alcance que se pretende con este

Yo no soy partidario de instalar todo. Mono es imprescindible. La creacin de

Introduccin a la programacin con C#, por Nacho Cabanes

x.x.x Command Prompt":

Revisin 0.99zz Pgina 28

carpeta llamada "Mono x.x.x for Windows", y dentro de ella un acceso a "Mono-

Mono est listo para usar. En nuestro men de Inicio deberamos tener una nueva

se ha completado:

cabo de un instante tendremos el mensaje de confirmacin de que la instalacin

confirmamos que todo nos parece correcto, comienza la copia de ficheros y al

A continuacin se nos muestra el resumen de lo que se va a instalar. Si

Introduccin a la programacin con C#, por Nacho Cabanes

y de la versin de Windows empleada).

Revisin 0.99zz Pgina 29

Windows 7 o Windows 8; los detalles exactos dependern del nombre del usuario

(Esa sera la forma de hacerlo para un usuario llamado "Yo" en un sistema con

cd \users\yo\desktop\programas

ejemplo) "Programas", y comenzar por desplazarnos hasta ella, tecleando

En ese caso, podemos crear una carpeta en nuestro escritorio, llamada (por

Revisin 0.99zz Pgina 30

mejor, pero eso lo haremos ms adelante.

permiso para escribir, como "Windows\System32".

editores que incorporan los sistemas Linux. La alternativa ser usar otro editor

quiz (algo habitual en las ltimas versiones) a alguna en la que no tengamos

guardar el programa, porque el "Bloc de notas" es mucho ms limitado que los

caso no veremos ninguna palabra destacada en colores, ni siquiera despus de

Podemos empezar a teclear el ejemplo que habamos visto anteriormente. En este

responder que s:

existe ese fichero, y que nos pregunta si deseamos crearlo. Lo razonable es

Aparecer la pantalla del "Bloc de notas", junto con un aviso que nos indica que no

notepad ejemplo01.cs

simplemente el "Bloc de notas" de Windows. Para ello, tecleamos:

podemos usar cualquier editor de texto. En este primer fuente, usaremos

Para crear un programa, el primero paso ser teclear el "fuente". Para ello

Introduccin a la programacin con C#, por Nacho Cabanes

Quiz se nos lleve a una carpeta que est dentro de "Documents and settings" o

bsqueda) preparada para que podamos acceder al compilador desde ella:

prompt"), la pantalla negra del sistema operativo, pero con el "path" (la ruta de

Si hacemos clic en esa opcin, accedemos al smbolo de sistema ("command

Introduccin a la programacin con C#, por Nacho Cabanes

ruta

Prompt" del men de inicio y escogemos

de Microsoft):
Revisin 0.99zz Pgina 31

correspondiente versin de ."Net" (es una descarga gratuita desde la pgina web

que lanzarlo usando Mono, o bien deberemos descargar e instalar la

plataforma ".Net" distinta de la que tenemos instalada. En ese caso, tendremos

Pero en ocasiones puede ocurrir que el ejecutable sea para una versin de la

la

opcin

"Iniciar

en".

Si

antes
copiado)

que

lo

conseguiremos

("pegando"

que

el

habamos

por el nombre de nuestra carpeta

cambiamos el contenido de esa casilla

veremos

En la pestaa llamada "Acceso directo"

"Propiedades".

sobre la opcin "Mono-x.x.x Command

nuestro programa, y podamos ejecutarlo directamente con su nombre:

para

(botn

Windows, pulsamos el botn derecho

Ctrl+C)

OsX), quiz no sea necesario decir que queremos que sea Mono quien lance

esa

Ahora vamos al men de Inicio de

ratn

"copiar"
del

memorizarla.

derecho

Podemos

Revisin 0.99zz Pgina 32

muestre la ruta completa de la carpeta.

su barra superior, de modo que se nos

carpeta que hemos creado y hacer clic en

Es algo fcil en la mayora de versiones de Windows. El primer paso ser abrir la

de Mono.

carpeta de programas, tenemos una alternativa: cambiar la carpeta de arranque

evitar tener que comenzar siempre con la orden "cd" para cambiar a nuestra

ser cierto en las ltimas versiones de Windows, y que no ocurrir en Linux ni Mac

ejemplo01

Introduccin a la programacin con C#, por Nacho Cabanes

Si el "Mono Command Prompt" se nos abre en Windows\System32 y queremos

Si en nuestro ordenador est instalado el "Dot Net Framework" (algo que debera

y el mensaje "Hola" debera aparecer en pantalla.

mono ejemplo01.exe

el programa tecleando

bien, se acaba de crear un fichero "ejemplo01.exe". En ese caso, podramos lanzar

Si no se nos responde nada, quiere decir que no ha habido errores. Si todo va

mcs ejemplo01.cs

guardado. El siguiente paso es compilarlo. Para eso, tecleamos

en la pantalla negra del smbolo del sistema. Nuestro fuente ya est escrito y

Guardamos los cambios, salimos del "Bloc de notas" y nos volvemos a encontrar

Introduccin a la programacin con C#, por Nacho Cabanes

Suma
Resta, negacin
Multiplicacin
Divisin
Resto de la divisin ("mdulo")

*
/
%

parte de la lgica del programa).

Revisin 0.99zz Pgina 33

entornos, pero no debera formar parte de un programa finalizado, porque no es

Operador
+

Operacin

Revisin 0.99zz Pgina 34

smbolos menos intuitivos. Veamos cuales son los ms importantes:

el de la resta, pero alguna de las operaciones matemticas habituales tienen

Parece evidente que el smbolo de la suma ser un +, y podemos esperar cual ser

1.5.1. Operadores

1.5. Operaciones aritmticas bsicas

lenguaje).

a teclear cada nuevo ejercicio te ayudar a memorizar las estructuras bsicas del

(Recomendacin: no "copies y pegues" aunque dos ejercicios se parezcan. Volver

(1.4.2) Crea un programa que diga el resultado de sumar 12345 y 67890.

(1.4.1) Crea un programa que diga el resultado de sumar 118 y 56.

Ejercicios propuestos:

public class Ejemplo_01_04a


{
public static void Main()
{
System.Console.WriteLine(3+4);
}
}

hacer:

contenido para ver qu puede significar. Por ejemplo, para sumar 3 y 4 bastara

es simple: no usar comillas en WriteLine. Entonces, C# intentar analizar el

El ejemplo ms sencillo es el de una operacin matemtica. La forma de realizarla

En muchos casos, se tratar de algo que habr que calcular.

encerramos entre comillas. Pero no siempre querremos escribir textos prefijados.

Cuando queremos escribir un texto "tal cual", como en el ejemplo anterior, lo

1.4. Mostrar nmeros enteros en pantalla

Introduccin a la programacin con C#, por Nacho Cabanes

ayuda para que compruebes que estn funcionando correctamente desde ciertos

(Nota: no debers entregar tus programas con ese "ReadLine" al final: es una

public class Ejemplo_01_03_03a


{
public static void Main()
{
System.Console.WriteLine("Hola");
System.Console.ReadLine();
}
}

se quede parado hasta que pulsemos Intro:

puede ser aadir "System.Console.ReadLine()" al final del programa, de modo que

editor tan rpido que no da tiempo a ver los resultados. Una solucin provisional

de desarrollo muestran el resultado de nuestro programa y luego regresan al

Hay un posible problema que se debe tener en cuenta: algunos de estos entornos

desarrollo, llamado Visual Studio.

MonoDevelop (para Windows, Linux y Mac), as como del entorno "oficial" de

un apartado posterior hablaremos de SharpDevelop (para Windows) y de

programas, incluso los de gran tamao que estn formados por varios ficheros, en

Si prefieres un entorno desde el que puedas teclear, compilar y probar tus

probar" de forma un tanto "artesanal".

temas tengas la obligacin de repetir el proceso "teclear - compilar - ejecutar -

cmo instalarlo y configurarlo, pero todava no, para que durante los primeros

"intrprete de comandos" del sistema operativo. Un poco ms adelante veremos

compilar y lanzar los programas desde el propio editor, sin necesidad de salir al

interesante, disponible para muchos sistemas operativos, y que permite incluso

podrs localizar fcilmente en Internet. Geany tambin es un alternativa muy

Notepad++, que es gratuito (realmente ms que eso: es de "cdigo abierto") y

Si quieres un editor ms potente que el Bloc de notas de Windows, puedes probar

1.3.3. Otros editores ms avanzados para Windows

nuestros fuentes.

Command Prompt de Mono se abra en la carpeta que habamos preparado para

Introduccin a la programacin con C#, por Nacho Cabanes

Luego la negacin.

Despus las multiplicaciones, divisiones y el resto de la divisin.

Finalmente, las sumas y las restas.

En caso de tener igual prioridad, se analizan de izquierda a derecha.

resultado de las siguientes operaciones:


Revisin 0.99zz Pgina 35

Ejercicios propuestos: Calcular (a mano y despus comprobar desde C#) el

public class Ejemplo_01_05_02a


{
public static void Main()
{
System.Console.WriteLine("Ejemplo de precedencia de operadores");
System.Console.WriteLine("3+4*5=");
System.Console.WriteLine(3+4*5);
}
}

multiplicacin).

a la izquierda, porque la prioridad de la suma es menor que la de la

se le suma 3) en vez de 35 (no se suma 3+4 antes de multiplicar, aunque aparezca

As, el siguiente ejemplo da como resultado 23 (primero se multiplica 4*5 y luego

En primer lugar se realizarn las operaciones indicadas entre parntesis.

Sencillo:

1.5.2. Orden de prioridad de los operadores

(1.5.1.4) Un programa que calcule el resto de la divisin de 301 entre 3.

(1.5.1.3) Un programa que calcule el resultado de dividir 301 entre 3.

(1.5.1.2) Un programa que calcule la diferencia (resta) entre 321 y 213.

(1.5.1.1) Haz un programa que calcule el producto de los nmeros 12 y 13.

Ejercicios propuestos:

tipo de datos que querremos guardar.


Revisin 0.99zz Pgina 36

Para usar una cierta variable primero hay que declararla: indicar su nombre y el

1.6.1. Definicin de variables: nmeros enteros

enteros que fijsemos en el programa.

Como primer ejemplo, vamos a ver lo que haramos para sumar dos nmeros

variables.

resultados temporales. A estas "zonas de memoria con nombre" les llamaremos

y en las que guardemos los datos con los que vamos a trabajar y tambin los

Por eso necesitaremos reservar zonas de memoria a las que datemos un nombre

de valores que haya tecleado el usuario o de clculos anteriores.

programa. Pero esto tampoco es "lo habitual", sino que esos nmeros dependern

all y nos permita sumar dos nmeros que habamos prefijado en nuestro

El primer ejemplo nos permita escribir "Hola". El segundo llegaba un poco ms

1.6. Introduccin a las variables: int

public class Ejemplo_01_05_03a


{
public static void Main()
{
System.Console.WriteLine(10000000*10000000);
}
}

compila, porque el compilador sabe que el resultado va a ser "demasiado grande":

este problema y cmo evitarlo. Como anticipo, el siguiente programa ni siquiera

usaremos nmeros pequeos. Ms adelante veremos a qu se debe realmente

mensaje de error o un resultado errneo. Por eso en los primeros ejemplos

resultado de una operacin es un nmero "demasiado grande", obtendremos un

los lmites exactos ms adelante, pero de momento nos basta saber que si el

El espacio del que disponemos para almacenar los nmeros es limitado. Veremos

1.5.3. Introduccin a los problemas de desbordamiento

(1.5.2.4) Calcular el resultado de 2 + 10 / 5 * 2 - 7 % 1

(1.5.2.3) Calcular el resultado de 15 + -5*6 / 10

public class Ejemplo_01_05_01a


{
public static void Main()
{
System.Console.WriteLine("El resto de dividir 19 entre 5 es");
System.Console.WriteLine(19 % 5);
}
}

(1.5.2.2) Calcular el resultado de (20+5) % 6

forma:

(1.5.2.1) Calcular el resultado de -2 + 3 * 5

Introduccin a la programacin con C#, por Nacho Cabanes

As, podemos calcular el resto de la divisin entre dos nmeros de la siguiente

Introduccin a la programacin con C#, por Nacho Cabanes

nmeros enteros; una de ellas se llama primerNumero y tiene como valor inicial
234 y la otra se llama segundoNumero y tiene como valor inicial 567).

se indican con "int" (abreviatura del ingls "integer"). Despus de esta palabra se

indica el nombre que tendr la variable:

Una vez que sabemos cmo mostrar un nmero en pantalla, es sencillo mostrar el

Podemos darle un valor a esa variable durante el programa haciendo

int primerNumero = 234, segundoNumero = 567;

Revisin 0.99zz Pgina 37

O incluso podemos definir e inicializar ms de una variable a la vez

int primerNumero, segundoNumero;

Si varias variables son del mismo tipo, podemos declararlas a la vez

int primerNumero = 234;

empiece el programa, en el mismo momento en que las definimos:

Tambin podemos dar un valor inicial a las variables ("inicializarlas") antes de que

primerNumero = 234;
primerNumero = 237;

cambiar el valor de una variable tantas veces como queramos

la derecha. Por eso no se puede hacer 234 = primerNumero, y s se puede

"asignacin de valor": el elemento de la izquierda recibe el valor que indicamos a

Hay que tener en cuenta que esto no es una igualdad matemtica, sino una

int primerNumero;
...
primerNumero = 234;

System.Console.WriteLine("La suma es {0}.", suma);

public class Ejemplo_01_06_03a

nmeros usando variables:

Revisin 0.99zz Pgina 38

Ya sabemos todo lo suficiente para crear nuestro programa que sume dos

System.Console.WriteLine("La suma de {0} y {1} es {2}",


primerNumero, segundoNumero, suma);

separados por comas:

necesario, y tras el texto incluiremos los nombres de cada una de esas variables,

aparecer cada una de ellas, usando {0}, {1} y tantos nmeros sucesivos como sea

Si queremos mostrar de ms de una variable, detallaremos en el texto dnde debe

forma:

de dicho texto queremos que aparezca el valor de la variable, de la siguiente

variable, podemos indicar el texto entre comillas, detallando con {0} en qu parte

O bien, si queremos mostrar un texto prefijado adems del valor de la

System.Console.WriteLine(suma);

analice su valor de antes de escribir):

pero si se trata de una variable es idntico (sin comillas, para que el compilador

System.Console.WriteLine(3+4);

valor de una variable. Para un nmero hacamos cosas como

1.6.3. Mostrar el valor de una variable en pantalla

1.6.2. Asignacin de valores

variables, llamadas n1, n2, n3.

Ejercicio propuesto (1.6.2.1): Ampla el ejercicio 1.6.1.1, para que las tres
variables n1, n2, n3 estn declaradas en la misma lnea y tengan valores iniciales.

suma = primerNumero + segundoNumero;

con los nmeros:

Ejercicio propuesto (1.6.1.1): Ampla el "Ejemplo 01.05.02a" para declarar tres

distintos valores, y al que nos referiremos con el nombre "primerNumero".

Esa orden reserva espacio para almacenar un nmero entero, que podr tomar

Despus ya podemos hacer operaciones con las variables, igual que las hacamos

(esta lnea reserva espacio para dos variables, que usaremos para almacenar

El primer tipo de datos que usaremos sern nmeros enteros (sin decimales), que

int primerNumero;
;

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

System.Console.WriteLine("La suma de {0} y {1} es {2}",


primerNumero, segundoNumero, suma);

primerNumero = 234;
segundoNumero = 567;
suma = primerNumero + segundoNumero;

public static void Main()


{
int primerNumero;
int segundoNumero;
int suma;

halla la suma de esos dos

primerNumero,

tres variables (los dos nmeros iniciales y su suma).

segundoNumero, suma); muestra en pantalla el texto y los valores de las

System.Console.WriteLine("La suma de {0} y {1} es {2}",

pantalla.

nmeros y la guarda en otra variable, en vez de mostrarla directamente en

suma = primerNumero + segundoNumero;

Revisin 0.99zz Pgina 39

(1.6.3.2) Crea un programa que calcule la suma de 285 y 1396, usando variables.

usando variables.

(1.6.3.1) Crea un programa que calcule el producto de los nmeros 121 y 132,

Ejercicios propuestos:

La suma de 234 y 567 es 801

El resultado de este programa sera:

sumar

segundoNumero = 567;

da el valor del segundo nmero que queremos

primerNumero = 234; da el valor del primer nmero que queremos sumar

llamaremos suma.

int suma; reserva espacio para guardar un tercer nmero entero, al que

que llamaremos segundoNumero.

int segundoNumero; reserva espacio para guardar otro nmero entero, al

llamaremos primerNumero.

int primerNumero; reserva espacio para guardar un nmero entero, al que

llaves: { y }

Main() indica donde comienza el cuerpo del programa, que se delimita entre

"void").

(Aplazamos todava los detalles de qu significan "public", "class", "static" y

Repasemos lo que hace:

Introduccin a la programacin con C#, por Nacho Cabanes

No deben tener espacios intermedios.

Tambin hay que

(empieza por nmero)


(contiene un espacio)
(tiene una ee)
(tiene una vocal acentuada)

esa variable, porque la habamos declarado como


Revisin 0.99zz Pgina 40

o cualquier variacin similar, el compilador protestar y nos dir que no conoce

PrimerNumero = 234;
primernumero = 234;

diferentes, de modo que si intentamos hacer

Hay que recordar que en C# las maysculas y minsculas se consideran

nos iremos encontrando con ellas).

variable (pero no vamos a incluir ahora una lista de palabras reservadas de C#, ya

entero, as que esa palabra "int" no la podremos usar tampoco como nombre de

Por ejemplo, la palabra "int" se refiere a que cierta variable guardar un nmero

Tampoco podremos usar como identificadores las palabras reservadas de C#.

aceptable).

estamos programando en C# con Visual Studio, el sistema s lo considerara

consideraremos vlido un nombre de variable como "ao", aun sabiendo que si

lenguajes de programacin, durante este curso introductorio nosotros no

contengan ee y vocales acentuadas, pero como no es lo habitual en todos los

(Nota: algunos entornos de programacin modernos s permitirn variables que

1numero
un numero
Ao1
MsDatos

Por eso, no son nombres de variable vlidos:

un identificador en la mayora de lenguajes de programacin.

letras "estndar" en todos los idiomas, as que no se pueden utilizar como parte de

recordar que las vocales acentuadas y la ee son problemticas, porque no son

letra o subrayado.

formados por letras, nmeros o el smbolo de subrayado (_) y deben comenzar por

Los nombres de variables (lo que se conoce como "identificadores") pueden estar

1.7. Identificadores

operacin n1+n2*n3.

(1.6.3.4) Ampla el ejercicio 1.6.2.1, para que se muestre el resultado de la

variables.

(1.6.3.3) Crea un programa que calcule el resto de dividir 3784 entre 16, usando

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 41

/* Y despus muestro su valor */


System.Console.WriteLine("La suma de {0} y {1} es {2}",
primerNumero, segundoNumero, suma);

/* Primero calculo la suma */


suma = primerNumero + segundoNumero;

public class Ejemplo_01_08a


{
public static void Main()
{
int primerNumero = 234;
int segundoNumero = 567;
int suma; /* Guardar el valor para usarlo ms tarde */

/* ---- Ejemplo en C#: sumar dos nmeros prefijados ---- */

ejemplo casi exagerado podra ser:

recuerde qu hace el programa sin que necesitemos mirarlo de arriba a abajo. Un

suele ser aconsejable que el programa comience con un comentario, que nos

nuestros programas que puedan resultar menos claras a simple vista. Incluso

Es conveniente escribir comentarios que aclaren la misin de las partes de

int suma; /* Guardar el valor para usarlo ms tarde */

escribiremos entre /* y */:

Existen dos formas de indicar comentarios. En su forma ms general, los

corregirlo.

fragmento del programa ms adelante, cuando tengamos que ampliarlo o

tiles para nosotros mismos, haciendo que sea ms fcil recordar el cometido un

Podemos escribir comentarios, que el compilador ignorar, pero que pueden ser

1.8. Comentarios

barra y terminan cuando se acaba la lnea (estos comentarios, claramente, no


podrn ocupar ms de una lnea). Son los "comentarios de una lnea" o

nmeros 87 y 94, usando esta vez variables llamadas "nmero1" y "nmero2".

donde te parezca adecuado.

Revisin 0.99zz Pgina 42

ejemplo, 3000) a millas. La equivalencia es 1 milla = 1609 metros. Usa comentarios

(1.8.1) Crea un programa que convierta una cantidad prefijada de metros (por

Ejercicios propuestos:

En este texto, a partir de ahora los fuentes comenzarn con un comentario que
resuma su cometido, y en ocasiones incluirn tambin comentarios intermedios.

// Y despus muestro su valor


System.Console.WriteLine("La suma de {0} y {1} es {2}",
primerNumero, segundoNumero, suma);

// Primero calculo la suma


suma = primerNumero + segundoNumero;

public class Ejemplo_01_08b


{
public static void Main()
{
int primerNumero = 234;
int segundoNumero = 567;
int suma; // Guardar el valor para usarlo ms tarde

// ---- Ejemplo en C#: sumar dos nmeros prefijados ----

De modo que el programa anterior se podra reescribir usando comentarios de


una lnea:

// Este es un comentario "al estilo C++"

lneas" o "comentarios al estilo de C" que ya hemos visto):

"comentarios al estilo de C++" (a diferencia de los "comentarios de mltiples

Tambin es posible declarar otro tipo de comentarios, que comienzan con doble

(1.7.4) Crea una nueva versin del programa que calcula el producto de los

/* Esto
es un comentario que
ocupa ms de una lnea
*/

Un comentario puede empezar en una lnea y terminar en otra distinta, as:

Introduccin a la programacin con C#, por Nacho Cabanes

los nmeros 87 y 94, usando esta vez variables llamadas "numero 1" y "numero 2".

(1.7.3) Intenta crear una nueva versin del programa que calcula el producto de

los nmeros 87 y 94, usando esta vez variables llamadas "1numero" y "2numero".

(1.7.2) Intenta crear una nueva versin del programa que calcula el producto de

variables llamadas "numero1" y "numero2".

(1.7.1) Crea un programa que calcule el producto de los nmeros 87 y 94, usando

Ejercicios propuestos:

int primerNumero;;

Introduccin a la programacin con C#, por Nacho Cabanes

por el usuario.
Revisin 0.99zz Pgina 43

(1.9.1) Crea un programa que calcule el producto de dos nmeros introducidos

Ejercicios propuestos:

System.Console.WriteLine("La suma de {0} y {1} es {2}",


primerNumero, segundoNumero, suma);

System.Console.WriteLine("Introduce el primer nmero");


primerNumero = System.Convert.ToInt32(
System.Console.ReadLine());
System.Console.WriteLine("Introduce el segundo nmero");
segundoNumero = System.Convert.ToInt32(
System.Console.ReadLine());
suma = primerNumero + segundoNumero;

// Ejemplo en C#: sumar dos nmeros introducidos por el usuario


public class Ejemplo_01_09a
{
public static void Main()
{
int primerNumero;
int segundoNumero;
int suma;

Un ejemplo de programa que sume dos nmeros tecleados por el usuario sera:

primerNumero = System.Convert.ToInt32( System.Console.ReadLine() );

deberemos convertir ese dato a un nmero entero, usando Convert.ToInt32:

momento, nosotros slo sabemos manipular nmeros enteros, as que

pero eso ocurrir un poco ms adelante, cuando veamos cmo manejar textos. De

texto = System.Console.ReadLine();

System.Console.ReadLine ("leer lnea"). Para leer textos, haramos

igual que tenemos System.Console.WriteLine ("escribir lnea"), tambin existe

necesitamos una nueva orden, que nos permita leer desde teclado. Pues bien, al

Si queremos que sea el usuario de nuestro programa quien teclee los valores,

directamente con el usuario.

cualquier otra red. El primer caso que veremos ser el de interaccionar

se lean desde un fichero, o desde una base de datos, o se reciban de Internet o

mundo real. Es mucho ms habitual que los datos los introduzca el usuario, o que

Hasta ahora hemos utilizado datos prefijados, pero eso es poco frecuente en el

1.9. Datos por el usuario: ReadLine

Introduccin a la programacin con C#, por Nacho Cabanes

Console.WriteLine("Introduce el primer nmero");


primerNumero = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Introduce el segundo nmero");

public class Ejemplo_01_10b


{
public static void Main()
{
int primerNumero, segundoNumero, suma;

Revisin 0.99zz Pgina 44

// Ejemplo en C#: "using System" y declaraciones mltiples de variables


using System;

programa podra ser an ms compacto:

Si adems declaramos varias variables a la vez, como vimos en el apartado 1.5.2, el

Console.WriteLine("La suma de {0} y {1} es {2}",


primerNumero, segundoNumero, suma);

Console.WriteLine("Introduce el primer nmero");


primerNumero = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Introduce el segundo nmero");
segundoNumero = Convert.ToInt32(Console.ReadLine());
suma = primerNumero + segundoNumero;

public class Ejemplo_01_10a


{
public static void Main()
{
int primerNumero;
int segundoNumero;
int suma;

// Ejemplo en C#: "using System" en vez de "System.Console"


using System;

"using System":

ahora, las de consola y las de conversin), si al principio del programa utilizamos

principio de la mayora de las rdenes que tienen que ver con el sistema (por

Va siendo hora de hacer una pequea mejora: no es necesario repetir "System." al

1.10. using System

en metros, usando: 1 milla nutica = 1852 metros.

(1.9.4) Pide al usuario una cantidad de "millas nuticas" y muestra la equivalencia

(1.9.3) Suma tres nmeros tecleados por usuario.

el usuario, as como el resto de esa divisin.

(1.9.2) Crea un programa que calcule la divisin de dos nmeros introducidos por

Introduccin a la programacin con C#, por Nacho Cabanes

legible), as
Revisin 0.99zz Pgina 45

(aunque generalmente eso har el programa ms largo y no necesariamente ms

Incluso el ltimo "WriteLine" de varios datos se podra convertir en varios Write

Console.WriteLine("La suma de {0} y {1} es {2}",


primerNumero, segundoNumero, suma);

Console.Write("Introduce el primer nmero: ");


primerNumero = Convert.ToInt32(Console.ReadLine());
Console.Write("Introduce el segundo nmero: ");
segundoNumero = Convert.ToInt32(Console.ReadLine());
suma = primerNumero + segundoNumero;

public class Ejemplo_01_11a


{
public static void Main()
{
int primerNumero, segundoNumero, suma;

// Ejemplo en C#: escribir sin avanzar de lnea


using System;

pantalla: emplear "Write" en vez de "WriteLine", as:

tambin escribir un texto y pedir un dato a continuacin, en la misma lnea de

calculados y textos prefijados. Pero hay otra alternativa, que adems nos permite

En el apartado 1.6.3 vimos cmo usar {0} para escribir en una misma lnea datos

1.11. Escribir sin avanzar de lnea

fecha en que has realizado el programa.

empleando "using System". Debers incluir un comentario con tu nombre y la

nmeros introducidos por el usuario, as como el resto de esa divisin (1.9.2),

(1.10.2) Crea una nueva versin del programa que calcula la divisin de dos

objetivo.

programa deber contener un comentario al principio, que recuerde cual es su

nmeros introducidos por el usuario (1.9.1), empleando "using System". El

(1.10.1) Crea una nueva versin del programa que calcula el producto de dos

Ejercicios propuestos:

Console.WriteLine("La suma de {0} y {1} es {2}",


primerNumero, segundoNumero, suma);

segundoNumero = Convert.ToInt32(Console.ReadLine());
suma = primerNumero + segundoNumero;

Introduccin a la programacin con C#, por Nacho Cabanes

mostrar varios datos en la misma lnea.

Revisin 0.99zz Pgina 46

= celsius x 18 / 10 + 32. Emplea "Write" en vez de "{0}" cuando debas

usar las siguiente tablas de conversin: kelvin = celsius + 273 ; fahrenheit

Kelvin y a Fahrenheit: pedir al usuario la cantidad de grados centgrados y

(1.11.4) Crea un programa que convierta de grados Celsius (centgrados) a

{1}, {2}, sino "Write".

nmero y muestra su tabla de multiplicar. Esta vez no debers utilizar {0},

(1.11.3) Crear una variante del programa anterior, que pide al usuario un

3 x 10 = 30

3x2=6

3x1=3

3x0=0

algo como

usando {0},{1} y {2}. Por ejemplo, si el nmero es el 3, debera escribirse

x (1.11.2) Pedir al usuario un nmero y mostrar su tabla de multiplicar,

Ambos resultados se deben mostrar en la misma lnea.

resultado de la operacin (a+b)*(a-b) y el resultado de la operacin a2-b2.

x (1.11.1) El usuario teclear dos nmeros (a y b), y el programa mostrar el

Ejercicios propuestos:

Console.Write("Introduce el primer nmero: ");


primerNumero = Convert.ToInt32(Console.ReadLine());
Console.Write("Introduce el segundo nmero: ");
segundoNumero = Convert.ToInt32(Console.ReadLine());
suma = primerNumero + segundoNumero;
Console.Write("La suma de ");
Console.Write(primerNumero);
Console.Write(" y ");
Console.Write(segundoNumero);
Console.Write(" es ");
Console.WriteLine(suma);

public class Ejemplo_01_11b


{
public static void Main()
{
int primerNumero, segundoNumero, suma;

// Ejemplo en C#: escribir sin avanzar de lnea (2)


using System;

Introduccin a la programacin con C#, por Nacho Cabanes

if (x % 2 == 0) ).

Revisin 0.99zz Pgina 47

pantalla "El nmero es positivo."; si es negativo o cero, no hace nada.

Este programa pide un nmero al usuario. Si es positivo (mayor que 0), escribe en

Console.WriteLine("Introduce un nmero");
numero = Convert.ToInt32(Console.ReadLine());
if (numero>0) Console.WriteLine("El nmero es positivo.");

public class Ejemplo_02_01_01a


{
public static void Main()
{
int numero;

using System;

// Ejemplo_02_01_01a.cs
// Condiciones con if
// Introduccin a C#, por Nacho Cabanes

if (condicin) sentencia;

Esa

public class Ejemplo_02_01_02a


{
public static void Main()

using System;

// Ejemplo_02_01_02a.cs
// Condiciones con if (2): Sentencias compuestas
// Introduccin a C#, por Nacho Cabanes

sentencias simples entre llaves ( { y } ), como en este ejemplo:

Revisin 0.99zz Pgina 48

simple o una compuesta. Las sentencias compuestas se forman agrupando varias

"sentencia" que se ejecuta si se cumple la condicin puede ser una sentencia

Habamos dicho que el formato bsico de "if" es

2.1.2. if y sentencias compuestas

de la divisin es cero: a % b == 0).

primero es mltiplo del segundo (pista: igual que antes, habr que ver si el resto

(2.1.1.3) Crea un programa que pida al usuario dos nmeros enteros y diga si el

el mayor de ellos.

(2.1.1.2) Crea un programa que pida al usuario dos nmeros enteros y diga cul es

(pista: habr que comprobar si el resto que se obtiene al dividir entre dos es cero:

cumplirse esa condicin, terminando con un punto y coma.

Vamos a verlo con un ejemplo:

(2.1.1.1) Crea un programa que pida al usuario un nmero entero y diga si es par

parntesis y a continuacin se detallar la orden que hay que realizar en caso de

Ejercicios propuestos:

if (numero>0)
Console.WriteLine("El nmero es positivo.");

Si la orden "if" es larga, se puede partir en dos lneas para que resulte ms legible:

pretendamos hacer.

incluiremos comentarios que nos permitan recordar de un vistazo qu

Como nuestros fuentes irn siendo cada vez ms complejos, a partir de ahora

Este programa comienza por un comentario que nos recuerda de qu se trata.

indicarse entre parntesis.

adelante. En todos los casos, la condicin que queremos comprobar deber

smbolos de "igual": if (numero==0). Las dems posibilidades las veremos algo ms

otro, usamos el smbolo ">". Para ver si dos valores son iguales, usaremos dos

Como se ve en el ejemplo, para comprobar si un valor numrico es mayor que

Introduccin a la programacin con C#, por Nacho Cabanes

Es decir, debe empezar con la palabra "if", la condicin se debe indicar entre

if (condicin) sentencia;

condicin ser "si ... entonces ...". Su formato es

La primera construccin que emplearemos para comprobar si se cumple una

2.1.1. if

2.1. Estructuras alternativas

repita.

cumplen condiciones y tambin cmo hacer que un bloque de un programa se

esos pasos debern ser repetitivos. Vamos a ver cmo podemos comprobar si se

funcin de si se cumplen ciertas condiciones o no. En muchas ocasiones, adems

deseemos automatizar supondr tomar decisiones: dar una serie de pasos en

Casi cualquier problema del mundo real que debamos resolver o tarea que

2. Estructuras de control

Introduccin a la programacin con C#, por Nacho Cabanes

Console.WriteLine("Introduce un nmero");
numero = Convert.ToInt32(Console.ReadLine());
if (numero > 0)
{
Console.WriteLine("El nmero es positivo.");
Console.WriteLine("Recuerde que tambin puede usar negativos.");
} // Aqu acaba el "if"
// Aqu acaba "Main"
// Aqu acaba "Ejemplo06

int numero;

(2.1.3.1) Crea un programa que multiplique dos nmeros enteros de la siguiente


forma: pedir al usuario un primer nmero entero. Si el nmero que se que teclee
es 0, escribir en pantalla "El producto de 0 por cualquier nmero es 0". Si se ha
tecleado un nmero distinto de cero, se pedir al usuario un segundo nmero y se
mostrar el producto de ambos.
(2.1.3.2) Crea un programa que pida al usuario dos nmeros enteros. Si el

"Main" algo ms a la derecha, y la sentencia compuesta que se debe realizar si se

cumple la condicin del "if" est an ms a la derecha. Este "sangrado" del texto

se suele llamar "escritura indentada". Un tamao habitual para el sangrado es de

4 espacios, aunque en este texto en algunas ocasiones usaremos slo dos

espacios, para que fuentes ms complejos quepan entre los mrgenes del papel.

Operador
<
>
<=
>=
==
!=

Operacin
Menor que
Mayor que
Menor o igual que
Mayor o igual que
Igual a
No igual a (distinto de)

son un poco menos evidentes, as que vamos a verlos:

Revisin 0.99zz Pgina 49

mayor que otro. El smbolo de "menor que" tambin es sencillo, pero los dems

Hemos visto que el smbolo ">" es el que se usa para comprobar si un nmero es

2.1.3. Operadores relacionales: <, <=, >, >=, ==, !=

continuacin si este segundo nmero tambin es mltiplo de 10.

public class Ejemplo_02_01_04a


{
public static void Main()
{
int numero;

using System;

// Ejemplo_02_01_04a.cs
// Condiciones con if (4): caso contrario ("else")
// Introduccin a C#, por Nacho Cabanes

condicin, usando la orden "else" (en caso contrario), as:

Revisin 0.99zz Pgina 50

Podemos indicar lo que queremos que ocurra en caso de que no se cumpla la

2.1.4. if-else

entre cero".

(2.1.2.1) Crea un programa que pida al usuario un nmero entero. Si es mltiplo

de 10, informar al usuario y pedir un segundo nmero, para decir a

Por el contrario, si el segundo nmero es cero, escribir "Error: No se puede dividir

Ejercicios propuestos:

segundo no es cero, mostrar el resultado de dividir entre el primero y el segundo.

Ejercicios propuestos:

poco ms a la derecha que la cabecera "public class Ejemplo06", y el contenido de

Console.WriteLine("Introduce un nmero");
numero = Convert.ToInt32(Console.ReadLine());
if (numero != 0)
Console.WriteLine("El nmero no es cero.");

public class Ejemplo_02_01_03a


{
public static void Main()
{
int numero;

using System;

// Ejemplo_02_01_03a.cs
// Condiciones con if (3): "distinto de"
// Introduccin a C#, por Nacho Cabanes

As, un ejemplo, que diga si un nmero no es cero sera:

Introduccin a la programacin con C#, por Nacho Cabanes

cada seccin de un programa. Por ejemplo, el contenido de "Ejemplo06" est un

la derecha que los anteriores, para que sea fcil ver dnde comienza y termina

Como se ve en este ejemplo, cada nuevo "bloque" se suele escribir un poco ms a

compuesta).

en lo que necesitemos hacer cosas "ms serias" dentro de una sentencia

luego... escribir otro! (no es gran cosa; ms adelante iremos encontrando casos

En este caso, si el nmero es positivo, se hacen dos cosas: escribir un texto y

Introduccin a la programacin con C#, por Nacho Cabanes

public class Ejemplo_02_01_04c


{

using System;

// Ejemplo_02_01_04c.cs
// Condiciones con if (6): condiciones encadenadas
// Introduccin a C#, por Nacho Cabanes

condicin, mira a ver si se cumple esta otra":

Revisin 0.99zz Pgina 51

Podemos enlazar varios "if" usando "else", para decir "si no se cumple esta

negativo o cero, por lo que el programa es algo ms lento.

nmero sea positivo, se vuelve a realizar la segunda comprobacin para ver si es

el programa ya ha terminado. En el segundo caso (ejemplo 02_01_04b), aunque el

se mira si el valor es positivo; si no lo es, se pasa a la segunda orden, pero si lo es,

Pero el comportamiento no es el mismo: en el primer caso (ejemplo 02_01_04a)

if (numero <= 0)
Console.WriteLine("El nmero es cero o negativo.");

if (numero > 0)
Console.WriteLine("El nmero es positivo.");

Console.WriteLine("Introduce un nmero");
numero = Convert.ToInt32(Console.ReadLine());

public class Ejemplo_02_01_04b


{
public static void Main()
{
int numero;

using System;

// Ejemplo_02_01_04b.cs
// Condiciones con if (5): caso contrario, sin "else"
// Introduccin a C#, por Nacho Cabanes

otro, as:

Podramos intentar evitar el uso de "else" si utilizamos un "if" a continuacin de

Console..WriteLine("Introduce un nmero");
numero = Convert.ToInt32(Console.ReadLine());
if (numero > 0)
Console.WriteLine("El nmero es positivo.");
else
Console.WriteLine("El nmero es cero o negativo.");

Introduccin a la programacin con C#, por Nacho Cabanes

Y
O
No

&&
||
!

...

using System;

// Ejemplo_02_01_05a.cs
// Condiciones con if enlazadas con &&
// Introduccin a C#, por Nacho Cabanes

podra ser:

Revisin 0.99zz Pgina 52

As, un programa que dijera si dos nmeros introducidos por el usuario son cero,

if ((opcion=
==1) && (usuario===2)) ...
if ((opcion=
==1) || (opcion=
==3)) ...
if ((!(opcion=
==opcCorrecta)
)) || (tecla=
==ESC)))

De modo que, ya con la sintaxis de C#, podremos escribir cosas como

Significado

Operador

Esos operadores se indican de la siguiente forma

correcta y no hemos agotado los intentos.

hemos encontrado la llave. O deberemos volver a pedir una contrasea si no es

nivel. Y podemos avanzar al nivel siguiente si hemos llegado hasta la puerta y

de un juego puede acabar si nos quedamos sin vidas o si superamos el ltimo

Las condiciones se puede encadenar con "y", "o", "no". Por ejemplo, una partida

2.1.5. Operadores lgicos: &&, ||, !

(2.1.4.2) Mejora la solucin al ejercicio 2.1.3.2, usando "else".

(2.1.4.1) Mejora la solucin al ejercicio 2.1.3.1, usando "else".

Ejercicio propuesto:

if (numero > 0)
Console.WriteLine("El nmero es positivo.");
else
if (numero < 0)
Console.WriteLine("El nmero es negativo.");
else
Console.WriteLine("El nmero es cero.");

Console.WriteLine("Introduce un nmero");
numero = Convert.ToInt32(Console.ReadLine());

public static void Main()


{
int numero;

Introduccin a la programacin con C#, por Nacho Cabanes

menos) uno es par.


Revisin 0.99zz Pgina 53

(2.1.5.6) Crea un programa que pida al usuario dos nmeros enteros y diga si (al

ambos son pares.

(2.1.5.5) Crea un programa que pida al usuario dos nmeros enteros y diga si

es mltiplo de 2 ni de 3.

(2.1.5.4) Crea un programa que pida al usuario un nmero entero y responda si no

mltiplo de 2 pero no de 3.

Console.WriteLine("Introduce un nmero");
numero = Convert.ToInt32(Console.ReadLine());
if (numero = 0)

public class Ejemplo_02_01_06a


{
public static void Main()
{
int numero;

using System;

(2.1.5.3) Crea un programa que pida al usuario un nmero entero y responda si es

mltiplo de 2 y de 3 simultneamente.

// Ejemplo_02_01_06a.cs
// Condiciones con if: comparacin incorrecta
// Introduccin a C#, por Nacho Cabanes

del siguiente programa:

Revisin 0.99zz Pgina 54

implicitly convert type 'int' to 'bool'" (no puedo convertir un "int" a "bool"). Es el caso

de tipo "bool"), de modo que obtendramos un error de compilacin "Cannot

algo cuyo resultado sea "verdadero" o "falso" (lo que pronto llamaremos un dato

En el caso del lenguaje C#, este riesgo no existe, porque la "condicin" debe ser

aviso, dando lugar a un funcionamiento incorrecto de nuestro programa).

"aviso", lo que permite que se genere un ejecutable, y podramos pasar por alto el

un valor sin pretenderlo, pero no es un "error" que invalide la compilacin, sino un

compiladores modernos al menos nos avisaran de que quiz estemos asignando

se considera vlido hacer una asignacin dentro de un "if" (aunque la mayora de

En algunos compiladores de lenguaje C, esto podra ser un problema serio, porque

asignar a "a" el valor de "b".

(a==b) ... Si no nos acordamos y escribimos if (a=b), estamos intentando

Cuidado con el comparador de igualdad: hay que recordar que el formato es if

2.1.6. El peligro de la asignacin en un "if"

iguales o, en caso contrario, cul es el mayor de ellos.

(2.1.5.10) Crea un programa que pida al usuario dos nmeros enteros y diga si son

mayor de los tres.

(2.1.5.9) Crea un programa que pida al usuario tres nmeros y muestre cul es el

los nmeros es positivo", segn corresponda.

de los nmeros es positivo", "Los dos nmeros son positivos" o bien "Ninguno de

(2.1.5.8) Crea un programa que pida al usuario dos nmeros enteros y diga "Uno

y slo uno es par.

(2.1.5.7) Crea un programa que pida al usuario dos nmeros enteros y diga si uno

Introduccin a la programacin con C#, por Nacho Cabanes

(2.1.5.2) Crea un programa que pida al usuario un nmero entero y responda si es

mltiplo de 2 o de 3.

(2.1.5.1) Crea un programa que pida al usuario un nmero entero y responda si es

Ejercicios propuestos:

vamos a ver unos cuantos ejercicios propuestos...

Como la mejor forma de entender este tipo de expresiones es practicndolas,

porque ya se sabe que la expresin global ser "verdadera".

la primera de ellas es "verdadera": no ser necesario comprobar la segunda,

toda la expresin. Lo mismo ocurrira si hay dos condiciones enlazadas con "o", y

el valor de "usuario", porque, sea el que sea, no podr hacer que sea "verdadera"

&& (usuario===2)), si "opcion" no vale 1, el compilador no se molesta en ver cul es

podr ser cierta. Eso supone que en el primer ejemplo anterior, if ((opcion===1)

segunda, porque se sabe de antemano que la condicin formada por ambas no

primera de las condiciones no se cumple, ni siquiera se llega a comprobar la

dos condiciones que estn enlazadas con "Y" se hace "en cortocircuito": si la

Una curiosidad: en C# (y en algn otro lenguaje de programacin), la evaluacin de

if ((n1 > 0) && (n2 > 0))


Console.WriteLine("Ambos nmeros son positivos.");
else
Console.WriteLine("Al menos uno no es positivo.");

Console.Write("Introduce un nmero: ");


n1 = Convert.ToInt32(Console.ReadLine());
Console.Write("Introduce otro nmero: ");
n2 = Convert.ToInt32(Console.ReadLine());

public class Ejemplo_02_01_05a


{
public static void Main()
{
int n1, n2;

Introduccin a la programacin con C#, por Nacho Cabanes

...

Revisin 0.99zz Pgina 55

El inicio o el final del programa se indica dentro de un crculo.

Es decir:

luego los aplicaremos a un caso concreto.

En primer lugar, vamos a ver los 4 elementos bsicos de un diagrama de flujo, y

diagramas de flujo, que nos permiten ver mejor qu se debe hacer y cuando.

Para ayudarnos a centrarnos en el problema, existen notaciones grficas, como los

vez de pensar en el problema que se pretende resolver.

dificultad est en el hecho de intentar teclear directamente un programa en C#, en

las que siguen a un "if" deben ir entre llaves y cuales no. Generalmente la

A veces puede resultar difcil ver claro donde usar un "else" o qu instrucciones de

2.1.7. Introduccin a los diagramas de flujo

comparacin y los nmeros en el lado izquierdo.

igualdad sea correcta y en la que las variables aparezcan en el lado derecho de la

(2.1.6.1) Crea una variante del ejemplo 02_01_06a, en la que la comparacin de

Ejercicios propuestos:

if (0 == numero)

signo de "=", obtendramos una asignacin no vlida y el programa no compilara:

colocando el nmero en el lado izquierdo, de modo que si olvidamos el doble

valor en vez de comparar, se suele recomendar plantear la comparacin al revs,

Nota: en lenguajes como C y C++, en los que s existe este riesgo de asignar un

Console.
.WriteLine("El nmero es cero.");
else
if (numero < 0)
Console.WriteLine("El nmero es negativo.");
else
Console.WriteLine("El nmero es positivo.");

Introduccin a la programacin con C#, por Nacho Cabanes

cumple una de las dos opciones posibles.

flechas. Cada una de ellas corresponder a la secuencia de pasos a dar si se

Las decisiones se indican dentro de un rombo, desde el que saldrn dos

horizontales, pero no tenga verticales los otros dos.

indican con un paralelogramo que tenga su lados superior e inferior

Las entradas y salidas (escrituras en pantalla y lecturas de teclado) se

rectngulo.

Los procesos internos, como realizar operaciones, se encuadran en un

diga si es positivo, negativo o cero:

Revisin 0.99zz Pgina 56

Vamos a aplicarlo al ejemplo de un programa que pida un nmero al usuario y

Introduccin a la programacin con C#, por Nacho Cabanes

dentro de poco, por lo que su uso actual es muy limitado.


Revisin 0.99zz Pgina 57

permite representar de forma fiable las estructuras repetitivas que veremos

Eso s, hay que tener en cuenta que sta es una notacin anticuada, y que no

en su salida "no".

que aparece en su salida "si" y si no se cumple ("else") ejecutar lo que aparezca

en pantalla, y las decisiones sern un "if", que si se cumple ejecutar la sentencia

ejemplo 11) debe ser casi inmediato: sabemos como leer de teclado, como escribir

El paso de aqu al correspondiente programa en lenguaje C# (el que vimos en el

Introduccin a la programacin con C#, por Nacho Cabanes

public class Ejemplo_02_01_08a


{
public static void Main()
{

using System;

// Ejemplo_02_01_08a.cs
// El operador condicional
// Introduccin a C#, por Nacho Cabanes

Aplicado a un programa sencillo, podra ser

se cumple o no una condicin.

Revisin 0.99zz Pgina 58

queramos optar entre dos valores posibles para una variable, dependiendo de si

Al igual que en este ejemplo, podremos usar el operador condicional cuando

if ( a > b )
numeroMayor = a;
else
numeroMayor = b;

esto equivale a la siguiente orden "if":

numeroMayor = a>b ? a : b;

de dos nmeros:

valor valor2". Un ejemplo de cmo podramos usarlo sera para calcular el mayor

y equivale a decir "si se cumple la condicin, toma el valor valor1; si no, toma el

nombreVariable = condicion ? valor1 : valor2;

"operador ternario"), que se usa

ms difcil de leer. Es el "operador condicional" ? : (tambin conocido como

asignar un valor segn se cumpla una condicin o no, ms compacta pero tambin

En C#, al igual que en la mayora de lenguajes que derivan de C, hay otra forma de

2.1.8. Operador condicional: ?

usuario y dice cul es el mayor de los tres.

(2.1.7.3) Crea el diagrama de flujo para el programa que pide tres nmeros al

nmeros y dice si uno de ellos es positivo, si lo son los dos o si no lo es ninguno.

(2.1.7.2) Crea el diagrama de flujo para el programa que pide al usuario dos

usuario y dice cul es el mayor de los dos.

(2.1.7.1) Crea el diagrama de flujo para el programa que pide dos nmeros al

Ejercicios propuestos:

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 59

(2.1.8.2) Usa el operador condicional para calcular el menor de dos nmeros.

mostrar tal cual; si es negativo, se mostrar cambiado de signo.

valor absoluto de un nmero de la siguiente forma: si el nmero es positivo, se

(2.1.8.1) Crea un programa que use el operador condicional para mostrar un el

Ejercicios propuestos:

resultado = operacion == 1 ? a-b : a+b;


Console.WriteLine("El resultado es {0}.", resultado);

Console.Write("Escriba una operacin (1 = resta; otro = suma): ");


operacion = Convert.ToInt32(Console.ReadLine());

Console.Write("Escriba otro: ");


b = Convert.ToInt32(Console.ReadLine());

Console.Write("Escriba un nmero: ");


a = Convert.ToInt32(Console.ReadLine());

public class Ejemplo_02_01_08b


{
public static void Main()
{
int a, b, operacion, resultado;

using System;

// Ejemplo_02_01_08b.cs
// El operador condicional (2)
// Introduccin a C#, por Nacho Cabanes

escoja, sera:

Un segundo ejemplo, que sume o reste dos nmeros segn la opcin que se

Console.WriteLine("El mayor de los nmeros es {0}.", mayor);

mayor = a>b ? a : b;

Si queremos ver varios posibles valores, sera muy pesado tener que hacerlo con

posibles.

ellos para indicarlo.

Si dos casos tienen que hacer lo mismo, se aade "goto case" a uno de

condiciones, se detalla despus de la palabra "default".

Si hay que hacer algo en caso de que no se cumpla ninguna de las

un cierto valor se indican a continuacin, terminando con "break".

Los pasos (porque pueden ser varios) que se deben dar si la expresin tiene

public class Ejemplo_02_01_09a


{
public static void Main()
{
char letra;

using System;

// Ejemplo_02_01_09a.cs
// La orden "switch" (1)
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 60

ReadLine, y que le podemos dar un valor (o compararlo) usando comillas simples:

nos basta que deberemos usar Convert.ToChar si lo leemos desde teclado con

"char" (carcter), que veremos con ms detalle en el prximo tema. De momento

cifra numrica, un espacio u otro smbolo. Para ello usaremos un dato de tipo

Vamos a ver un ejemplo, que diga si el smbolo que introduce el usuario es una

Tras la palabra "switch" se escribe la expresin a analizar, entre parntesis.


Despus, tras varias rdenes "case" se indica cada uno de los valores

x
x

Es decir:

switch (expresin)
{
case valor1: sentencia1;
break;
case valor2: sentencia2;
sentencia2b;
break;
case valor3:
goto case valor1;
...
case valorN: sentenciaN;
break;
default:
otraSentencia;
break;
}

cuya sintaxis es

muchos "if" seguidos o encadenados. La alternativa es emplear la orden "switch",

2.1.9. switch

Console.Write("Escriba un nmero: ");


a = Convert.ToInt32(Console.ReadLine());
Console.Write("Escriba otro: ");
b = Convert.ToInt32(Console.ReadLine());

Introduccin a la programacin con C#, por Nacho Cabanes

int a,
, b, mayor;

Introduccin a la programacin con C#, por Nacho Cabanes

switch (letra)
{
case ' ': Console.WriteLine("Espacio.");
break;
case '1':
case '2':
case '3':
case '4':
case '5':

Console.WriteLine("Introduce una letra");


letra = Convert.ToChar( Console.ReadLine() );

public class Ejemplo_02_01_09b


{
public static void Main()
{
char letra;

using System;

// Ejemplo_02_01_09b.cs
// La orden "switch" (variante sin break)
// Introduccin a C#, por Nacho Cabanes

y en ese caso se puede dejar totalmente vaco:

Revisin 0.99zz Pgina 61

caso no haga absolutamente nada excepto dejar pasar el control al siguiente caso,

errores provocados por una "break" olvidado) con la nica excepcin de que un

C# siempre obliga a usar "break" o "goto" al final de cada cada caso (para evitar

manejado por el siguiente, lo que se consigue si no se usa "break", mientras que

Cuidado quien venga del lenguaje C: en C se puede dejar que un caso sea

switch (letra)
{
case ' ': Console.WriteLine("Espacio.");
break;
case '1': goto case '0';
case '2': goto case '0';
case '3': goto case '0';
case '4': goto case '0';
case '5': goto case '0';
case '6': goto case '0';
case '7': goto case '0';
case '8': goto case '0';
case '9': goto case '0';
case '0': Console.WriteLine("Dgito.");
break;
default: Console.WriteLine("Ni espacio ni dgito.");
break;
}

Console..WriteLine("Introduce una letra");


letra = Convert.ToChar( Console.ReadLine() );

Introduccin a la programacin con C#, por Nacho Cabanes

Ejercicios propuestos:
Revisin 0.99zz Pgina 62

Console.WriteLine("Bienvenido, Juan.");
break;
case "Pedro": Console.WriteLine("Que tal estas, Pedro.");
break;
default:
Console.WriteLine("Procede con cautela,
desconocido.");
break;
}
}
}

switch (nombre)
{
case "Juan":

Console.WriteLine("Introduce tu nombre");
nombre = Console.ReadLine();

public class Ejemplo_02_01_09c


{
public static void Main()
{
string nombre;

using System;

// Ejemplo_02_01_09c.cs
// La orden "switch" con cadenas de texto
// Introduccin a C#, por Nacho Cabanes

personalizada si somos "Juan" o "Pedro" podra ser:

entre comillas dobles. Por ejemplo, un programa que nos salude de forma

necesidad de convertir) y se le puede dar un valor desde programa si se indica

declara con la palabra "string", se puede leer de teclado con ReadLine (sin

Una cadena de texto, como veremos con ms detalle en el prximo tema, se

texto ("strings").

ms evolucionado, se puede usar tambin para comprobar valores de cadenas de

valores de variables "simples" (numricas y caracteres); en C#, que es un lenguaje

En el lenguaje C, que es ms antiguo, slo se poda usar "switch" para comprobar

'6':
'7':
'8':
'9':
'0': Console.WriteLine("Dgito.");
break;
default: Console.WriteLine("Ni espacio ni dgito.");
break;

case
case
case
case
case

Introduccin a la programacin con C#, por Nacho Cabanes

que termine cuando tecleemos el nmero 0, podra ser:


Revisin 0.99zz Pgina 63

Un ejemplo que nos diga si cada nmero que tecleemos es positivo o negativo, y

se repita ms de una sentencia, basta agruparlas entre llaves: { y }.

es falsa ya desde un principio, la sentencia no se ejecuta nunca. Si queremos que

Es decir, la sentencia se repetir mientras la condicin sea cierta. Si la condicin

while (condicin))
sentencia;;

En el primer caso, su sintaxis es

bloque repetitivo.

formatos distintos, segn comprobemos la condicin al principio o al final del

cumpla una cierta condicin, usaremos la orden "while". Esta orden tiene dos

Si queremos hacer que una seccin de nuestro programa se repita mientras se

2.2.1.1. Estructura bsica de un bucle "while"

2.2.1. while

conseguirlo.

una condicin (lo que llamaremos un "bucle"). En C# tenemos varias formas de

parte de un programa se repita un cierto nmero de veces o mientras se cumpla

Hemos visto cmo comprobar condiciones, pero no cmo hacer que una cierta

2.2. Estructuras repetitivas


}

Revisin 0.99zz Pgina 64

segundo es mltiplo del primero, o ninguno de ellos es mltiplo del otro.

cada par de nmeros, responder si el primero es mltiplo del segundo, o el

(2.2.1.1.4) Crea una versin mejorada del programa anterior, que, tras introducir

del segundo.

usuario. Tras introducir cada par de nmeros, responder si el primero es mltiplo

(2.2.1.1.3) Crea un programa que pida de forma repetitiva pares de nmeros al

(usa "while" para conseguirlo).

mostrar su cuadrado. Se repetir mientras el nmero introducido no sea cero

(2.2.1.1.2) Crea un "calculador de cuadrados": pedir al usuario un nmero y

volvrsela a pedir tantas veces como sea necesario.

Deber terminar cuando introduzca como contrasea el nmero 1111, pero

(2.2.1.1.1) Crea un programa que pida al usuario su contrasea (numrica).

Ejercicios propuestos:

se entra al bloque del "while", terminando el programa inmediatamente.

En este ejemplo, si se introduce 0 la primera vez, la condicin es falsa y ni siquiera

Console.WriteLine("Teclea otro nmero (0 para salir): ");


numero = Convert.ToInt32(Console.ReadLine());

while (numero != 0)
{
if (numero > 0) Console.WriteLine("Es positivo");
else Console.WriteLine("Es negativo");

valores, sino que se puede hacer con "if ((simbolo >= '0') && (simbolo <='9'))").

(2.1.9.6) Repite el ejercicio 2.1.9.3, empleando "if" en lugar de "switch".

las cfras numricas del 0 al 9 estn ordenadas, no hace falta comprobar los 10

Console.Write("Teclea un nmero (0 para salir): ");


numero = Convert.ToInt32(Console.ReadLine());

public class Ejemplo_02_02_01_01a


{
public static void Main()
{
int numero;

using System;

// Ejemplo_02_02_01_01a.cs
// La orden "while": mientras...
// Introduccin a C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

(2.1.9.5) Repite el ejercicio 2.1.9.2, empleando "if" en lugar de "switch" (pista: como

(2.1.9.4) Repite el ejercicio 2.1.9.1, empleando "if" en lugar de "switch".

trata de una vocal, una cifra numrica o una consonante, usando "switch".

(2.1.9.3) Crea un programa que lea una letra tecleada por el usuario y diga si se

carcter, usando "switch" (pista: habr que usar un dato de tipo "char").

trata de un signo de puntuacin (. , ; :), una cifra numrica (del 0 al 9) o algn otro

(2.1.9.2) Crea un programa que lea una letra tecleada por el usuario y diga si se

programa escribir "uno").

nombre de ese nmero, usando "switch" (por ejemplo, si introduce "1", el

(2.1.9.1) Crea un programa que pida un nmero del 1 al 5 al usuario, y escriba el

Introduccin a la programacin con C#, por Nacho Cabanes

habitual), deberemos encerrarlas entre llaves.

do
sentencia;
;
while (condicin));

comienza la parte repetitiva se indica con la orden "do", as:

Revisin 0.99zz Pgina 65

zona repetitiva (se podra traducir como "repetirmientras"). El punto en que

se comprueba al final, de modo que siempre se dar al menos una pasada por la

Este es el otro formato que puede tener la orden "while": en este caso, la condicin

2.2.2. do ... while

usuario tres oportunidades para adivinar un nmero del 1 al 10.

(2.2.1.2.4) Crea el diagrama de flujo y la versin en C# de un programa que d al

positivo (pista: se puede hacer dividiendo varias veces entre 10).

(2.2.1.2.3) Crea un programa calcule cuantas cifras tiene un nmero entero

10 (descendiendo), usando "while".

(2.2.1.2.2) Crea un programa que escriba en pantalla los nmeros pares del 26 al

usando "while".

(2.2.1.2.1) Crea un programa que escriba en pantalla los nmeros del 1 al 10,

Ejercicios propuestos:

Console.WriteLine("Aceptada.");

}
while (clave != valida);

if (clave != valida)
Console.WriteLine("No vlida!");

public class Ejemplo_02_02_02b


{
public static void Main()
{
string valida = "secreto";

using System;

// Ejemplo_02_02_02b.cs
// La orden "do..while" (2)
// Introduccin a C#, por Nacho Cabanes

usar "string" e indicar su valor entre comillas dobles:

Revisin 0.99zz Pgina 66

un texto en vez de un nmero, los cambios al programa son mnimos, basta con

Como veremos con detalle un poco ms adelante, si preferimos que la clave sea

correcta, el ordenador escribe "Aceptada" y termina el programa.

Finalmente, cuando tecleamos la clave

Mientras que la respuesta que demos no sea la


correcta, se nos vuelve a preguntar.

la clave al menos una vez.

En este caso, se comprueba la condicin al final, de modo que se nos preguntar

public class Ejemplo_02_02_02a


{
public static void Main()
{
int valida = 711;
int clave;

public class Ejemplo_02_02_01_02a


{
public static void Main()
{
int n = 1;

using System;

using System;

Console.Write("Introduzca su clave numrica: ");


clave = Convert.ToInt32(Console.ReadLine());

// Ejemplo_02_02_02a.cs
// La orden "do..while" (repetir..mientras)
// Introduccin a C#, por Nacho Cabanes

// Ejemplo_02_02_01_02a.cs
// Contar con "while"
// Introduccin a C#, por Nacho Cabanes

do
{

de acceso y no nos deja entrar hasta que tecleemos la clave correcta:

5, as:

while (n < 6)
{
Console.WriteLine(n);
n = n + 1;
}

Como ejemplo, vamos a ver cmo sera el tpico programa que nos pide una clave

1, que aumentara una unidad en cada repeticin y se repetira hasta llegar al valor

ejemplo, si queremos contar del 1 al 5, usaramos una variable que empezase en

Al igual que en el caso anterior, si queremos que se repitan varias rdenes (es lo

Ahora que sabemos "repetir" cosas, podemos utilizarlo tambin para contar. Por

Introduccin a la programacin con C#, por Nacho Cabanes

2.2.1.2. Contadores usando un bucle "while"

Introduccin a la programacin con C#, por Nacho Cabanes

Console.WriteLine("Aceptada.");

"i=i+1":

Revisin 0.99zz Pgina 67

inicial sera "i=1", la condicin de repeticin sera "i<=10" y el incremento sera

letra "i" como contador cuando se trata de tareas muy sencillas, as que el valor

condicin de repeticin, y el incremento sera de 1 en 1. Es muy habitual usar la

As, para contar del 1 al 10, tendramos "1" como valor inicial, "<=10" como

for (valorInicial;
; CondicinRepeticin;; Incremento)
)
Sentencia;;

se repitan un cierto nmero de veces. El formato de "for" es

sta es la orden que usaremos habitualmente para crear partes del programa que

2.2.3. for

contrasea "Peter".

no le permita seguir hasta que introduzca como nombre "Pedro" y como

(2.2.2.5) Crea un programa que pida al usuario su identificador y su contrasea, y

identificador "1234" y como contrasea "1111".

(ambos numricos), y no le permita seguir hasta que introduzca como

(2.2.2.4) Crea un programa que pida al usuario su identificador y su contrasea

(descendiendo), usando "do..while".

(2.2.2.3) Crea un programa que escriba en pantalla los nmeros pares del 26 al 10

usando "do..while".

(2.2.2.2) Crea un programa que escriba en pantalla los nmeros del 1 al 10,

nmero negativo o cero).

calculando y mostrando la suma de todos ellos (terminar cuando se teclea un

(2.2.2.1) Crear un programa que pida nmeros positivos al usuario, y vaya

Ejercicios propuestos:

if (clave != valida)
Console.WriteLine("No vlida!");

Console.Write("Introduzca su clave: ");


clave = Console.ReadLine();

}
while (clave != valida);

do
{

string clave;
;

Introduccin a la programacin con C#, por Nacho Cabanes

puede abreviar i--).


Revisin 0.99zz Pgina 68

(pista: en cada pasada habr que descontar 1, por ejemplo haciendo i=i-1, que se

(2.2.3.6) Crea un programa que muestre los nmeros del 15 al 5, descendiendo

el doble del valor que hace de contador).

10 12 14 16 (pista: en cada pasada habr que aumentar de 2 en 2, o bien mostrar

(2.2.3.5) Crea un programa que muestre los primeros ocho nmeros pares: 2 4 6 8

(2.2.3.4) Crea un programa que muestre la tabla de multiplicar del 9.

incluidos) que sean divisibles entre 7 y a la vez entre 3.

(2.2.3.1.3) Crea un programa que muestre los nmeros del 100 al 200 (ambos

de la divisin entre 3 resulta 0).

sean mltiplos de 3 (pista: habr que recorrer todos esos nmeros y ver si el resto

(2.2.3.2) Crea un programa que escriba en pantalla los nmeros del 1 al 50 que

incluidos.

(2.2.3.1) Crea un programa que muestre los nmeros del 10 al 20, ambos

Ejercicios propuestos:

for (contador=1; contador<=10; contador++)


Console.Write("{0} ", contador);

public class Ejemplo_02_02_03a


{
public static void Main()
{
int contador;

using System;

// Ejemplo_02_02_03a.cs
// Uso bsico de "for"
// Introduccin a C#, por Nacho Cabanes

un programa que escribiera los nmeros del 1 al 10 podra ser:

En general, ser preferible usar nombres de variable ms descriptivos que "i". As,

for (i=1; i<=10; i++)


...

modo que la forma habitual de crear el contador anterior sera

la forma abreviada "i++", como veremos con ms detalle en el prximo tema, de

La orden para incrementar el valor de una variable ("i = i+1") se puede escribir de

for (i=1; i<=10; i=i+1)


...

Introduccin a la programacin con C#, por Nacho Cabanes

public class Ejemplo_02_02_05a


{
public static void Main()
{

using System;

// Ejemplo_02_02_05a.cs
// "for" anidados
// Introduccin a C#, por Nacho Cabanes

escribir las tablas de multiplicar del 1 al 5 con:

Revisin 0.99zz Pgina 69

Los bucles se pueden anidar (incluir uno dentro de otro), de modo que podramos

2.2.5. Bucles anidados

nmeros enteros positivos a partir del uno.

(2.2.4.2) Crea un programa que contenga un bucle sin fin que muestre los

pantalla, sin avanzar de lnea.

(2.2.4.1) Crea un programa que contenga un bucle sin fin que escriba "Hola " en

Ejercicios propuestos:

while (1 == 1)

indica una condicin que siempre vaya a ser cierta, como sta:

Tambin se puede crear un bucle sin fin usando "while" y usando "do..while", si se

for ( ; ; )

nunca ("bucle sin fin") sera la siguiente orden:

Un caso todava ms exagerado de algo a lo que se entra y de lo que no se sale

que siga al "for". El programa no termina nunca. Se trata de un "bucle sin fin".

condicin de salida: nos quedamos encerrados dando vueltas dentro de la orden

la variable "contador" no se incrementa nunca, por lo que nunca se cumplir la

for (contador=1; contador<=10; )

Por eso, si escribimos la siguiente lnea:

comprobar si todava se cumple la condicin de repeticin.

orden que se ejecuta cuando se termine la "Sentencia" y antes de volver a

Si queremos que se hagan varias cosas, basta definirlas como un

Console.WriteLine();

Revisin 0.99zz Pgina 70

for (tabla=1; tabla<=5; tabla++)


{
for (numero=1; numero<=10; numero++)
Console.WriteLine("{0} por {1} es {2}", tabla, numero,
tabla*numero);

public class Ejemplo_02_02_06a


{
public static void Main()
{
int tabla, numero;

using System;

// Ejemplo_02_02_06a.cs
// "for" anidados (2)
// Introduccin a C#, por Nacho Cabanes

entre tabla y tabla, sera:

queremos mejorar el ejemplo anterior haciendo que deje una lnea en blanco

bloque (una sentencia compuesta) encerrndolas entre llaves. Por ejemplo, si

sentencia.

En los ltimos ejemplos que hemos visto, despus de "for" haba una nica

2.2.6. Repetir sentencias compuestas

entre 7.

incluidos) diga si son divisibles entre 5, si son divisibles entre 6 y si son divisibles

(2.2.5.3) Crea un programa que, para los nmeros entre el 10 y el 20 (ambos

lnea, usando "while": 12345123451234512345.

(2.2.5.2) Crea un programa escriba 4 veces los nmeros del 1 al 5, en una misma

lnea, usando "for": 12345123451234512345.

(2.2.5.1) Crea un programa escriba 4 veces los nmeros del 1 al 5, en una misma

Ejercicios propuestos:

resultado que se obtiene al multiplicar por los nmeros del 1 al 10).

(Es decir: tenemos varias tablas, del 1 al 5, y para cada tabla queremos ver el

for (tabla=1; tabla<=5; tabla++)


for (numero=1; numero<=10; numero++)
Console.WriteLine("{0} por {1} es {2}", tabla, numero,
tabla*numero);

Realmente, en un "for", la parte que hemos llamado "Incremento" no tiene por qu

incrementar la variable, aunque se es su uso ms habitual. Es simplemente una

int tabla,
, numero;

Introduccin a la programacin con C#, por Nacho Cabanes

2.2.4. Bucles sin fin

Introduccin a la programacin con C#, por Nacho Cabanes

using System;

// Ejemplo_02_02_07b.cs
// "for" que descuenta
// Introduccin a C#, por Nacho Cabanes

"a" de la siguiente manera:

Revisin 0.99zz Pgina 71

"for" y en la parte que lo incrementa. As, podramos escribir las letras de la "z" a la

en dos, o como nos interese, basta indicarlo en la condicin de finalizacin del

Como ya hemos comentado, si queremos contar de forma decreciente, o de dos

uno.

En este caso, empezamos en la "a" y terminamos en la "z", aumentando de uno en

for (letra='a'; letra<='z'; letra++)


Console.Write("{0} ", letra);

public class Ejemplo_02_02_07a


{
public static void Main()
{
char letra;

using System;

// Ejemplo_02_02_07a.cs
// "for" que usa "char"
// Introduccin a C#, por Nacho Cabanes

detallan entre comillas simples, as:

usar letras, si el contador lo declaramos como "char" y los valores inicial y final se

Para "contar" no necesariamente hay que usar nmeros. Por ejemplo, podemos

2.2.7. Contar con letras

****

****

****

(por ejemplo, 3) y escriba un rectngulo formado por esa cantidad de asteriscos:

(2.2.6.2) Crea un programa que pida al usuario el ancho (por ejemplo, 4) y el alto

estar formada por los nmeros del 1 al 5.

(2.2.6.1) Crea un programa que escriba 4 lneas de texto, cada una de las cuales

Ejercicios propuestos:

Introduccin a la programacin con C#, por Nacho Cabanes

for (letra='z'; letra>='a'; letra--)


Console.Write("{0} ", letra);

Revisin 0.99zz Pgina 72

// Y ahora con "while"... pero no funcionar correctamente


while (n<=10)
{
Console.WriteLine("{0} x 3 = {1}", n, n*3);
n++;

public class Ejemplo_02_02_08a


{
public static void Main()
{
int n = 1;
// Vamos a mostrar la tabla de multiplicar del 3 con "for"
for (n=1; n<=10; n++)
Console.WriteLine("{0} x 3 = {1}", n, n*3);

using System;

// Ejemplo_02_02_08a.cs
// Reutilizacion incorrecta de la variable de un "for"
// Introduccin a C#, por Nacho Cabanes

ya no es un valor aceptable para entrar al bloque "while":

hemos vuelto a inicializar la variable "n", as que ya est por encima del valor 10 y

dos veces la tabla de multiplicar del 3, pero el "while" no muestra nada, porque no

Por ejemplo, el siguiente fuente compila correctamente y puede parecer mostrar

for (int i=1; i<=10; i++) ...

volver a darles un valor inicial:

trabajar, porque ayuda a evitar un fallo frecuente: reutilizar variables pero olvidar

dejar de estar definida cuando el "for" acabe. Es una forma recomendable de

Se puede incluso declarar una nueva variable en el interior de "for", y esa variable

2.2.8. Declarar variables en un "for"

N (mayscula), en la misma lnea.

(2.2.7.2) Crea un programa que muestre 5 veces las letras de la L (mayscula) a la

(mayscula, descendiendo).

(2.2.7.1) Crea un programa que muestre las letras de la Z (mayscula) a la A

Ejercicios propuestos:

public class Ejemplo_02_02_07b


{
public static void Main()
{
char letra;

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 73

inicialmente esperemos repetir slo una una orden:


Revisin 0.99zz Pgina 74

Por eso, una alternativa recomendable es incluir siempre las llaves, aunque

public class Ejemplo_02_02_09a


{
public static void Main()
{
for (int tabla=1; tabla<=5; tabla++)
for (int numero=1; numero<=10; numero++)
Console.WriteLine("{0} por {1} es {2}", tabla, numero,
tabla*numero);
Console.WriteLine();
}
}

public class Ejemplo_02_02_08c


{
public static void Main()
{
for (int tabla=1; tabla<=5; tabla++)
{
for (int numero=1; numero<=10; numero++)
Console.WriteLine("{0} por {1} es {2}", tabla, numero,
tabla*numero);

Console.WriteLine();

using System;

using System;

// Ejemplo_02_02_09a.cs
// "for" anidados de forma incorrecta, sin llaves
// Introduccin a C#, por Nacho Cabanes

terminar el programa:

siguiente, sino que slo se escribir una lnea en blanco al final, justo antes de

repite, y no se dejar ningn espacio en blanco entre una tabla de multiplicar y la

tabulada ms a la derecha, no forma parte de ningn "for", de modo que no se

detenimiento, veremos que la orden "Console.WriteLine" del final, aunque est

Por ejemplo, el siguiente fuente puede parecer correcto, pero si lo miramos con

incluir siempre las llaves, aunque esperemos repetir slo una una orden.

repetitiva y olvidar las llaves. llaves. Por eso, una alternativa recomendable es

repetir inicialmente una nica orden, aadir despus una segunda orden

que lo mismo ocurre con "while", "do-while" e "if". Pero un error frecuente es

una nica sentencia, sino cuando se repite un bloque de dos o ms sentencias, y

Sabemos que las "llaves" no son necesarias cuando una orden "for" va a repetir

2.2.9. Las llaves son recomendables

(declaradas en el "for") para el bloque repetitivo.

datos que pidas al usuario, y las variables "filaActual" y "columnaActual"

como en el ejercicio 2.2.6.2. Debers usar las variables "ancho" y "alto" para los

(por ejemplo, 3) y escriba un rectngulo formado por esa cantidad de asteriscos,

(2.2.8.2) Crea un programa que pida al usuario el ancho (por ejemplo, 4) y el alto

"linea" y "numero", y ambas deben estar declaradas en el "for".

estar formada por los nmeros del 1 al 7. Debes usar dos variables llamadas

(2.2.8.1) Crea un programa que escriba 6 lneas de texto, cada una de las cuales

Ejercicios propuestos:

Introduccin a la programacin con C#, por Nacho Cabanes

// Ejemplo_02_02_08c.cs
// "for" anidados, variables en "for"
// Introduccin a C#, por Nacho Cabanes

forma ms segura as:

el fuente 2.2.6a, que mostraba varias tablas de multiplicar, se podra reescribir de

Esta idea sea puede aplicar a cualquier fuente que contenga un "for". Por ejemplo,

// Y ahora con "while"... pero no compila


while (n<=10)
{
Console.WriteLine("{0} x 3 = {1}", n, n*3);
n++;
}

public class Ejemplo_02_02_08b


{
public static void Main()
{
// Vamos a mostrar la tabla de multiplicar del 3 con "for"
for (int n=1; n<=10; n++)
Console.WriteLine("{0} x 3 = {1}", n, n*3);

using System;

// Ejemplo_02_02_08b.cs
// Intento de reutilizacion incorrecta de la variable
// de un "for": no compila
// Introduccin a C#, por Nacho Cabanes

hace que el error de diseo sea evidente:

Si declaramos la variable dentro del "for", la zona de "while" no compilara, lo que

Introduccin a la programacin con C#, por Nacho Cabanes

Console.WriteLine();

Console.Write("{0} ", contador);

public class Ejemplo_02_02_10a


{
public static void Main()
{
for (int contador=1; contador<=10; contador++)
{
if (contador==5)
break;

using System;

// Ejemplo_02_02_10a.cs
// "for" interrumpido con "break"
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 75

public class Ejemplo_02_02_10c


{
public static void Main()
{

using System;

// Ejemplo_02_02_10c.cs
// alternativa a un "for" interrumpido con "break"
// Introduccin a C#, por Nacho Cabanes

O reescribirlo de esta otra (preferible):

Console.Write("{0} ", contador);

"break":

Podemos salir de un bucle antes de tiempo si lo interrumpimos con la orden

2.2.10. Interrumpir un bucle: break

slo incluyan una sentencia.

divisores comunes. Debes usar llaves en todas las estructuras de control, aunque

public class Ejemplo_02_02_10b


{
public static void Main()
{
for (int contador=105; contador<=120; contador++)
{
if (contador % 13 == 0)
break;

using System;

// Ejemplo_02_02_10b.cs
// "for" interrumpido con "break" (2)
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 76

13, que no se mostrar. Lo podramos hacer de esta forma (poco correcta):

ser mostrar los nmeros del 105 al 120 hasta encontrar uno que sea mltiplo de

la condicin fuera "contador < 5". Un ejemplo ligeramente ms complejo podra

reescribir la condicin del bucle de otra forma. En el ejemplo anterior, bastara que

que se interrumpe por otros criterios. Como norma general, es preferible

difciles de leer, en los que no se cumple la condicin de repeticin del bucle, sino

Es una orden que se debe tratar de evitar, porque puede conducir a programas

valor 10).

(en cuanto se llega al valor 5, se interrumpe el "for", por lo que no se alcanza el

1 2 3 4

El resultado de este programa es:

Introduccin a la programacin con C#, por Nacho Cabanes

(2.2.9.2) Crea un programa que pida al usuario dos nmeros y escriba sus

control, aunque slo incluyan una sentencia.

de 9 que haya entre 1 ese nmero. Debes usar llaves en todas las estructuras de

(2.2.9.1) Crea un programa que pida un nmero al usuario y escriba los mltiplos

Ejercicios propuestos:

public class Ejemplo_02_02_09b


{
public static void Main()
{
for (int tabla=1; tabla<=5; tabla++)
{
for (int numero=1; numero<=10; numero++)
{
Console.WriteLine("{0} por {1} es {2}", tabla, numero,
tabla*numero);
}

using System;

// Ejemplo_02_02_09b.cs
// "for" anidados, variables en "for", llaves "redundantes"
// Introduccin a C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

1 2 3 4 6 7 8 9 10

El resultado de este programa es:

Console.Write("{0} ", contador);

continue;

if (contador==5)

public class Ejemplo_02_02_11a


{
public static void Main()
{
for (int contador=1; contador<=10; contador++)
{

using System;

// Ejemplo_02_02_11a.cs
// "for" interrumpido con "continue"
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 77

Podemos saltar alguna repeticin de un bucle con la orden "continue":

2.2.11. Forzar la siguiente iteracin: continue

(2.2.11.1) Crea un programa que escriba los nmeros del 20 al 10, descendiendo,

int n=1;

Console.WriteLine();

public class Ejemplo_02_02_12a


{
public static void Main()
{
for (int contador=1; contador<=10; contador++)
{
Console.Write("{0} ", contador);
}

using System;

// Ejemplo_02_02_12a.cs
// "for" y "while" equivalente
// Introduccin a C#, por Nacho Cabanes

alternativa como un "while", como en este ejemplo:

Revisin 0.99zz Pgina 78

compactado, de modo que casi cualquier "for" se puede escribir de forma

En la gran mayora de condiciones, un bucle "for" equivale a un "while"

2.2.12. Equivalencia entre "for" y "while"

los que sean mltiplos de 10, usando "continue".

(2.2.11.2) Crea un programa que escriba los nmeros pares del 2 al 106, excepto

excepto el 13, usando "continue".

Ejercicios propuestos:

encuentres un nmero que sea mltiplo de ambos, interrumpes la bsqueda).

public class Ejemplo_02_02_11b


{
public static void Main()
{
for (int contador=1; contador<=10; contador++)
{
if (contador != 5)
Console.Write("{0} ", contador);
}
}
}

using System;

// Ejemplo_02_02_11b.cs
// Alternativa a "for" interrumpido con "continue"
// Introduccin a C#, por Nacho Cabanes

un "if" que escriba los valores que no sean 5, as:

En l podemos observar que no aparece el valor 5. Se podra haber usado tambin

Introduccin a la programacin con C#, por Nacho Cabanes

todos los nmeros a partir del mayor de ambos, de forma creciente; cuando

comn mltiplo (pista: una solucin lenta pero sencilla es probar con un "for"

(2.2.10.2) Crea un programa que pida al usuario dos nmeros y escriba su mnimo

encuentres un nmero que sea divisor de ambos, interrumpes la bsqueda).

los nmeros descendiendo a partir del menor de ambos, hasta llegar a 1; cuando

comn divisor (pista: una solucin lenta pero sencilla es probar con un "for" todos

(2.2.10.1) Crea un programa que pida al usuario dos nmeros y escriba su mximo

Ejercicios propuestos:

(S, en la mayora de los casos, un "for" se puede convertir en un "while"; veremos


ms detalles dentro de muy poco).

while ( (contador<=120) && (contador % 13 != 0) )


{
Console.Write("{0} ", contador);
contador++;
}

int contador=
=105;

Introduccin a la programacin con C#, por Nacho Cabanes

escribirlos usando "while".


Revisin 0.99zz Pgina 79

por un espacio, sin avanzar de lnea, usando "for". En la siguiente lnea, vuelve a

(2.2.12.1) Crea un programa que escriba los nmeros del 100 al 200, separados

Ejercicios propuestos:

llega a pasar del 5.

no se escriba, pero que tampoco se incremente la variable, de modo que nunca se

4, porque cuando se llega al nmero 5, la orden "continue" hace que dicho valor

provoca un bucle sin fin y el programa se queda "colgado" tras escribir el nmero

En este caso, el "for" muestra todos los valores menos el 5, pero en el "while" se

int n=1;
while (n<=10)
{
if (n == 5)
continue;
Console.Write("{0} ", n);
n++;
}

Console.WriteLine();

public class Ejemplo_02_02_12b


{
public static void Main()
{
for (int contador=1; contador<=10; contador++)
{
if (contador == 5)
continue;
Console.Write("{0} ", contador);
}

using System;

// Ejemplo_02_02_12b.cs
// "for" y "while" equivalente... con "continue"
// Introduccin a C#, por Nacho Cabanes

"break", pero no en caso de usar un "continue", como muestra este ejemplo:

Incluso se comportaran igual si no se avanza de uno en uno, o se interrumpe con

while (n<=10)
{
Console.Write("{0} ", n);
n++;
}

Introduccin a la programacin con C#, por Nacho Cabanes

"i", luego nunca se llegar a cumplir la condicin de salida.


Revisin 0.99zz Pgina 80

Respuesta: escribe "1" continuamente, porque no aumentamos el valor de

for (i=1; i<4; ) Console.Write("{0} ",i);

Qu escribira en pantalla este fragmento de cdigo?

ya tiene el valor 5.

modo que repite cuatro veces una orden vaca, y cuando termina el "for", "i"

Respuesta: escribe un 5, porque hay un punto y coma despus del "for", de

for (i=1; i<=4; i++); Console.Write("{0} ",i);

Qu escribira en pantalla este fragmento de cdigo?

principio.

Respuesta: no escribira nada, porque la condicin es falsa desde el

for (i=1; i>4; i++) Console.Write("{0} ",i);

Qu escribira en pantalla este fragmento de cdigo?

menor que 4).

Respuesta: los nmeros del 1 al 3 (se empieza en 1 y se repite mientras sea

for (i=1; i<4; i++) Console.Write("{0} ",i);

Qu escribira en pantalla este fragmento de cdigo?

problemas:

ejercicios resueltos, que te ayudarn a "entrenar la vista" para localizar ese tipo de

que el programa se comporte de forma errnea. Por eso, aqu tienes varios

un "punto" y coma tras una orden "for" o "while" puede hacer que nada se repita y

Existen varios errores frecuentes en el manejo de los bucles. Por ejemplo, incluir

2.2.13. Ejercicios resueltos sobre bucles

descendiendo, excepto el 14, primero con "for" y luego con "while".

(2.2.12.2) Crea un programa que escriba los nmeros pares del 20 al 10,

Introduccin a la programacin con C#, por Nacho Cabanes

for ( i = 0 ; i<= 4 ; i++)


if ( i == 2 ) continue ;
Console.Write("{0} ",i);

Qu escribira en pantalla este fragmento de cdigo?

"continue" nunca se llega a dar.

Revisin 0.99zz Pgina 81

Respuesta: escribe los nmeros del 0 al 4, porque la condicin del

for ( i = 0 ; i <= 4 ; i++) {


if ( i == 10 ) continue ;
Console.Write("{0} ",i);
}

Qu escribira en pantalla este fragmento de cdigo?

Respuesta: escribe los nmeros 0 y 1 (interrumpe en el 2).

for ( i = 0 ; i <= 4 ; i++) {


if ( i == 2 ) break ;
Console.Write("{0} ",i);
}

Qu escribira en pantalla este fragmento de cdigo?

Respuesta: escribe los nmeros del 0 al 4, excepto el 2.

for ( i = 0 ; i <= 4 ; i++) {


if ( i == 2 ) continue ;
Console.Write("{0} ",i);
}

Qu escribira en pantalla este fragmento de cdigo?

uno y aumentando una unidad en cada pasada, pero sin terminar.

Respuesta: escribe nmeros crecientes continuamente, comenzando en

for (i=1; ; i++) Console.Write("{0} ",i);

Qu escribira en pantalla este fragmento de cdigo?

Introduccin a la programacin con C#, por Nacho Cabanes

Pero en casos concretos

salida:
Console.Write("Fin del programa");

Revisin 0.99zz Pgina 82

for (i=0; i<=5; i++)


for (j=0; j<=20; j=j+2)
{
if ((i==1) && (j>=7))
goto salida;
Console.WriteLine("i vale {0} y j vale {1}.", i, j);
}

public class Ejemplo_02_03a


{
public static void Main()
{
int i, j;

using System;

// Ejemplo_02_03a.cs
// "for" y "goto"
// Introduccin a C#, por Nacho Cabanes

como en el siguiente ejemplo:

donde:

y la posicin de salto se indica con su nombre seguido de dos puntos (:)

goto donde;

El formato de "goto" es

preferible replantear las condiciones de forma ms natural, y no utilizar "goto".

slo saldra del "for" ms interno). Al igual que ocurra con la orden "break", ser

dentro de otro "for" que a su vez est dentro de otro "for": en este caso, "break"

puede ser muy til, por ejemplo, para salir de un bucle muy anidado (un "for"

programas llenos de saltos, muy difciles de seguir.

Su uso indisciplinado est muy mal visto, porque puede ayudar a hacer

El lenguaje C# tambin permite la orden "goto", para hacer saltos incondicionales.

2.3. Saltar a otro punto del programa: goto

la orden "if".

Respuesta: escribe 5, porque no hay llaves tras el "for", luego slo se repite

Introduccin a la programacin con C#, por Nacho Cabanes

0.
2.
4.
6.
8.
10.
12.
14.
16.
18.
20.
0.
2.
4.
6.

condicin):

Revisin 0.99zz Pgina 83

repita (una flecha que vuelve hacia atrs, al punto en el que se comprobaba la

Por su parte, un bucle "while" se vera como una condicin que hace que algo se

condiciones encadenadas.

forma clara de representar una orden "switch", que equivaldra a varias

lenguaje C# (y de muchos otros lenguajes actuales). Por ejemplo, no existe una

tipo de diagramas es antiguo, no tiene en cuenta todas las posibilidades del

paso a C# (o a casi cualquier otro lenguaje de programacin es sencillo). Pero este

para plantear lo que un programa debe hacer. Si entendemos esta herramienta, el

Cuando comenzamos el tema, vimos cmo ayudarnos de los diagramas de flujo

2.4. Ms sobre diagramas de flujo. Diagramas de Chapin

(2.3.1) Crea un programa que escriba los nmeros del 1 al 10, separados por un
espacio, sin avanzar de lnea. No puedes usar "for", ni "while", ni "do..while", slo
"if" y "goto".

Ejercicios propuestos:

Vemos que cuando i=1 y j>=7, se sale de los dos "for".

i vale 0 y j vale
i vale 0 y j vale
i vale 0 y j vale
i vale 0 y j vale
i vale 0 y j vale
i vale 0 y j vale
i vale 0 y j vale
i vale 0 y j vale
i vale 0 y j vale
i vale 0 y j vale
i vale 0 y j vale
i vale 1 y j vale
i vale 1 y j vale
i vale 1 y j vale
i vale 1 y j vale
Fin del programa

El resultado de este programa es:

Introduccin a la programacin con C#, por Nacho Cabanes

Mostrar primer num+segundo num

Pedir segundo nmero

Pedir primer nmero

se representa cada orden dentro de una caja:

Revisin 0.99zz Pgina 84

cmodas. Slo comentaremos una: los diagramas de Chapin. En estos diagramas,

Aun as, existen otras notaciones ms modernas y que pueden resultar ms

repite:

Y un "do...while" se representara como una condicin al final de un bloque que se

Introduccin a la programacin con C#, por Nacho Cabanes

mayor"

Decir "n1 es

mayor"

Mientras clave z correcta

Leer clave de acceso

Escribir "Teclee su clave"

// Ejemplo_02_05a.cs
// Primer ejemplo de "foreach"
// Introduccin a C#, por Nacho Cabanes

obtener las letras una a una con "foreach" as:

Revisin 0.99zz Pgina 85

todava con muy poco detalle) es la cadena de texto, "string", de la que podramos

datos de uno en uno. De momento, el nico dato compuesto que hemos visto (y

de datos ms complejas, que es en las que la nos resultar til para extraer los

traducira "para cada"). La veremos ms adelante, cuando manejemos estructuras

Nos queda por ver otra orden que permite hacer cosas repetitivas: "foreach" (se

2.5. foreach

En ambos casos, no existe una grfica "clara" para los "for".

Cerrar fichero

Revisin 0.99zz Pgina 86

como producto de su factores primos. Por ejemplo, 60 = 2 2 3 5

(2.6.2) Crear un programa que descomponga un nmero (que teclee el usuario)

pasada deber avisar de si se ha pasado o se ha quedado corto.

del 1 al 100 (prefijado en el programa) en un mximo de 6 intentos. En cada

(2.6.1) Crear un programa que d al usuario la oportunidad de adivinar un nmero

Ejercicios propuestos:

ser reemplazado por un "while", para que el programa resulte ms legible.

especial, es porque realmente no se trata de un contador, y en ese caso debera

Conceptualmente, si un "for" necesita un "break" para ser interrumpido en un caso

queremos que se repita (por ejemplo: 10 veces sera "for (i=1; i<=10; i++)").

"for" hace que sea especialmente til cuando sabemos exactamente cuantas veces

En cuanto a "for", es equivalente a un "while", pero la sintaxis habitual de la orden

menos una vez al usuario, o quiz ms veces, si la teclea correctamente).

De igual modo, "do...while" ser lo adecuado cuando debamos repetir al menos


una vez (por ejemplo, para pedir una clave de acceso, se le debe preguntar al

Leer dato

vaco, no habr datos que leer).

llegue a repetir nunca (por ejemplo: cuando leemos un fichero, si el fichero est

En general, nos interesar usar "while" cuando puede que la parte repetitiva no se

2.6. Recomendacin de uso para los distintos tipos de


bucle

frase que teclee el usuario, utilizando "foreach".

(2.5.1) Crea un programa que cuente cuantas veces aparece la letra 'a' en una

Ejercicios propuestos:

public class Ejemplo_02_05a


{
public static void Main()
{
Console.Write("Dime tu nombre: ");
string nombre = Console.ReadLine();
foreach(char letra in nombre)
{
Console.WriteLine(letra);
}
}
}

using System;

Introduccin a la programacin con C#, por Nacho Cabanes

Mostrar dato

Mientras haya datos en fichero

Abrir fichero

como si se comprueba al principio (while):

(do..while):

marca qu zona es la que se repite, tanto si la condicin se comprueba al final

Y las condiciones repetitivas se indican dejando una barra a la izquierda, que

no

Decir "n2 es

si

n1>n2?

Pedir nmero n2

Pedir nmero n1

Las condiciones se denotan dividiendo las cajas en dos:

Introduccin a la programacin con C#, por Nacho Cabanes

comprobando cada una de los posibles situaciones que pueden dar lugar a un

situaciones de error. Por eso, los lenguajes modernos, como C#, permiten una
alternativa: el manejo de "excepciones".

tringulo sera as:


****
***
**
*
(2.6.6) Crea un programa que "dibuje" un rectngulo hueco, cuyo borde sea una

fila (o columna) de asteriscos y cuyo interior est formado por espacios en blanco,

tamao 5, el cuadrado sera as:


11111
Revisin 0.99zz Pgina 87

con el tamao que indique el usuario, hasta un mximo de 9. Por ejemplo, si desea

(2.6.9) Crea un programa que "dibuje" un cuadrado formado por cifras sucesivas,

Precio? 1
Pagado? 100
Su cambio es de 99: 50 20 20 5 2 2

Precio? 44
Pagado? 100
Su cambio es de 56: 50 5 1

decimales. La ejecucin podra ser algo como:

cantidad ilimitada de monedas (o billetes) de 100, 50, 20, 10, 5, 2 y 1, y que no hay

monedas (o billetes) del mayor valor posible. Supondremos que tenemos una

desea 4 caracteres de alto, el tringulo sera as:


*
**
***
****
(2.6.8) Crea un programa que devuelva el cambio de una compra, utilizando

derecha, con la altura que indique el usuario. Por ejemplo, si el usuario dice que

altura 3, el rectngulo sera as:


****
* *
****
(2.6.7) Crea un programa que "dibuje" un tringulo creciente, alineado a la

con el ancho y el alto que indique el usuario. Por ejemplo, si desea anchura 4 y

La forma "clsica" del control de errores es usar instrucciones "if", que vayan

indique el usuario. Por ejemplo, si el usuario dice que desea 4 caracteres de alto, el

public static void Main()


{
int numero1, numero2, resultado;

public class Ejemplo_02_07a


{

using System;

// Ejemplo_02_07a.cs
// Excepciones (1)
// Introduccin a C#, por Nacho Cabanes

errores:

Revisin 0.99zz Pgina 88

con un primer ejemplo, que intente dividir dos nmeros, e intercepte los posibles

complejos, especialmente en el manejo de ficheros, pero podemos acercarnos

Lo veremos ms adelante con ms detalle, cuando nuestros programas sean ms

que queremos "interceptar" (catch), y lo que se debe hacer en ese caso.

En un primer bloque, indicaremos los pasos que queremos "intentar" (try).


A continuacin, detallaremos las posibles situaciones de error (excepciones)

x
x

Lo haremos dividiendo el fragmento de programa en dos bloques:

"convencional".

completar. Esto permite que el programa sea ms legible que la alternativa

ellos indicaremos qu hay que hacer en caso de que alguno no se consiga

La idea es la siguiente: "intentaremos" dar una serie de pasos, y al final de todos

por rdenes que no tienen que ver con el problema en s, sino con las posibles

difcil de leer, porque la lgica de la resolucin del problema se ve interrumpida

error, a medida que estas situaciones llegan. Esto tiende a hacer el programa ms

2.7. Una alternativa para el control errores: las


excepciones

22222
33333
44444
55555

Introduccin a la programacin con C#, por Nacho Cabanes

si desea anchura 4 y altura 3, el rectngulo sera as:


****
****
****
(2.6.5) Crea un programa que "dibuje" un tringulo decreciente, con la altura que

el ancho y el alto que indique el usuario, usando dos "for" anidados. Por ejemplo,

(2.6.4) Crea un programa que "dibuje" un rectngulo formado por asteriscos, con

multiplicaciones sucesivas.

(2.6.3) Crea un programa que calcule un nmero elevado a otro, usando

Introduccin a la programacin con C#, por Nacho Cabanes

ha afectado al programa, no necesitamos declarar ninguna variable de tipo

public class Ejemplo_02_07b


{
public static void Main()

using System;

Revisin 0.99zz Pgina 90

Lo mismo ocurrir si el ao de nacimiento no es un nmero vlido.

Si la edad que introduce no es un nmero vlido, mostrar un mensaje de aviso.

(2.7.1) Crea un programa que pregunte al usuario su edad y su ao de nacimiento.

Ejercicios propuestos:

// Ejemplo_02_07b.cs
// Excepciones (2)
// Introduccin a C#, por Nacho Cabanes

error que pueda surgir y que nosotros no hayamos contemplado. En cualquier

alternativa es la menos deseable, porque quiz pasemos por alto algn tipo de

qu errores obtenemos en pantalla al introducir un valor no vlido. Esta

demasiado grande). Otra alternativa ms peligrosa es "probar el programa" y ver

FormatException (no se ha podido convertir) y OverflowException (nmero

que podemos obtener en ese intento de conversin de texto a entero:

toint32" nos llevar a una pgina en la que podemos ver que hay dos excepciones

Network): si tecleamos en un buscador de Internet algo como "msdn convert

en la "referencia oficial" para programadores de C#, la MSDN (Microsoft Developer

Y cmo sabemos qu excepciones debemos interceptar? La mejor forma es mirar

"catch (FormatException e)".

Exception: nos basta con construcciones como "catch (FormatException)" en vez de

caso, volveremos a las excepciones ms adelante.

Revisin 0.99zz Pgina 89

resultado = numero1 / numero2;


Console.WriteLine("Su divisin es: {0}", resultado);

Console.WriteLine("Introduzca el segundo numero");


numero2 = Convert.ToInt32( Console.ReadLine() );

Console.WriteLine("Introduzca el primer numero");


numero1 = Convert.ToInt32( Console.ReadLine() );

catch (FormatException)
{
Console.WriteLine("No es un nmero vlido");
}
catch (DivideByZeroException)
{
Console.WriteLine("No se puede dividir entre cero");
}

try
{

int numero1, numero2, resultado;

Como se ve en este ejemplo, si no vamos a usar detalles adicionales del error que

Introduccin a la programacin con C#, por Nacho Cabanes

acciones, o al menos dar mensajes de error ms detallados, as:

sino uno por uno (con varias sentencias "catch"), para poder tomar distintas

Una alternativa ms elegante es no "atrapar" todos los posibles errores a la vez,

Introduzca el primer numero


3
Introduzca el segundo numero
0
Ha habido un error: Intento de dividir por cero.

Y si el segundo nmero es 0, se nos dira

Introduzca el primer numero


hola
Ha habido un error: La cadena de entrada no tiene el formato correcto.

respuesta

En este ejemplo, si escribimos un texto en vez de un nmero, obtendramos como

errorEncontrado.Message)

acceder a detalles como el mensaje correspondiente a ese tipo de excepcin:

(La variable "errorEncontrado" es de tipo "Exception", y nos sirve para poder

resultado = numero1 / numero2;


Console.WriteLine("Su divisin es: {0}", resultado);

Console.WriteLine("Introduzca el segundo numero");


numero2 = Convert.ToInt32( Console.ReadLine() );

Console.WriteLine("Introduzca el primer numero");


numero1 = Convert.ToInt32( Console.ReadLine() );

}
catch (Exception errorEncontrado)
{
Console.WriteLine("Ha habido un error: {0}",
errorEncontrado.Message);
}

try
{

Introduccin a la programacin con C#, por Nacho Cabanes

pero aun as le preguntar su ao de nacimiento.

Revisin 0.99zz Pgina 91

Si la edad que introduce no es un nmero vlido, mostrar un mensaje de aviso,

(2.7.2) Crea un programa que pregunte al usuario su edad y su ao de nacimiento.

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 92

ocupan en memoria y el rango de valores que nos permiten almacenar son:

Los tipos de datos enteros que podemos usar en C#, junto con el espacio que

3.1.1. Tipos de datos para nmeros enteros

decimales, pero eso lo dejamos para el siguiente apartado.

Siendo estrictos, si hablamos de valores monetarios, necesitaramos usar

manejar nmeros con ms de 9 cifras, as que un dato "int" se les quedara corto.

menos memoria. Tambin existe el caso contrario: un banco puede necesitar

que es de suponer que existir algn tipo de datos ms adecuado, que desperdicie

persona, no necesitamos usar nmeros negativos, y nos bastara con 3 cifras, as

Pero no es la nica opcin. Por ejemplo, si queremos guardar la edad de una

(Nota: si no sabes lo que es un byte, deberas mirar el Apndice 1 de este texto).

como negativos, y ocupa 4 bytes en memoria.

de tipo "int" puede guardar nmeros de hasta unas nueve cifras, tanto positivos

podemos emplear, as como su signo (positivo o negativo). Por ejemplo, un dato

importante que hemos esquivado hasta ahora es el tamao de los nmeros que

Empieza a ser el momento de refinar, de dar ms detalles. El primer "matiz"

valor no sabemos de antemano.

cmo usar variables para reservar espacio y as poder trabajar con datos cuyo

Hemos hablado de nmeros enteros, de cmo realizar operaciones sencillas y de

3.1. Tipo de datos entero

3. Tipos de datos bsicos

Introduccin a la programacin con C#, por Nacho Cabanes

sbyte

byte

short

ushort

int

uint

long

ulong
}

Revisin 0.99zz Pgina 93

signo), y para los de 8 bytes existen ToInt64 (con signo) y ToUInt64 (sin signo).

(con signo), para datos de 2 bytes tenemos ToInt16 (con signo) y ToUInt16 (sin

bytes). Para datos de tipo "byte" usaramos Convert.ToByte (sin signo) y ToSByte

servir Convert.ToInt32, porque no todos los datos son enteros de 32 bits (4

Si queremos obtener estos datos a partir de una cadena de texto, no siempre nos

3.1.2. Conversiones de cadena a entero

especialmente (como ya hemos visto) a la hora de controlar bucles: incrementar el

a++;
a--;

decremento):
es lo mismo que
es lo mismo que

a = a+1;
a = a-1;
Revisin 0.99zz Pgina 94

existe una notacin ms compacta para esta operacin, y para la opuesta (el

Pues bien, en C# (y en otros lenguajes que derivan de C, como C++, Java y PHP),

a = a + 1;

valor de una variable en una unidad:

tambin existe una operacin que es muy frecuente cuando se crean programas,

(3.1.1.1) Calcula el producto de 1.000.000 por 1.000.000, usando una variable


llamada "producto", de tipo "long". Prueba tambin a calcularlo usando una
variable de tipo "int".

Conocemos la forma de realizar las operaciones aritmticas ms habituales. Pero

3.1.3. Incremento y decremento

su resta y su producto.

(3.1.2.3) Pide al usuario dos nmeros enteros largos ("long") y muestra su suma,

pantalla.

multiplicacin, que se deber guardar en un "ushort", y muestra el resultado en

(3.1.2.2) Pide al usuario dos nmeros de dos cifras ("byte"), calcula su

aparentas 20 aos").

continuacin, le debers decir que no aparenta tantos aos (por ejemplo, "No

(3.1.2.1) Pregunta al usuario su edad, que se guardar en un "byte". A

Ejercicios propuestos:

byte edad = Convert.ToByte(ejemplo1);


ushort anyo = Convert.ToUInt16(ejemplo2);
long resultado = Convert.ToInt64(ejemplo3);
Console.WriteLine("Los datos son {0}, {1} y {2}",
edad, anyo, resultado);

public class Ejemplo_03_01_02a


{
public static void Main()
{
string ejemplo1 = "74";
string ejemplo2 = "2001";
string ejemplo3 = "10000000000";

using System;

// Ejemplo_03_01_02a.cs
// Conversiones para otros tipos de nmeros enteros
// Introduccin a C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

Ejercicios propuestos:

public class Ejemplo_03_01_01a


{
public static void Main()
{
byte edad = 74;
ushort anyo = 2001;
long resultado = 10000000000;
Console.WriteLine("Los datos son {0}, {1} y {2}",
edad, anyo, resultado);
}
}

using System;

// Ejemplo_03_01_01a.cs
// Tipos de nmeros enteros
// Introduccin a C#, por Nacho Cabanes

un "int".

edades sera "byte", que permite valores entre 0 y 255, y ocupa 3 bytes menos que

Como se puede observar en esta tabla, el tipo de dato ms razonable para guardar

0 a 18446744073709551615

9223372036854775807

-9223372036854775808 a

0 a 4294967295

-2147483648 a 2147483647

0 a 65535

-32768 a 32767

0 a 255

-128 a 127

Tamao (bytes) Rango de valores

Nombre

Introduccin a la programacin con C#, por Nacho Cabanes

Por tanto, al final tenemos que b=2 y a=3

b
b
b
b
b

;
;
;
;
;

es
es
es
es
es

lo
lo
lo
lo
lo

mismo
mismo
mismo
mismo
mismo

que
que
que
que
que

a
a
a
a
a

=
=
=
=
=

a+b;
a-b;
a*b;
a/b;
a%b;

tambin

podemos

distinguir

postdecremento

(a--)

ver si habas hallado la solucin correcta.


Revisin 0.99zz Pgina 95

b=b*5; a=a*2; Calclalo a mano y luego crea un programa que lo resuelva, para

(3.1.3.2) Cul sera el resultado de las siguientes operaciones? a=5; b=++a; c=a++;

programa.

valores esperas que se obtengan? Contrstalo con el resultado obtenido por el

15, -10, 2.147.483.647. Se deber incrementar el valor de estas variables. Qu

(3.1.3.1) Crea un programa que use tres variables x,y,z. Sus valores iniciales sern

Ejercicios propuestos:

predecremento (--a).

supuesto,

// Ejemplo_03_01_05a.cs
// Asignaciones mltiples
// Introduccin a C#, por Nacho Cabanes

a = b = c = 1;

es posible hacer asignaciones mltiples:

Revisin 0.99zz Pgina 96

Ya que estamos hablando de las asignaciones, es interesante comentar que en C#

3.1.5. Asignaciones mltiples

c=-3; c*=2; ++c; a*=b; Crea un programa que te lo muestre.

(3.1.4.2) Cul sera el resultado de las siguientes operaciones? a=5; b=a+2; b-=3;

resultado obtenido por el programa.

Por

formato abreviado. Qu valores esperas que se obtengan? Contrstalo con el

(preincremento), de modo que a=3 y b=3.

15, -10, 214. Debers incrementar el valor de estas variables en 12, usando el

(3.1.4.1) Crea un programa que use tres variables x,y,z. Sus valores iniciales sern

Ejercicios propuestos:

public class Ejemplo_03_01_04a


{
public static void Main()
{
int n = 10;
Console.WriteLine("n vale {0}", n);
n *= 2;
Console.WriteLine("Tras duplicarlo, vale {0}", n);
n /= 3;
Console.WriteLine("Tras dividirlo entre tres, vale {0}", n);
}
}

using System;

// Ejemplo_03_01_04a.cs
// Operaciones abreviadas
// Introduccin a C#, por Nacho Cabanes

All van
a +=
a -=
a *=
a /=
a %=

An hay ms. Tenemos incluso formas reducidas de escribir cosas como "a = a+5".

3.1.4. Operaciones abreviadas: +=

Introduccin a la programacin con C#, por Nacho Cabanes

y "a" vala 2, primero aumentamos "a" y luego los asignamos a "b"

b = ++a;

En cambio, si escribimos

(postincremento: se incrementa "a" tras asignar su valor).

aumentar el valor de "a".

As, si "a" vala 2, lo que esta instruccin hace es dar a "b" el valor de "a" y

b = a++;

posible hacer asignaciones como

vistazo: podemos distinguir entre "preincremento" y "postincremento". En C# es

Pero esto tiene algo ms de dificultad de la que puede parecer en un primer

public class Ejemplo_03_01_03a


{
public static void Main()
{
int n = 10;
Console.WriteLine("n vale {0}", n);
n++;
Console.WriteLine("Tras incrementar vale {0}", n);
n--;
n--;
Console.WriteLine("Tras decrementar dos veces, vale {0}", n);
}
}

using System;

// Ejemplo_03_01_03a.cs
// Incremento y decremento
// Introduccin a C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

2 entre 3 usando enteros


0
2 entre 3 usando reales
0,6666667

En la mayora de lenguajes de programacin, contamos con dos tamaos de


nmeros reales para elegir, segn si queremos guardar nmeros con mayor
cantidad de cifras o con menos. Para nmeros con pocas cifras significativas (un

13405000000 o como el 0,0000007349 pero no se guardara correctamente el

12,0000034, que se redondeara a un nmero cercano.

Revisin 0.99zz Pgina 97

significativas:
Revisin 0.99zz Pgina 98

reales, con mayor precisin todava, el tipo "decimal", que se acerca a las 30 cifras

precisin") tenemos el tipo "double". En C# existe un tercer tipo de nmeros

flotante. En C# corresponden al tipo de datos llamado "float".

// Ejemplo_03_02_01a.cs
// Nmeros reales (1: float)
// Introduccin a C#, por Nacho Cabanes

el tipo "float" y para nmeros que necesiten ms precisin (unas 15 cifras, "doble

Casi cualquier lenguaje de programacin actual va a emplear nmeros de coma

mximo de 7, lo que se conoce como "un dato real de simple precisin") usaremos

3.2.2. Simple y doble precisin

ejemplo, con 5 cifras significativas se podran almacenar nmeros como el

reales? a=5; a/=2; a+=1; a*=3; --a;

(3.2.1.2) Cul sera el resultado de las siguientes operaciones, usando nmeros

nmeros enteros y luego usando nmeros de coma flotante.

(3.2.1.1) Crea un programa que muestre el resultado de dividir 3 entre 4 usando

Ejercicios propuestos:

Vamos a dividir
El resultado es
Vamos a dividir
El resultado es

programa es:

Usando "float" s hemos podido dividir con decimales. El resultado de este

Console.WriteLine("Vamos a dividir 2 entre 3 usando reales");


divisionF = f1/f2;
Console.WriteLine("El resultado es {0}", divisionF);

float f1 = 2, f2 = 3;
float divisionF;

Console.WriteLine("Vamos a dividir 2 entre 3 usando enteros");


divisionI = i1/i2;
Console.WriteLine("El resultado es {0}", divisionI);

public class Ejemplo_03_02_01a


{
public static void Main()
{
int i1 = 2, i2 = 3;
float divisionI;

using System;

Introduccin a la programacin con C#, por Nacho Cabanes

lo que importa es el nmero de cifras significativas (a partir del ltimo 0). Por

Coma flotante: el nmero de decimales y de cifras enteras permitido es variable,

y el 1020 no se podra guardar (tiene ms de 3 cifras enteras).

5,678642 se guardara como 5,6786 (se perdera a partir de la cuarta cifra decimal)

003,7500), el nmero 970,4361 tambin se guardara sin problemas, pero el

y 4 cifras decimales, el nmero 3,75 se almacenara correctamente (como

nmero de cifras enteras tambin. Por ejemplo, con un formato de 3 cifras enteras

Coma fija: el nmero mximo de cifras decimales est fijado de antemano, y el

En el mundo de la informtica hay dos formas de trabajar con nmeros reales:

3.2.1. Coma fija y coma flotante

ms de un tipo de nmero real para elegir.

"reales" (con decimales). Al igual que ocurra con los nmeros enteros, tendremos

"int". Necesitamos otro tipo de datos que s est preparado para guardar nmeros

Cuando queremos almacenar datos con decimales, no nos sirve el tipo de datos

3.2. Tipo de datos real

public class Ejemplo_03_01_05a


{
public static void Main()
{
int a=5, b=2, c=-3;
Console.WriteLine("a={0}, b={1}, c={2}", a, b, c);
a = b = c = 4;
Console.WriteLine("Ahora a={0}, b={1}, c={2}", a, b, c);
a++; b--; c*=2;
Console.WriteLine("Y finalmente a={0}, b={1}, c={2}", a, b, c);
}
}

using System;

Introduccin a la programacin con C#, por Nacho Cabanes

32

float

3,41038

15-16

1,710308

5,010-324

64

double

28-29

7,91028

1,010-28

128

decimal

}
}

convertir cuando vayamos a realizar operaciones aritmticas. Ahora usaremos

Revisin 0.99zz Pgina 99

nmero, para indicar al compilar que debe ser tratado como un "float":

Hay un par de formas de solucionarlo. La ms sencilla es aadir el sufijo "f" al

// Ejemplo_03_02_03a.cs

de precisin extra (decimal):

Revisin 0.99zz Pgina 100

cuando sea un dato de simple precisin (float) y Convert.ToDecimal para un dato

Convert.ToDouble cuando se trate de un dato de doble precisin, Convert.ToSingle

Al igual que hacamos con los enteros, podemos leer como cadena de texto, y

perder precisin:

float pi = 3.14; // No vlido

3.2.3. Pedir nmeros reales al usuario

derecha es para l un dato "double" y el tipo de la variable es "float", as que se

(rea = pi * radio al cuadrado)

(3.2.2.2) Calcula el rea de un crculo, dado su radio, que ser un nmero entero

luego con nmeros de doble precisin.

nmeros enteros, luego usando nmeros de coma flotante de simple precisin y

(3.2.2.1) Crea un programa que muestre el resultado de dividir 13 entre 6 usando

Ejercicios propuestos:

Console.WriteLine("Introduce el radio");
radio = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("La longitud de la circunferencia es");
Console.WriteLine(2 * pi * radio);

public class Ejemplo_03_02_02b


{
public static void Main()
{
int radio;
float pi = 3.14f; // Atencin a la "f" del final

using System;

// Ejemplo_03_02_02a.cs
// Nmeros reales: valor inicial de un float
// Introduccin a C#, por Nacho Cabanes

valor ser 2 * PI * radio) podra ser:

(que ser un nmero entero) para mostrar la longitud de la circunferencia (cuyo

As, podemos crear un programa que pida al usuario el radio de una circunferencia

de muy poco.

Otra forma alternativa es forzar una "conversin de tipos", como veremos dentro

float pi = 3.14f; // Dato correcto

Introduccin a la programacin con C#, por Nacho Cabanes

compilador mostrar un mensaje de error diciendo que lo que aparece a la

pero no podremos dar un valor que contenga cifras decimales, porque el

float x = 2;

vlido darle un valor entero, como hemos hecho en el ejemplo anterior:

Si queremos dar un valor inicial a un dato "float", debemos llevar cuidado. Es

Vamos a dividir 2 entre 3


El resultado es 0,666666666666667

Ahora su resultado sera:

Console.WriteLine("Vamos a dividir 2 entre 3");


division = n1/n2;
Console.WriteLine("El resultado es {0}", division);

public class Ejemplo_03_02_02a


{
public static void Main()
{
double n1 = 2, n2 = 3;
double division;

using System;

// Ejemplo_03_02_02a.cs
// Nmeros reales (2: double)
// Introduccin a C#, por Nacho Cabanes

resultado ms preciso:

As, podramos plantear el ejemplo anterior con un "double" para obtener un

Cifras significativas 7

Valor ms grande

Valor ms pequeo -1,510-45

Tamao en bits

Introduccin a la programacin con C#, por Nacho Cabanes

Console.WriteLine("La suma de {0} y {1} es {2}",


primerNumero, segundoNumero, suma);

Revisin 0.99zz Pgina 101

dinero obtenido viene dado por la frmula del inters compuesto: Resultado = e

(3.2.3.4) Si se ingresan E euros en el banco a un cierto inters I durante N aos, el

Bx + C. Pista: la raz cuadrada de un nmero x se calcula con Math.Sqrt(x)

(3.2.3.3) Halla las soluciones de una ecuacin de segundo grado del tipo y = Ax2 +

por hora (pista: 1 milla = 1.609 metros).

y muestre la velocidad, en metros por segundo, en kilmetros por hora y en millas

tiempo necesario para recorrerla (como tres nmeros: horas, minutos, segundos),

(3.2.3.2) Crea un programa que pida al usuario a una distancia (en metros) y el

doble precisin (volumen = pi * radio al cubo * 4/3)

(3.2.3.1) Calcula el volumen de una esfera, dado su radio, que ser un nmero de

Ejercicios propuestos:

Introduce el primer nmero


23,6
Introduce el segundo nmero
34.2
La suma de 23,6 y 342 es 365,6

34.2 en la versin espaola de Windows 8 obtendremos como respuesta:

punto, que ser ignorado. Por ejemplo, ocurre si introducimos los datos 23,6 y

separar los decimales, considerar que la coma es el separador correcto y no el

operativo, de modo que si ste sabe que en nuestro pas se usa la "coma" para

cuando se pidan datos al usuario, parte del trabajo se le encarga al sistema

decimales usando un punto, como 123.456, al poner el ejecutable en marcha,

Cuidado al probar este programa: aunque en el fuente debemos escribir los

Console.WriteLine("Introduce el primer nmero");


primerNumero = Convert.ToSingle(Console.ReadLine());
Console.WriteLine("Introduce el segundo nmero");
segundoNumero = Convert.ToSingle(Console.ReadLine());
suma = primerNumero + segundoNumero;

public class Ejemplo_03_02_03a


{
public static void Main()
{
float primerNumero;
float segundoNumero;
float suma;

using System;

// Nmeros reales: pedir al usuario


// Introduccin a C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

Hacer un forzado de tipos, que es ms rpido pero no siempre es posible,

longitud = 2 * pi * radio;

Console.WriteLine("Introduce el radio");
radio = Convert.ToDouble(Console.ReadLine());

public class Ejemplo_03_02_04a


{
public static void Main()
{
double radio;
float pi = (float) 3.141592654;
double longitud;
float longitudSimplePrec;
int longitudEntera;

using System;

// Ejemplo_03_02_04a.cs
// Nmeros reales: typecast
// Introduccin a C#, por Nacho Cabanes

convertiremos a "float" y a "int" forzando el nuevo tipo de datos:

Revisin 0.99zz Pgina 102

circunferencia, de modo que su resultado sea un "double", que luego

Por ejemplo, podramos retocar el programa que calculaba la longitud de la

parntesis, as: x = (int) y;

ello, se precede el valor de la variable con el nuevo tipo de datos entre

slo cuando el tipo de origen y el de destino se parecen lo suficiente. Para

Usar Convert, como en x = Convert.ToInt32(y);

quedarnos con la parte entera de un nmero real), tenemos dos alternativas:

Cuando queremos convertir de un tipo de nmero a otro (por ejemplo, para

3.2.4. Conversin de tipos (typecast)

"double".

resultados hasta esa cantidad de trminos. Debes hacer todas las operacion con

indicar la cantidad de trminos a utilizar, y el programa mostrar todos los

expresin: pi/4 = 1/1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 + 1/13 ... El usuario deber

(3.2.3.7) Escribe un programa que calcule una aproximacin de PI mediante la

asterisco. La cantidad de espacios depender del valor obtenido para "y".

entre 1 y 10. Deber hacerlo dibujando varios espacios en pantalla y luego un

(3.2.3.6) Crea un programa que "dibuje" la grfica de y = (x-5)2 para valores de x

x2 - 1

(3.2.3.5) Crea un programa que muestre los primeros 20 valores de la funcin y =

aos al 3% de inters anual.

(1+ i)n Aplicarlo para calcular en cuanto se convierten 1.000 euros al cabo de 10

Introduccin a la programacin con C#, por Nacho Cabanes

Algunos de los cdigos de formato que se pueden usar son:


Revisin 0.99zz Pgina 103

formato numrico que queremos usar, por ejemplo: suma.ToString("0.00")

usando "ToString". A esta orden se le puede indicar un dato adicional, que es el

Una forma de conseguirlo es crear una cadena de texto a partir del nmero,

slo un decimal.

dos cifras decimales, o que una nota se muestre redondeada, sin decimales, o con

puede interesar que una cifra que corresponde a dinero se muestre siempre con

pantalla, para mostrar slo una cierta cantidad de decimales: por ejemplo, nos

En ms de una ocasin nos interesar afinar la apariencia de los nmeros en

3.2.5. Formatear nmeros

"double", pero mostrar el resultado como "float".

tantos trminos como indique el usuario. Debes hacer todas las operacion con

de PI mediante la expresin: pi/4 = 1/1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 + 1/13 (...) con

(3.2.4.2) Crea una nueva versin del un programa que calcula una aproximacin

se mostrar como "float"

introduzca el usuario. La raz se deber calcular como "double", pero el resultado

(3.2.4.1) Crea un programa que calcule la raz cuadrada del nmero que

Ejercicios propuestos:

numero.ToString("N1") );
numero.ToString("N3") );
numero.ToString("0.0") );
numero.ToString("0.000") );
numero.ToString("#.#") );
numero.ToString("#.###") );

Si indicamos ms decimales de los que tiene el nmero, se mostrarn ceros


x

tiene el nmero, aun as se muestran todas ellas.


Revisin 0.99zz Pgina 104

Si indicamos menos cifras antes de la coma decimal de las que realmente

#.###

si usamos como formato Nx o 0.000, y no se mostrar nada si usamos

Si indicamos menos decimales de los que tiene el nmero, se redondea.


x

Como se puede ver, ocurre lo siguiente:

12,3
12,340
12,3
12,340
12,3
12,34

El resultado de este ejemplo sera:

Console.WriteLine(
Console.WriteLine(
Console.WriteLine(
Console.WriteLine(
Console.WriteLine(
Console.WriteLine(

public class Ejemplo_03_02_05a


{
public static void Main()
{
double numero = 12.34;

using System;

// Ejemplo_03_02_05a.cs
// Formato de nmeros reales
// Introduccin a C#, por Nacho Cabanes

Introduce el radio
2,3456789
La longitud de la circunferencia es
14,7383356099727
Y con simple precisin
14,73834
Y como nmero entero
14

decimales".

N2 quiere decir "con dos cifras decimales" y N5 es "con cinco cifras

Vamos a probarlos en un ejemplo:

Alternativamente, se pueden usar otros formatos abreviados: por ejemplo,

nmero, y no se escribir nada si no hay nmero.

Su resultado sera:

longitudEntera = (int) longitud;


Console.WriteLine("Y como nmero entero");
Console.WriteLine(longitudEntera);

mostrar un 0 si no hay ninguno.


Una almohadilla (#) indica una posicin en la que puede aparecer un
Un punto (.) indica la posicin en la que deber aparecer la coma decimal.

longitudSimplePrec = (float) longitud;


Console.WriteLine("Y con simple precisin");
Console.WriteLine(longitudSimplePrec);

Un cero (0) indica una posicin en la que debe aparecer un nmero, y se

Introduccin a la programacin con C#, por Nacho Cabanes

Console..WriteLine("La longitud de la circunferencia es");


Console.WriteLine(longitud);

Introduccin a la programacin con C#, por Nacho Cabanes

este texto)

equivalente en sistema binario y en hexadecimal. Debe repetirse hasta que el


usuario introduzca el nmero 0.
(3.2.6.2) Crea un programa que pida al usuario la cantidad de rojo (por ejemplo,
255), verde (por ejemplo, 160) y azul (por ejemplo, 0) que tiene un color, y que
muestre ese color RGB en notacin hexadecimal (por ejemplo, FFA000).
(3.2.6.3) Crea un programa para mostrar los nmeros del 0 a 255 en hexadecimal,
en 16 filas de 16 columnas cada una (la primera fila contendr los nmeros del 0 al
15 decimal-, la segunda del 16 al 31 decimal- y as sucesivamente).

reales, y nos bastar con dos cifras decimales. Se deber pedir al usuario los

valores para las tres variables y mostrar en pantalla el valor de x2 + y - z (con

exactamente dos cifras decimales).

(3.2.5.3) Calcula el permetro, rea y diagonal de un rectngulo, a partir de su

ancho y alto (permetro = suma de los cuatro lados; rea = base x altura; diagonal,

usando el teorema de Pitgoras). Muestra todos ellos con una cifra decimal.

(3.2.5.4) Calcula la superficie y el volumen de una esfera, a partir de su radio

(superficie = 4 * pi * radio al cuadrado; volumen = 4/3 * pi * radio al cubo). Usa

f7
11110111

Su resultado sera:

Revisin 0.99zz Pgina 105

public class Ejemplo_03_02_06b


{
public static void Main()
{
int n1 = 0x13;
int n2 = Convert.ToInt32("1a", 16);

public class Ejemplo_03_02_06a


{
public static void Main()
{
int numero = 247;

using System;

using System;

// Ejemplo_03_02_06b.cs
// De hexadecimal y binario a decimal
// Introduccin a C#, por Nacho Cabanes

// Ejemplo_03_02_06a.cs
// De decimal a hexadecimal y binario
// Introduccin a C#, por Nacho Cabanes

Console.WriteLine( "{0} {1} {2} {3} {4}",


n1, n2, n3, n4, n5);

int n5 = Convert.ToInt32("11001001", 2);

Revisin 0.99zz Pgina 106

int n3 = 013; // No es octal, al contrario que en C y C++


int n4 = Convert.ToInt32("14", 8);

base 10, como se ve en este ejemplo:

como en este ejemplo:

es as: un nmero que empiece por 0 (no por 0x) se considera que est escrito en

(o a base octal, menos frecuente) usando Convert.ToString e indicando la base,

Console.WriteLine( Convert.ToString(numero, 16) );


Console.WriteLine( Convert.ToString(numero, 2) );

10). En los lenguajes C y C++, un valor precedido por "0" se considera octal, de
modo que para "int n2 = 013;" el valor decimal de n2 sera 8+3=11, pero en C# no

como en "int n1 = 0x13;" (donde n1 tendra el valor 16+3=19, expresado en base

habitualmente trabajamos con nmeros decimales (en base 10), pero en

(el sistema hexadecimal). Podemos convertir un nmero a binario o hexadecimal

destacar que una constante hexadecimal se puede expresar precedida por "0x",

Un uso alternativo de ToString es el de cambiar un nmero de base. Por ejemplo,

informtica son tambin muy frecuentes la base 2 (el sistema binario) y la base 16

podemos usar Convert.ToInt32, como se ve en el siguiente ejemplo. Es importante

3.2.6. Cambios de base

Para convertir en sentido contrario, de hexadecimal o binario a decimal,

(3.2.6.1) Crea un programa que pida nmeros (en base 10) al usuario y muestre su

(3.2.5.2) Crea un programa que use tres variables x,y,z. Las tres sern nmeros

datos "doble" y muestra los resultados con 5 cifras decimales.

Ejercicios propuestos:

nmero entre el segundo, utilizando tres cifras decimales.

cifras significativas. El programa deber mostrar el resultado de dividir el primer

(Si quieres saber ms sobre el sistema hexadecimal, mira los apndices al final de

(3.2.5.1) El usuario de nuestro programa podr teclear dos nmeros de hasta 12

Introduccin a la programacin con C#, por Nacho Cabanes

Ejercicios propuestos:

Introduccin a la programacin con C#, por Nacho Cabanes

letra = 'a';
Console.WriteLine("La letra es {0}", letra);

public class Ejemplo_03_03_01a


{
public static void Main()
{
char letra;

using System;

// Ejemplo_03_03_01a.cs
// Tipo de datos "char"
// Introduccin a C#, por Nacho Cabanes

tecleada por el usuario, y la muestre, podra ser:

Revisin 0.99zz Pgina 107

As, un programa que de un valor inicial a una letra, la muestre, lea una nueva letra

letra = Convert.ToChar(Console.ReadLine());

y convertimos a tipo "char" usando Convert.ToChar:

anteriores: leemos toda una frase (que debera tener slo una letra) con ReadLine

Para leer valores desde teclado, lo podemos hacer de forma similar a los casos

letra = 'a';

Asignar valores es sencillo: el valor se indica entre comillas simples

char letra;;

permite almacenar una nica letra, el tipo "char":

Como ya vimos brevemente, en C# tambin tenemos un tipo de datos que nos

3.3.1. Leer y mostrar caracteres

3.3. Tipo de datos carcter

usuario introduzca la palabra "fin".

equivalente en sistema hexadecimal y en decimal. Debe repetirse hasta que el

(3.2.6.4) Crea un programa que pida nmeros binarios al usuario y muestre su

Ejercicios propuestos:

19 26 13 12 201

Que mostrara:

Introduccin a la programacin con C#, por Nacho Cabanes

Secuencia
Significado
\a
Emite un pitido
\b
Retroceso (permite borrar el ltimo carcter)
\f
Avance de pgina (expulsa una hoja en la impresora)
\n
Avanza de lnea (salta a la lnea siguiente)
\r
Retorno de carro (va al principio de la lnea)
\t
Salto de tabulacin horizontal
\v
Salto de tabulacin vertical

Estas secuencias especiales son las siguientes:

veremos una alternativa ms segura).

Revisin 0.99zz Pgina 108

puede no funcionar correctamente en todos los sistemas operativos; ms adelante

se avanzar a la lnea siguiente de pantalla (es preferible evitar este ltimo, porque

dobles, con \' unas comillas simples, con \\ se escribe una barra invertida y con \n

algn otro carcter poco habitual. Por ejemplo, con \" se escribirn unas comillas

una barra invertida (\) y que nos permiten conseguir escribir esas comillas dobles y

escape". Existen ciertos caracteres especiales que se pueden escribir despus de

usando ciertos caracteres especiales, lo que se conoce como "secuencias de

cmo escribimos una comilla doble en pantalla? La forma de conseguirlo es

indicados entre parntesis y entre comillas dobles. Entonces surge una dificultad:

Como hemos visto, los textos que aparecen en pantalla se escriben con WriteLine,

3.3.2. Secuencias de escape: \n y otras

esa cantidad de letras:


XXXX
XXXX
XXXX

(por ejemplo, 3) y una letra (por ejemplo, X) y escriba un rectngulo formado por

(3.3.1.3) Crea un programa que pida al usuario el ancho (por ejemplo, 4) y el alto

"aceg...".

el usuario y la "z". Por ejemplo, si el usuario introduce una "a", se escribir

(3.3.1.2) Crea un programa que muestre una de cada dos letras entre la que teclee

vocal.

(3.3.1.1) Crea un programa que pida una letra al usuario y diga si se trata de una

Ejercicios propuestos

Console..WriteLine("Introduce una nueva letra");


letra = Convert.ToChar(Console.ReadLine());
Console.WriteLine("Ahora la letra es {0}", letra);

Introduccin a la programacin con C#, por Nacho Cabanes

Muestra una comilla simple


Muestra una comilla doble
Muestra una barra invertida
Carcter nulo (NULL)

deberamos

duplicar

todas

las

barras

invertidas:

solucionarlo, se duplican las comillas, as:


Revisin 0.99zz Pgina 109

En este caso, el problema est si aparecen comillas en medio de la cadena. Para

ruta = @"c:\datos\ejemplos\curso\ejemplo1"

antes del texto, en vez de usar las barras invertidas:

c:\\datos\\ejemplos\\curso\\ejemplo1. En este caso, se puede usar una arroba (@)

Windows,

Por ejemplo, cuando usemos estructuras de directorios al estilo de MsDos y

En algunas ocasiones puede ser incmodo manipular estas secuencias de escape.

otro salto
Comillas dobles: " y simples ', y barra \

Juguemos mas:

y esta es otra, separada dos lineas

Esta es una frase

Su resultado sera este:

Console.WriteLine("\n\nJuguemos mas:\n\notro salto");


Console.WriteLine("Comillas dobles: \" y simples \', y barra \\");

Al contrario que en lenguajes ms antiguos (como C), las cadenas de texto en C#

Si queremos dar un valor inicial, ste se indica entre comillas dobles.


Cuando leemos con ReadLine, no hace falta convertir el valor obtenido.
Podemos comparar su valor usando "==" (igualdad) o "!=" (desigualdad).

x
x
x

if (frase == "Hola!")
Console.WriteLine("Hola a ti tambin! ");

Revisin 0.99zz Pgina 110

Console.WriteLine("Introduce una nueva frase");


frase = Console.ReadLine();
Console.WriteLine("Ahora la frase es \"{0}\"", frase);

frase = "Hola, como estas?";


Console.WriteLine("La frase es \"{0}\"", frase);

public class Ejemplo_03_04a


{
public static void Main()
{
string frase;

using System;

// Ejemplo_03_04a.cs
// Uso basico de "string"
// Introduccin a C#, por Nacho Cabanes

leyera un valor tecleado por el usuario podra ser:

practicar las secuencias de escape que hemos visto en el apartado anterior) y

As, un ejemplo que diera un valor a un "string", lo mostrara (entre comillas, para

Se declaran con "string".

detalles que hay que tener en cuenta en un primer acercamiento son:

son tan fciles de manejar como los dems tipos de datos que hemos visto. Los

3.4. Toma de contacto con las cadenas de texto

public class Ejemplo_03_03_02a


{
public static void Main()
{
Console.WriteLine("Esta es una frase");
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("y esta es otra, separada dos lineas");

ejemplo si las letras que se teclean son a, l, o, h, escribira "hola".

muestre en pantalla juntas, pero en orden inverso, y entre comillas dobles. Por

(3.3.2.1) Crea un programa que pida al usuario que teclee cuatro letras y las

Ejercicio propuesto

orden = @"copy ""documento de ejemplo"" f:"

Introduccin a la programacin con C#, por Nacho Cabanes

using System;

// Ejemplo_03_03_02a.cs
// Secuencias de escape
// Introduccin a C#, por Nacho Cabanes

Vamos a ver un ejemplo que use los ms habituales:

\'
\"
\\
\0

Introduccin a la programacin con C#, por Nacho Cabanes

complejas (es la alternativa ms natural a los "break"). Un ejemplo que pida una
letra y diga si es una vocal, una cifra numrica u otro smbolo, usando variables
"bool" podra ser:
// Ejemplo_03_05a.cs
// Variables bool
// Introduccin a C#, por Nacho Cabanes

maysculas o a minsculas, eliminar espacios, cambiar una subcadena por otra,

dividir en trozos, etc. Pero ya volveremos a las cadenas ms adelante, en el

prximo tema.

Ejercicios propuestos:

ultimoNivel)))"

sino

simplemente

"if
}

// Ejemplo ms desarrollado
if (enemigos ==0) && (nivel == ultimoNivel)
partidaTerminada = true;
else
partidaTerminada = true;
// Notacin alternativa, sin usar "if"
partidaTerminada = (enemigos ==0) && (nivel == ultimoNivel);

// Ejemplo bsico
partidaTerminada = false;
if (vidas == 0) partidaTerminada = true;
// Notacin alternativa, sin usar "if"
partidaTerminada = vidas == 0;

Revisin 0.99zz Pgina 111

operador condicional.

Revisin 0.99zz Pgina 112

(3.5.4) Crea una versin alternativa del ejercicio 3.5.3, que use "if" en vez del

el usuario son pares, o "false" si alguno es impar.

llamada "ambosPares" (booleana) el valor "true" si dos nmeros introducidos por

(3.5.3) Crea un programa que use el operador condicional para dar a una variable

operador condicional.

(3.5.2) Crea una versin alternativa del ejercicio 3.5.1, que use "if" en vez del

usuario son iguales, o "false" si son distintos.

llamada "iguales" (booleana) el valor "true" si los dos nmeros que ha tecleado el

(3.5.1) Crea un programa que use el operador condicional para dar a una variable

==

Ejercicios propuestos:

(nivel

comparacin:

&&

A las variables "bool" tambin se le puede dar como valor el resultado de una

0)
}

==

if (esCifra)
Console.WriteLine("Es una cifra numrica.");
else if (esVocal)
Console.WriteLine("Es una vocal.");
else
Console.WriteLine("Es una consonante u otro smbolo.");

esVocal = (letra == 'a') || (letra == 'e') || (letra == 'i') ||


(letra == 'o') || (letra == 'u');

esCifra = (letra >= '0') && (letra <='9');

Console.WriteLine("Introduce una letra");


letra = Convert.ToChar(Console.ReadLine());

public class Ejemplo_03_05a


{
public static void Main()
{
char letra;
bool esVocal, esCifra;

(partidaTerminada) ..."

((enemigos

fragmentos de nuestro programa no sean "if ((vidas == 0) || (tiempo == 0) ||

condiciones que podran resultar complejas. As podemos hacer que ciertos

Este tipo de datos har que podamos escribir de forma sencilla algunas

bool encontrado;;
encontrado = true;

tomar dos valores: verdadero ("true") o falso ("false"):

En C# tenemos tambin un tipo de datos llamado "booleano" ("bool"), que puede

3.5. Los valores "booleanos"

avisar al usuario y se le volvern a pedir las dos contraseas.

contrasea se debe introducir dos veces. Si las dos contraseas no son iguales, se

(3.4.2) Crear un programa que pida al usuario un nombre y una contrasea. La

llama "Juan", o bien le diga "No te conozco" si teclea otro nombre.


using System;

Lo emplearemos a partir de ahora en los fuentes que usen condiciones un poco

Se pueden hacer muchas ms operaciones sobre cadenas de texto: convertir a

(3.4.1) Crear un programa que pida al usuario su nombre, y le diga "Hola" si se

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

// Ejemplo_04_01_01a.cs
// Primer ejemplo de tablas (arrays)
// Introduccin a C#, por Nacho Cabanes
Revisin 0.99zz Pgina 113

Como ejemplo, vamos a definir un grupo de 5 nmeros enteros y hallar su suma:

int[] datos = new int[100];

nombres en plural, como en

Habitualmente, como un array representa un conjunto de nmeros, utilizaremos

ejemplo[0] = 15;

dar el valor 15 al primer elemento de nuestro array as:

que seran ejemplo[0], ejemplo[1], ejemplo[2], ejemplo[3]. Por tanto, podramos

empieza a numerar desde 0, as que en el caso anterior tendramos 4 elementos,

(ejemplo) y el nmero de elemento que nos interesa, pero con una precaucin: se

Podemos acceder a cada uno de los valores individuales indicando su nombre

Revisin 0.99zz Pgina 114

suma = numeros[0] +
// Hallamos la suma
numeros[1] + numeros[2] + numeros[3] + numeros[4];
Console.WriteLine("Su suma es {0}", suma);

public class Ejemplo_04_01_02a


{
public static void Main()
{
int[] numeros =
// Un array de 5 nmeros enteros
{200, 150, 100, -50, 300};
int suma;
// Un entero que ser su suma

using System;

// Ejemplo_04_01_02a.cs
// Segundo ejemplo de tablas: valores iniciales con []
// Introduccin a C#, por Nacho Cabanes

En este caso, los indicaremos todos entre llaves, separados por comas:

elementos de una tabla al principio del programa, si conocemos todos su valores.

Al igual que ocurra con las variables "normales", podemos dar valor inicial a los

4.1.2. Valor inicial de un array

array de "float") y luego los muestre en el orden contrario al que se introdujeron.

(4.1.1.2) Un programa que pida al usuario 5 nmeros reales (pista: necesitars un

int[] ejemplo = new int[4];

datos tecleados.

declaramos la variable:

array), calcule su media aritmtica y despus muestre en pantalla la media y los

(4.1.1.1) Un programa que pida al usuario 4 nmeros, los memorice (utilizando un

Ejercicios propuestos:

numeros[0] = 200;
// Les damos valores
numeros[1] = 150;
numeros[2] = 100;
numeros[3] = -50;
numeros[4] = 300;
suma = numeros[0] +
// Y calculamos la suma
numeros[1] + numeros[2] + numeros[3] + numeros[4];
Console.WriteLine("Su suma es {0}", suma);
// Nota: esta es la forma ms ineficiente e incmoda
// Lo mejoraremos...

int[] numeros = new int[5]; // Un array de 5 nmeros enteros


int suma;
// Un entero que ser la suma

public class Ejemplo_04_01_01a


{
public static void Main()
{

using System;

Introduccin a la programacin con C#, por Nacho Cabanes

Si sabemos el tamao desde el principio, podemos reservar espacio a la vez que

ejemplo = new int[4];

reservar espacio con la orden "new", as:

Cuando sepamos cuantos datos vamos a guardar (por ejemplo 4), podremos

int[
[] ejemplo;

que usaremos para declararlo ser "int []":

Por ejemplo, si queremos definir un grupo de nmeros enteros, el tipo de datos

accederemos usando el mismo nombre.

un conjunto de elementos, todos los cuales son del mismo tipo, y a los que

Una tabla, vector, matriz o array (que algunos autores traducen por "arreglo") es

4.1.1. Definicin de un array y acceso a los datos

4.1. Conceptos bsicos sobre arrays o tablas

4. Arrays, estructuras y cadenas de texto

Introduccin a la programacin con C#, por Nacho Cabanes

Ejemplo_04_01_03a.cs
Tercer ejemplo de tablas: valores iniciales con llaves
y recorrido con "for"
Introduccin a C#, por Nacho Cabanes

using System;

//
//
//
//

Revisin 0.99zz Pgina 115

// Valor inicial de la suma: 0


// Y calculamos la suma repetitiva

El fuente completo podra ser as:

suma = 0;
for (int i=0; i<=4; i++)
suma += numeros[i];

hemos visto (while, do..while, for), por ejemplo as:

El "truco" consistir en emplear cualquiera de las estructuras repetitivas que ya

suma = numeros[0] + numeros[1] + numeros[2] + numeros[3] + numeros[4];

un array, sin tener siempre que repetirlos todos, como hemos hecho en

Es de esperar que exista una forma ms cmoda de acceder a varios elementos de

4.1.3. Recorriendo los elementos de una tabla

tiene ese mes.

un mes (1=enero, 12=diciembre) y muestre en pantalla el nmero de das que

cada mes (supondremos que es un ao no bisiesto), pida al usuario que le indique

(4.1.2.1) Un programa que almacene en una tabla el nmero de das que tiene

Ejercicios propuestos:

int[] numeros = {200, 150, 100, -50, 300};

al analizar el contenido del array:

necesario usar "new" junto con el tamao, ya que el compilador lo puede deducir

Pero, como se ve en el ejemplo anterior, casi siempre se podr abreviar, y no ser

int[] numeros = new int[5] {200, 150, 100, -50, 300};

Nota: el formato completo para la declaracin de un array con valores iniciales es


ste. incluyendo tanto la orden "new" como los valores entre llaves:

// Nota: esta forma es algo menos engorrosa, pero todava no


// est bien hecho. Lo seguiremos mejorando.

Introduccin a la programacin con C#, por Nacho Cabanes

Console.WriteLine("Su suma es {0}", suma);

// Valor inicial de la suma: 0


// Y calculamos la suma repetitiva

Console.WriteLine("Su suma es {0}", suma);

Ejercicios propuestos:

suma = 0;
// Y calculamos la suma
for (int i=0; i<=4; i++)
suma += numeros[i];

Revisin 0.99zz Pgina 116

for (int i=0; i<=4; i++)


// Pedimos los datos
{
Console.Write("Introduce el dato numero {0}: ", i+1);
numeros[i] = Convert.ToInt32(Console.ReadLine());
}

int[] numeros = new int[5];


int suma;

public class Ejemplo_04_01_03b


{
public static void Main()
{

using System;

// Ejemplo_04_01_03b.cs
// Cuarto ejemplo de tablas: introducir datos repetitvos
// Introduccin a C#, por Nacho Cabanes

usando un "for", "while" o "do..while":

Lgicamente, tambin podemos pedir los datos al usuario de forma repetitiva,

que sera evidente.

pero si trabajsemos con 100, 500 o 1000 nmeros, la ganancia en comodidad s

En este caso, que slo sumbamos 5 nmeros, no hemos escrito mucho menos,

suma = 0;
for (int i=0; i<=4; i++)
suma += numeros[i];

public class Ejemplo_04_01_03a


{
public static void Main()
{
int[] numeros =
// Un array de 5 nmeros enteros
{200, 150, 100, -50, 300};
int suma;
// Un entero que ser su suma

Introduccin a la programacin con C#, por Nacho Cabanes

frecuentes: buscar si existe un cierto dato, aadir un dato al final de los existentes,
insertar un dato entre dos que ya hay, borrar uno de los datos almacenados, etc.
Por eso, vamos a ver las pautas bsicas para realizar estas operaciones, y un
fuente de ejemplo.

(4.1.3.3) Un programa que pida al usuario 10 reales de doble precisin, calcule su

media y luego muestre los que estn por encima de la media.

(4.1.3.4) Un programa que almacene en una tabla el nmero de das que tiene

almacenado con el dato que se busca. Puede interesarnos simplemente saber si


est o no (con lo que se podra interrumpir la bsqueda en cuanto aparezca una
primera vez) o ver en qu posiciones se encuentra (para lo que habra que recorrer
todo el array). Si el array estuviera ordenado, se podra buscar de una forma ms
rpida, pero la veremos ms adelante.

ejemplo, el 15 de febrero sera el da nmero 46, el 31 de diciembre sera el da

365).

(4.1.3.5) A partir del ejercicio anterior, crea otro que pida al usuario que le indique

la fecha, formada por da (1 al 31) y el mes (1=enero, 12=diciembre), y como

respuesta muestre en pantalla el nmero de das que quedan hasta final de ao.

ver si est por encima o debajo de ese mximo o mnimo provisional, y cambiarlo
si fuera necesario.

dir si se encuentra o no entre los 10 que se han tecleado antes. Volver a pedir

otro nombre y a decir si se encuentra entre ellos, y as sucesivamente hasta que se

teclee "fin".

no est completamente lleno, y llevar un contador de cuntas posiciones hay


ocupadas, de modo que seamos capaces de guardar el dato en la primera posicin
libre.

pulse Intro sin teclear nada, momento en el que dejarn de pedirse ms nombres

y se mostrar en pantalla la lista de los nombres que se han introducido.

(4.1.3.8) Un programa que reserve espacio para un vector de 3 componentes, pida

desplazarse "hacia la derecha" para dejarle hueco. Este movimiento debe empezar
desde el final para que cada dato que se mueve no destruya el que estaba a
continuacin de l. Tambin habr que actualizar el contador, para indicar que
queda una posicin libre menos.

(4.1.3.9) Un programa que reserve espacio para dos vectores de 3 componentes,

pida al usuario sus valores y calcule la suma de ambos vectores (su primera

componente ser x1+y1, la segunda ser x2+y2 y as sucesivamente).

(4.1.3.10) Un programa que reserve espacio para dos vectores de 3 componentes,

para indicar que queda una posicin libre ms.

que hasta ese momento es el mximo provisional. El valor inicial de este mximo

nmeros son negativos), sino el primer elemento del array.

Revisin 0.99zz Pgina 117

// Ejemplo_04_01_04a.cs
Revisin 0.99zz Pgina 118

huecos. Como en el caso anterior, habr que actualizar el contador, pero ahora

hay que comparar cada uno de los valores que tiene almacenados el array con el

Vamos a verlo con un ejemplo:

continuacin debern desplazarse "hacia la izquierda" para que no queden

muestre) cul es el mayor de ellos. Nota: para calcular el mayor valor de un array,

provisional no debera ser cero (porque el resultado sera incorrecto si todos los

Si se quiere borrar el dato que hay en una cierta posicin, los que estaban a

(4.1.3.11) Un programa que pida al usuario 4 nmeros enteros y calcule (y

pida al usuario sus valores y calcule su producto escalar (x1y1+ x2y2+x3y3).

Para insertar un dato en una cierta posicin, los que queden detrs debern

mdulo (raz cuadrada de la suma de sus componentes al cuadrado).

al usuario valores para dichas componentes (por ejemplo [2, -5, 7]) y muestre su

Para poder aadir un dato al final de los ya existentes, necesitamos que el array

nombres. El usuario deber ir introduciendo un nombre cada vez, hasta que se

(4.1.3.7) Un programa que prepare espacio para guardar un mximo de 100

Para encontrar el mximo o el mnimo de los datos, tomaremos el primero de los


datos como valor provisional, y compararemos con cada uno de los dems, para

trata de un array de "string"). Despus deber pedir que se teclee un nombre y

(4.1.3.6) Un programa que pida 10 nombres y los memorice (pista: esta vez se

Para ver si un dato existe, habr que recorrer todo el array, comparando el valor

febrero) y un da (ej. el da 15) y diga qu nmero de da es dentro del ao (por

cada mes (de un ao no bisiesto), pida al usuario que le indique un mes (ej. 2 para

Algunas operaciones con datos pertenecientes a un array son especialmente

finalmente calcule y muestre la media de esos nmeros.

4.1.4. Operaciones habituales con arrays: buscar, aadir,


insertar, borrar

Introduccin a la programacin con C#, por Nacho Cabanes

introducir (por ejemplo, 10), le pida todos esos nmeros, los guarde en un array y

(4.1.3.2) Crea un programa que pregunte al usuario cuntos nmeros enteros va a

mostrarlos).

los muestre en orden inverso (pista: usa un array para almacenarlos y "for" para

(4.1.3.1) Crea un programa que pida al usuario 6 nmeros enteros cortos y luego

Introduccin a la programacin con C#, por Nacho Cabanes

// Para recorrer los elementos

int i;

// Insertamos 30 en la tercera posicin


if (cantidad < capacidad)

// Y volvemos a mostrar el array


for (i=0; i<cantidad; i++)
Console.Write("{0} ",datos[i]);
Console.WriteLine();

// Borramos el segundo dato


Console.WriteLine("Borrando el segundo dato");
int posicionBorrar = 1;
for (i=posicionBorrar; i<cantidad-1; i++)
datos[i] = datos[i+1];
cantidad--;

// Y volvemos a mostrar el array


for (i=0; i<cantidad; i++)
Console.Write("{0} ",datos[i]);
Console.WriteLine();

// Aadimos un dato al final


Console.WriteLine("Aadiendo 6 al final");
if (cantidad < capacidad)
{
datos[cantidad] = 6;
cantidad++;
}

// Buscamos el mximo
int maximo = datos[0];
for (i=1; i<cantidad; i++)
if (datos[i] > maximo)
maximo = datos[i];
Console.WriteLine("El mximo es {0} ", maximo);

Revisin 0.99zz Pgina 119

// Buscamos el dato "15"


for (i=0; i<cantidad; i++)
if (datos[i] == 15)
Console.WriteLine("15 encontrado en la posicin {0} ", i+1);

// Mostramos el array
for (i=0; i<cantidad; i++)
Console.Write("{0} ",datos[i]);
Console.WriteLine();

// Capacidad maxima del array


// Nmero real de datos guardados

int capacidad = 5;
int cantidad = 3;

public class Ejemplo_04_01_04a


{
public static void Main()
{
int[] datos = {10, 15, 12, 0, 0};

using System;

// Aadir y borrar en un array


// Introduccin a C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

no es vlida.

Revisin 0.99zz Pgina 120

se encuentre en la posicin que elija el usuario. Debe avisar si la posicin escogida

(4.1.4.4) Crea una variante del ejemplo anterior (04_01_04a) que borre el dato que

posicin escogida es incorrecta (porque est ms all del final de los datos).

introducido por el usuario en la posicin que elija el usuario. Debe avisar si la

(4.1.4.3) Crea una variante del ejemplo anterior (04_01_04a) que inserte un dato

introducido por el usuario al final de los datos existentes.

(4.1.4.2) Crea una variante del ejemplo anterior (04_01_04a) que aada un dato

encontrado en caso contrario.

dato a buscar, avise si ese dato no aparece, y que diga cuntas veces se ha

(4.1.4.1) Crea una variante del ejemplo anterior (04_01_04a) que pida al usuario el

Ejercicios propuestos:

sabemos que no est en la posicin actual).

"else", porque en cada pasada del bucle "for" no sabemos si el dato no existe, slo

testigo, de forma que al final nos avise si el dato no exista (no sirve emplear un

buscando. Se puede mejorar usando una variable "booleana" que nos sirva de

Este programa "no dice nada" cuando no se encuentra el dato que se est

10 15 12
15 encontrado en la posicin 2
El mximo es 15
Aadiendo 6 al final
10 15 12 6
Borrando el segundo dato
10 12 6
Insertando 30 en la posicin 3
10 12 30 6

que tendra como resultado:

Console.WriteLine("Insertando 30 en la posicin 3");


int posicionInsertar = 2;
for (i=cantidad; i>posicionInsertar; i--)
datos[i] = datos[i-1];
datos[posicionInsertar] = 30;
cantidad++;

// Y volvemos a mostrar el array


for (i=0; i<cantidad; i++)
Console.Write("{0} ",datos[i]);
Console.WriteLine();

Introduccin a la programacin con C#, por Nacho Cabanes

Salir del programa.

y entonces debemos recordar que

const int MAXIMO = 5;

public class Ejemplo_04_01_05a


{
public static void Main()
{

using System;

// Cantidad de datos
Revisin 0.99zz Pgina 121

int datosAlumnos[2][20]

pero en C# esto no tiene

segundo ejemplo.

Revisin 0.99zz Pgina 122

podran ser incluso dos arrays de distinto tamao, como veremos en el

arrays, cuyos elementos a su vez son arrays de 20 elementos. De hecho,

exactamente el mismo significado que [2,20], sino que se trata de dos

en C es emplear

Una alternativa, que puede sonar ms familiar a quien ya haya programado

y entonces sabemos

// Ejemplo_04_01_05a.cs
// Quinto ejemplo de tablas: constantes
// Introduccin a C#, por Nacho Cabanes

int datosAlumnos[2,20]
datosAlumnos[1,i] son los del segundo.

O bien podemos emplear

daremos ms detalles.

los 20 siguientes a otro grupo. Es "demasiado artesanal", as que no

para la capacidad del array podra ser:


x

int datosAlumnos[40]

los 20 primeros datos corresponden realmente a un grupo de alumnos y

Se puede usar

que los datos de la forma datosAlumnos[0,i] son los del primer grupo, y los

personas, tendra dos opciones:

quiere guardar datos de dos grupos de alumnos, cada uno de los cuales tiene 20

Podemos declarar tablas de dos o ms dimensiones. Por ejemplo, si un profesor

4.2. Arrays bidimensionales

valor mximo del array en ambos recorridos.

Diciembre) o en orden inverso (de Diciembre a Enero). Usa constantes para el

del ao. El usuario podr elegir entre verlos en orden natural (de Enero a

(4.1.5.1) Crea un programa que contenga un array con los nombres de los meses

Ejercicios propuestos:

Console.WriteLine("Su suma es {0}", suma);

As, una nueva versin del fuente del apartado 4.1.3 (b), usando una constante

const int MAXIMO = 5;

en maysculas:

distinguir una constante de una variable, se suele escribir su nombre totalmente

que la modifiquemos por error. Adems, por convenio, para que sea fcil

palabra "const" para indicar que debe ser constante, y el compilador no permitir

una variable. Dado que el valor de sta no debera cambiar, podemos usar la

mantenimiento del programa, puede ser preferible no usar el valor numrico, sino

tamao mximo de un array. En esos casos, por legibilidad y por facilidad de

En ocasiones, manejaremos valores que realmente no van a variar. Es el caso del

4.1.5. Constantes

Mostrar los datos que contiene el array.

"adios"

borrar el dato de la segunda posicin, el array pasar a contener "hola",

huecos; por ejemplo, si el array contiene "hola", "bien", "adios" y se pide

estaban detrs debern desplazarse "a la izquierda" para que no haya

Borrar el dato que hay en una cierta posicin (como se ha visto, lo que

segunda posicin, el array pasar a contener "hola", "bien", "adios".

ejemplo, si el array contiene "hola", "adios" y se pide insertar "bien" en la

Insertar un dato en una cierta posicin (como ya se ha comentado, los que

quedn detrs debern desplazarse "a la derecha" para dejarle hueco; por

Aadir un dato al final de los ya existentes.

suma = 0;
// Y calculamos la suma
for (int i=0; i<MAXIMO; i++)
suma += numeros[i];

for (int i=0; i<MAXIMO; i++)


// Pedimos los datos
{
Console.Write("Introduce el dato numero {0}: ", i+1);
numeros[i] = Convert.ToInt32(Console.ReadLine());
}

operaciones:

Deber mostrar al usuario un men que le permita realizar las siguientes

int[
[] numeros = new int[MAXIMO];
int suma;

Introduccin a la programacin con C#, por Nacho Cabanes

(4.1.4.5) Crea un programa que prepare espacio para un mximo de 10 nombres.

Introduccin a la programacin con C#, por Nacho Cabanes

// Ejemplo_04_02b.cs
// Array de arrays (array de dos dimensiones al estilo C)
// Introduccin a C#, por Nacho Cabanes

para lo que podemos usar "a.Length":

Revisin 0.99zz Pgina 123

elementos de distinto tamao. En ese caso nos puede interesar saber su longitud,

como ya hemos comentado, y como veremos en este ejemplo, pueden tener

La otra forma de tener arrays multidimensionales son los "arrays de arrays", que,

conocimientos al uso de arrays bidimensionales.

matrices, ms adelante tienes algunos ejercicios propuestos para aplicar esos

complejos que los que hemos visto hasta ahora. Si ya has estudiado la teora de

guardar matrices, cuando se trata de resolver problemas matemticos ms

Este tipo de tablas de varias dimensiones son las que se usan tambin para

Console.WriteLine("La nota1 del segundo alumno del grupo 1 es {0}",


notas1[0,1]);
Console.WriteLine("La nota2 del tercer alumno del grupo 1 es {0}",
notas2[0,2]);

int[,] notas2 = // 2 bloques de 10 datos, prefijados


{
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
{11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
};

public class Ejemplo_04_02a


{
public static void Main()
{
int[,] notas1 = new int[2,2]; // 2 bloques de 2 datos
notas1[0,0] = 1;
notas1[0,1] = 2;
notas1[1,0] = 3;
notas1[1,1] = 4;

using System;

// Ejemplo_04_02a.cs
// Array de dos dimensiones "rectangulares" (estilo Pascal)
// Introduccin a C#, por Nacho Cabanes

"new" y a los que demos valores en un segundo paso:

arrays con valores prefijados, como arrays para los que reservemos espacio con

[2,20], lo que podramos llamar el "estilo Pascal". En este ejemplo usaremos tanto

Vamos a ver un primer ejemplo de uso con arrays "rectangulares", de la forma

igual que si fuera una tabla de una nica dimensin.

En cualquier caso, si queremos indicar valores iniciales, lo haremos entre llaves,

Introduccin a la programacin con C#, por Nacho Cabanes

} // Fin de "Main"

Revisin 0.99zz Pgina 124

de nmeros enteros (por ejemplo, uno de 10 elementos y otro de 12). Luego

(4.2.3) Un programa que pregunte al usuario el tamao que tendrn dos bloques

de los dos bloques de informacin anteriores.

Despus pedir al usuario una nueva cadena y comprobar si aparece en alguno

(4.2.2) Un programa que pida al usuario dos bloques de 6 cadenas de texto.

que se ha introducido en cada uno de ellos.

(usando un array de dos dimensiones). Despus deber mostrar el mayor dato

(4.2.1) Un programa que pida al usuario dos bloques de 10 nmeros enteros

Ejercicios propuestos:

2 3 4 5 6 7 8 9 10 11 12 13

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

0123456789

La salida de este programa sera

// Y mostramos esos valores


for (int i=0;i<notas.Length;i++)
{
for (int j=0;j<notas[i].Length;j++)
{
Console.Write(" {0}", notas[i][j]);
}
Console.WriteLine();
}

// Damos valores de ejemplo


for (int i=0;i<notas.Length;i++)
{
for (int j=0;j<notas[i].Length;j++)
{
notas[i][j] = i + j;
}
}

public class Ejemplo_04_02b


{
public static void Main()
{
int[][] notas;
// Array de dos dimensiones
notas = new int[3][]; // Seran 3 bloques de datos
notas[0] = new int[10]; // 10 notas en un grupo
notas[1] = new int[15]; // 15 notas en otro grupo
notas[2] = new int[12]; // 12 notas en el ultimo

using System;

Introduccin a la programacin con C#, por Nacho Cabanes

public class Ejemplo_04_03_01a


{
struct tipoPersona
{
public string nombre;
public char inicial;
public int
edad;

using System;

// Ejemplo_04_03_01a.cs
// Registros (struct)
// Introduccin a C#, por Nacho Cabanes

punto:

Revisin 0.99zz Pgina 125

se debe indicar el nombre de la variable y el del dato (o campo) separados por un

forman el registro, tanto si queremos leer su valor como si queremos cambiarlo,

Ya desde el cuerpo del programa, para acceder a cada uno de los datos que

queremos que sean pblicos.

por lo que siempre les aadiremos delante la palabra "public" para indicar que

nosotros nos interesar que sean accesibles desde el resto de nuestro programa,

Los datos que forman un "struct" pueden ser pblicos o privados. Por ahora, a

adelante, ya dentro de "Main", podremos declarar variables de ese nuevo tipo.

estructura de nuestro registro, lo que no se puede hacer dentro de "Main". Ms

En C# (al contrario que en C), primero deberemos declarar cual va a ser la

necesariamente son del mismo tipo. Se definen con la palabra "struct".

Un registro es una agrupacin de datos, llamados campos, los cuales no

4.3.1. Definicin y acceso a los datos

4.3. Estructuras o registros

lineales mediante el mtodo de Gauss.

(4.2.7) Un programa que use matrices para resolver un sistema de ecuaciones

dependientes.

(4.2.6) Un programa que calcule si las filas de una matriz son linealmente

(4.2.5) Un programa que calcule el determinante de una matriz de 3x3.

(4.2.4) Un programa que calcule el determinante de una matriz de 2x2.

Si has estudiado lgebra de matrices:

mayor dato que se ha introducido en cada uno de ellos.

pedir los datos para ambos bloques de datos. Finalmente deber mostrar el

Introduccin a la programacin con C#, por Nacho Cabanes

persona.nombre = "Juan";
persona.inicial = 'J';
persona.edad = 20;
persona.nota = 7.5f;
Console.WriteLine("La edad de {0} es {1}",
persona.nombre, persona.edad);

Se pueden almacenar los de

personas[0].nombre = "Juan";
personas[0].inicial = 'J';
personas[0].edad = 20;
personas[0].nota = 7.5f;
Console.WriteLine("La edad de {0} es {1}",

public static void Main()


{
tipoPersona[] personas = new tipoPersona[100];

public class Ejemplo_04_03_02a


{
struct tipoPersona
{
public string nombre;
public char inicial;
public int
edad;
public float nota;
}

using System;

// Ejemplo_04_03_02a.cs
// Array de struct
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 126

Por ejemplo, si queremos guardar los datos de 100

personas podramos hacer:

vimos anteriormente.

varias personas si combinamos el uso de los "struct" con las tablas (arrays) que

Hemos guardado varios datos de una persona.

4.3.2. Arrays de structs

despus mostrarlos en pantalla.

debe pedir los datos de una cancin al usuario, almacenarlos en dicho "struct" y

Artista, Ttulo, Duracin (en segundos), Tamao del fichero (en KB). Un programa

(4.3.1.1) Crea un "struct" que almacene datos de una cancin en formato MP3:

Ejercicios propuestos:

public float nota;

public static void Main()


{
tipoPersona persona;

Introduccin a la programacin con C#, por Nacho Cabanes

como minutos y segundos, usando un "struct" anidado que contenga a su vez


estos dos campos.

2000), alto en pxeles (por ejemplo, 3000), tamao en Kb (por ejemplo 145,6). El

de comparar cual es su valor (==).

// Ejemplo_04_03_03a.cs
// Registros anidados
// Introduccin a C#, por Nacho Cabanes

hacerlo desde C#, incluiramos un "struct" dentro de otro, as:

Revisin 0.99zz Pgina 127

saludase usando todo ello podra ser:


Revisin 0.99zz Pgina 128

"concatenar" cadenas. Un ejemplo que nos pidiese nuestro nombre y nos

partir de otras si las unimos con el smbolo de la suma (+), lo que llamaremos

Vamos a repasar todas esas posibilidades, junto con la de formar una cadena a

mostrarlas en pantalla (Console.Write), as como la forma de darles un valor (=) y

ocurra que uno de esos datos est formado por varios datos ms sencillos. Por

ejemplo, una fecha de nacimiento podra estar formada por da, mes y ao. Para

Hemos visto cmo leer cadenas de caracteres (Console.ReadLine) y cmo

Podemos encontrarnos con un registro que tenga varios datos, y que a su vez

4.4.1. Definicin. Lectura desde teclado

4.3.3. structs anidados

cierto nombre.

todas las fichas (nmero y nombre de cada imagen), buscar la ficha que tenga un

su capacidad est llena). Debe permitir las opciones: aadir una ficha nueva, ver

4.4. Cadenas de caracteres

(4.3.3.1) Amplia el programa 4.3.2.1, para que el campo "duracin" se almacene

De cada imagen se debe guardar: nombre (texto), ancho en pxeles (por ejemplo

programa debe ser capaz de almacenar hasta 700 imgenes (deber avisar cuando

Ejercicios propuestos:

ordenador que contengan fotografas o cualquier otro tipo de informacin grfica).

persona.nombre = "Juan";
persona.inicial = 'J';
persona.diaDeNacimiento.dia = 15;
persona.diaDeNacimiento.mes = 9;
persona.nota = 7.5f;
Console.WriteLine("{0} naci en el mes {1}",
persona.nombre, persona.diaDeNacimiento.mes);

public static void Main()


{
tipoPersona persona;

struct tipoPersona
{
public string nombre;
public char inicial;
public fechaNacimiento diaDeNacimiento;
public float nota;
}

public class Ejemplo_04_03_03a


{
struct fechaNacimiento
{
public int dia;
public int mes;
public int anyo;
}

using System;

Introduccin a la programacin con C#, por Nacho Cabanes

(4.3.2.2) Crea un programa que permita guardar datos de "imgenes" (ficheros de

contenga un cierto texto (en el artista o en el ttulo).

nueva cancin, mostrar el ttulo de todas las canciones, buscar la cancin que

hasta 100 canciones. Deber tener un men que permita las opciones: aadir una

(4.3.2.1) Amplia el programa del ejercicio 4.3.1.1, para que almacene datos de

Ejercicios propuestos:

cadenas de texto).

"new", sus valores se dejan "vacos" (0 para los nmeros, cadenas vacas para las

porque cuando reservamos espacio para los elementos de un "array" usando

La edad de Juan es 20
La edad de Pedro es 0

Al probar este programa obtenemos

sera "personas[99].edad".

La inicial de la primera persona sera "personas[0].inicial", y la edad del ltimo

personas[1].nombre = "Pedro";
Console.WriteLine("La edad de {0} es {1}",
personas[1].nombre, personas[1].edad);

personas[[0].nombre, personas[0].edad);

Introduccin a la programacin con C#, por Nacho Cabanes

despedida = "Adios " + nombre + "!";


Console.WriteLine(despedida);

public class Ejemplo_04_04_03a


{
public static void Main()
{
string saludo = "Hola";
int longitud = saludo.Length;
Console.WriteLine("La longitud de {0} es {1}", saludo, longitud);
for (int i=0; i<longitud; i++)

resultado de esa operacin (por ejemplo, si los nmeros son 3 y 6 y la operacin es

texto y analizarla con un "switch".

Revisin 0.99zz Pgina 129

"suma", el resultado sera 9). La operacin debes tomarla como una cadena de

Revisin 0.99zz Pgina 130

using System;

podr usar una "x", minscula o mayscula. A continuacin se mostrar el

con los operadores matemticos "+", "-", "*" y "/". Para multiplicar tambin se

multiplicacin" y "divisin", que tambin se podrn escribir de forma abreviado

// Ejemplo_04_04_03a.cs
// Cadenas de texto (3: longitud)
// Introduccin a C#, por Nacho Cabanes

como "for".

una operacin que realizar con ellos. La operacin podr ser "suma", "resta",

(4.4.1.4) Crea un programa que pida al usuario dos nmeros enteros y despus

una coma y el da del mes por una barra inclinada, as: "Juan, nacido el 31/12".

permite que podamos recorrer la cadena letra por letra, usando construcciones

Podemos saber cuantas letras forman una cadena con "cadena.Length". Esto

nacimiento y lo junte todo en una cadena, separando el nombre de la fecha por

4.4.3. Longitud de la cadena

(4.4.1.3) Un programa que pida tu nombre, tu da de nacimiento y tu mes de

es su inicial.

(4.4.2.1) Crea un programa que pregunte al usuario su nombre y le responda cul

Ejercicios propuestos:

public class Ejemplo_04_04_02a


{
public static void Main()
{
string saludo = "Hola";
Console.WriteLine("La tercera letra de {0} es {1}",
saludo, saludo[2]);
}
}

using System;

// Ejemplo_04_04_02a.cs
// Cadenas de texto (2: acceder a una letra)
// Introduccin a C#, por Nacho Cabanes

adelante.

texto[0]='a'. Para eso habr que usar una construccin auxiliar, que veremos ms

Eso s, las cadenas en C# no se pueden modificar letra a letra: no podemos hacer

ser texto[0], el segundo ser texto[1] y as sucesivamente.

elementos de cualquier array: si la cadena se llama "texto", el primer elemento

Podemos leer una de las letras de una cadena, de igual forma que leemos los

4.4.2. Cmo acceder a las letras que forman una cadena

Introduccin a la programacin con C#, por Nacho Cabanes

saludar por su nombre.

(por ejemplo, "Nacho"), responder "Bienvenido, jefe". En caso contrario, le

(4.4.1.2) Crea un programa que pida al usuario su nombre. Si se llama como t

(4.4.1.1) Crea un programa que te pida tu nombre y lo escriba 5 veces.

Ejercicios propuestos:

if (nombre == "Alberto")
Console.WriteLine("Dices que eres Alberto?");
else
Console.WriteLine("As que no eres Alberto?");

Console.WriteLine("{0} {1}", saludo, nombre);


Console.WriteLine(segundoSaludo);

segundoSaludo = "Que tal?";


Console.WriteLine("Dime tu nombre... ");
nombre = Console.ReadLine();

public class Ejemplo_04_04_01a


{
public static void Main()
{
string saludo = "Hola";
string segundoSaludo;
string nombre, despedida;

using System;

// Ejemplo_04_04_01a.cs
// Cadenas de texto (1: manejo bsico)
// Introduccin a C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

Console.WriteLine("La letra {0} es {1}", i, saludo[i]);

Revisin 0.99zz Pgina 131

if (nombre.Contains("Juan")) ...

nos bastar con usar "Contains":

Revisin 0.99zz Pgina 132

Si solamente queremos ver si aparece, pero no nos importa en qu posicin est,

decir, busca de derecha a izquierda).

De forma similar, LastIndexOf ("ltima posicin de") indica la ltima aparicin (es

using System;

public class Ejemplo_04_04_04a


{
public static void Main()
{
string saludo = "Hola";
string subcadena = saludo.Substring(1,3);
Console.WriteLine("Una subcadena de {0} es {1}",
saludo, subcadena);
}

if (nombre.IndexOf("Juan", 5, 15) >= 0) ...

antes con un tercer parmetro opcional:

La bsqueda termina al final de la cadena, salvo que indiquemos que termine

if (nombre.IndexOf("Juan", 5) >= 0) ...

que queremos buscar:

Podemos aadir un segundo parmetro opcional, que es la posicin a partir de la

if (nombre.IndexOf("Juan") >= 0) Console.Write("Bienvenido, Juan");

devuelve el valor -1, si no aparece):

de"), que nos dice en qu posicin se encuentra, siendo 0 la primera posicin (o

Para ver si una cadena contiene un cierto texto, podemos usar IndexOf ("posicin

4.4.5. Buscar en una cadena

Juan

Jua

Ju

pantalla:

tringulo creciente. Por ejemplo, si tu nombre es "Juan", debera aparecer en

(4.4.4.2) Un programa que te pida tu nombre y lo muestre en pantalla como un

a n".

"Substring". Por ejemplo, si tu nombre es "Juan", debera aparecer en pantalla "J u

cada letra de la siguiente con un espacio, similar al 4.4.3.1, pero esta vez usando

(4.4.4.1) Un programa que te pida tu nombre y lo muestre en pantalla separando

Ejercicios propuestos:

Introduccin a la programacin con C#, por Nacho Cabanes

// Ejemplo_04_04_04a.cs
// Cadenas de texto (4: substring)
// Introduccin a C#, por Nacho Cabanes

indicada hasta el final de la cadena.

Podemos omitir el segundo nmero, y entonces se extraer desde la posicin

saludo = frase.Substring(0,4);

caracteres que queremos obtener. El resultado ser otra cadena:

dos parmetros: la posicin a partir de la que queremos empezar y la cantidad de

Podemos extraer parte del contenido de una cadena con "Substring", que recibe

4.4.4. Extraer una subcadena

letra a letra.

(por ejemplo, de 30 cifras), que se debern pedir como cadena de texto y analizar

(4.4.3.5) Un programa capaz de multiplicar dos nmeros enteros muy grandes

a letra.

ejemplo, de 30 cifras), que se debern pedir como cadena de texto y analizar letra

(4.4.3.4) Un programa capaz de sumar dos nmeros enteros muy grandes (por

finalmente diga si aparece esa letra como parte de esa frase o no.

(4.4.3.3) Un programa que pida al usuario una frase, despus una letra y

(de la ltima letra a la primera).

(4.4.3.2) Un programa que pida una frase al usuario y la muestra en orden inverso

debera aparecer en pantalla "J u a n".

cada letra de la siguiente con un espacio. Por ejemplo, si tu nombre es "Juan",

(4.4.3.1) Un programa que te pida tu nombre y lo muestre en pantalla separando

Ejercicios propuestos:

Introduccin a la programacin con C#, por Nacho Cabanes

public class Ejemplo_04_04_06a


{

public class Ejemplo_04_04_05a


{
public static void Main()
{
string saludo = "Hola";
string subcadena = "ola";
Console.WriteLine("{0} aparece dentro de {1} en la posicin {2}",
subcadena, saludo, saludo.IndexOf(subcadena) );
}
}

Insert(int posicin, string subcadena): Insertar una subcadena en una cierta

nombre.Replace("Pepe", "Jose");
Revisin 0.99zz Pgina 133

cadena (todas las veces que aparezca) por otra: nombreCorregido =

Replace(string textoASustituir, string cadenaSustituta): Sustituye una

cierta posicin: apellidos = nombreCompleto.Remove(0,6);

Remove(int posicin, int cantidad): Elimina una cantidad de caracteres en

posicin de la cadena inicial: nombreFormal = nombre.Insert(0,"Don");

ToLower() convierte a minsculas: password2 = password.ToLower();

ToUpper() convierte a maysculas: nombreCorrecto = nombre.ToUpper();

El texto es: Hola, que tal estas


La primera letra es: H
Las tres primeras letras son: Hol
La longitud del texto es: 19

Y su resultado sera

Revisin 0.99zz Pgina 134

Console.WriteLine("Si cambiamos ESTAS por ESTAMOS: {0}",


ejemplo.Replace("estas", "estamos"));

Console.WriteLine("Si borramos las 6 primeras letras: {0}",


ejemplo.Remove(0, 6));

una nueva cadena. Por ejemplo:

modificar. Pero s podemos realizar ciertas operaciones sobre ellas para obtener

Console.WriteLine("Si insertamos \", tio\": {0}",


ejemplo.Insert(4,", tio"));

Console.WriteLine("En minsculas: {0}",


ejemplo.ToLower());

Console.WriteLine("En maysculas: {0}",


ejemplo.ToUpper());

Console.WriteLine("La ultima A esta en la posicion: {0}",


ejemplo.LastIndexOf("a"));

Console.WriteLine("La posicion de \"que\" es: {0}",


ejemplo.IndexOf("que"));

Console.WriteLine("La longitud del texto es: {0}",


ejemplo.Length);

Console.WriteLine("Las tres primeras letras son: {0}",


ejemplo.Substring(0,3));

Console.WriteLine("La primera letra es: {0}",


ejemplo[0]);

Console.WriteLine("El texto es: {0}",


ejemplo);

Ya hemos comentado que las cadenas en C# son inmutables, no se pueden

4.4.6. Otras manipulaciones de cadenas

exactamente al principio.

los textos aparezca como subcadena, se avise adems si se encuentra

(4.4.5.2) Crea una versin del ejercicio 4.4.5.1 en la que, en caso de que alguno de

texto introducido sea "fin".

aparece como parte de alguno de los elementos del array. Terminar cuando el

luego le pregunte textos de forma repetitiva, e indique si cada uno de esos textos

(4.4.5.1) Un programa que pida al usuario 10 frases, las guarde en un array, y

using System;

using System;

Ejercicios propuestos:

// Ejemplo_04_04_06a.cs
// Cadenas de texto (6: manipulaciones diversas)
// Introduccin a C#, por Nacho Cabanes

// Ejemplo_04_04_05a.cs
// Cadenas de texto (5: substring)
// Introduccin a C#, por Nacho Cabanes

public static void Main()


{
string ejemplo = "Hola, que tal estas";

Un programa que probara todas estas posibilidades podra ser as:

Introduccin a la programacin con C#, por Nacho Cabanes

Un ejemplo de la utilizacin de IndexOf podra ser:

Introduccin a la programacin con C#, por Nacho Cabanes

posicion de "que" es: 6


ultima A esta en la posicion: 17
maysculas: HOLA, QUE TAL ESTAS
minsculas: hola, que tal estas
insertamos ", tio": Hola, tio, que tal estas
borramos las 6 primeras letras: que tal estas
cambiamos ESTAS por ESTAMOS: Hola, que tal estamos
}

0
1
2
3

=
=
=
=

uno
dos
tres
cuatro

string ejemplo = "uno dos tres cuatro";


char delimitador = ' ';
int i;

public class Ejemplo_04_04_07a


{
public static void Main()
{

using System;

// Ejemplo_04_04_07a.cs
// Cadenas de texto: partir con "Split"
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 135

los fragmentos de la cadenam usando el separador que le indiquemos, as:

Afortunadamente, C# nos permite hacerlo con Split, que crea un array a partir de

especialmente sencillo.

subcadenas que hay entre cada dos espacios y las guardaramos en el array. No es

dos espacios, tendremos tres palabras). En una segunda pasada, obtendremos las

saber el tamao del array que deber almacenar las palabras (por ejemplo, si hay

y contando los espacios (o los separadores que nos interesen). As podremos

Si lo queremos hacer "de forma artesanal", podemos recorrer la cadena buscando

separadas por espacios en blanco.

ejemplo, podramos descomponer una frase en varias palabras que estaban

y muestre su suma.

Revisin 0.99zz Pgina 136

(4.4.7.2) Un programa que pida al usuario varios nmeros separados por espacios

orden inverso.

(4.4.7.1) Un programa que pida al usuario una frase y muestre sus palabras en

Ejercicios propuestos:

for (i=0; i<ejemploPartido.Length; i++)


Console.WriteLine("Fragmento {0} = {1}",
i, ejemploPartido[i]);

string [] ejemploPartido = ejemplo.Split(delimitadores);

public class Ejemplo_04_04_07b


{
public static void Main()
{
string ejemplo = "uno,dos.tres,cuatro";
char [] delimitadores = {',', '.'};
int i;

using System;

// Ejemplo_04_04_07b.cs
// Cadenas de texto: partir con "Split" - 2
// Introduccin a C#, por Nacho Cabanes

seran mnimos:

cadena en varios fragmentos que estn delimitados por ciertos separadores. Por

pero tambin la coma, el punto y cualquier otro. Los cambios en el programa

Una operacin relativamente frecuente, pero trabajosa, es descomponer una

caracteres). Por ejemplo, podramos considerar un separador vlido el espacio,

Pero tambin podemos usar como delimitador un conjunto (un array de

Fragmento
Fragmento
Fragmento
Fragmento

Que mostrara en pantalla lo siguiente:

for (i=0; i<ejemploPartido.Length; i++)


Console.WriteLine("Fragmento {0} = {1}",
i, ejemploPartido[i]);

string [] ejemploPartido = ejemplo.Split(delimitador);

Introduccin a la programacin con C#, por Nacho Cabanes

4.4.7. Descomponer una cadena en fragmentos

siguiente).

redundantes que contenga (debe quedar slo un espacio entre cada palabra y la

(4.4.6.2) Un programa que pida al usuario una frase y elimine todos los espacios

minsculas a la hora de buscar.

(4.4.6.1) Una variante del ejercicio 4.4.5.2, que no distinga entre maysculas y

Ejercicios propuestos:

La
La
En
En
Si
Si
Si

Introduccin a la programacin con C#, por Nacho Cabanes

cadenas

maysculas

antes

de

convertir,

bien

empleando

// Compruebo si es mayor o menor


if (frase.CompareTo("hola") > 0)
Console.WriteLine("Es mayor que hola");
else if (frase.CompareTo("hola") < 0)
Console.WriteLine("Es menor que hola");

// Compruebo si es exactamente hola


if (frase == "hola")
Console.WriteLine("Ha escrito hola");

Si tenemos la necesidad de modificar una cadena letra a letra, no podemos usar

Revisin 0.99zz Pgina 138

son algo ms complejos de manejar: hay de reservarles espacio con "new" (igual

Como alternativa, podemos recurrir a un "StringBuilder", que s lo permiten pero

Insert.

de unir varios substring o de borrar un fragmento con Remove y aadir otro con

Deberamos formar una nueva cadena en la que modificsemos esa letra a base

un "string" convencional, porque no es vlido hacer cosas como texto[1]='h';

4.4.9. Una cadena modificable: StringBuilder

muestre la "mayor" de ellas.

(4.4.8.2) Un programa que pida al usuario cinco frases, las guarde en un array y

de ellas (la que aparecera en ltimo lugar en un diccionario).

(4.4.8.1) Un programa que pida al usuario dos frases y diga cual sera la "mayor"

Ejercicios propuestos:

Escriba una palabra


hOLa
Es mayor que hola
Es hola (mays o mins)

minsculas nos dir que coinciden:

"mayores" que las minsculas), y una comparacin sin considerar maysculas o

comparacin normal nos dir que es mayor (las maysculas se consideran

Si escribimos "hOLa", que coincide con "hola" salvo por las maysculas, una

Escriba una palabra


gol
Es menor que hola
Es menor que hola (mays o mins)

est antes de la H de "hola", se nos dir que esa palabra es menor:

Console.WriteLine("Escriba una palabra");


frase = Console.ReadLine();

Revisin 0.99zz Pgina 137

Si tecleamos una palabra como "gol", que comienza por G, que alfabticamente

// Comparo sin distinguir maysculas ni minsculas


bool ignorarMays = true;
if (String.Compare(frase, "hola", ignorarMays) > 0)
Console.WriteLine("Es mayor que hola (mays o mins)");
else if (String.Compare(frase, "hola", ignorarMays) < 0)
Console.WriteLine("Es menor que hola (mays o mins)");
else
Console.WriteLine("Es hola (mays o mins)");

Introduccin a la programacin con C#, por Nacho Cabanes

string frase;

public class Ejemplo_04_04_08a


{
public static void Main()
{

using System;

// Ejemplo_04_04_08a.cs
// Cadenas de texto y comparacin alfabtica
// Introduccin a C#, por Nacho Cabanes

Un programa completo de prueba podra ser as:

if (String.Compare(frase, "hola", true) > 0)


Console.WriteLine("Es mayor que hola (mays o mins)");

ser "true" cuando queramos ignorar esa distincin:

String.Compare, al que indicamos las dos cadenas y un tercer dato booleano, que

ambas

distinguir entre maysculas y minsculas, y eso se puede conseguir convirtiendo

minsculas se consideran diferentes. Es ms habitual que deseemos comparar sin

Esto tiene una limitacin: si lo usamos de esa manera, las maysculas y

if (frase.CompareTo("hola") > 0)
Console.WriteLine("La frase es mayor que hola");

(o un nmero negativo si nuestra cadena es menor, o 0 si son iguales):

mayor que 0 si la nuestra cadena es mayor que la que indicamos como parmetro

cadenas. En su lugar, debemos usar "CompareTo", que devolver un nmero

que" (>) que usamos con los nmeros no se puede aplicar directamente a las

otra, y eso algo que es necesario si queremos ordenar textos. El operador "mayor

operador de igualdad (==), pero no sabemos comparar qu cadena es "mayor" que

Sabemos comprobar si una cadena tiene exactamente un cierto valor, con el

4.4.8. Comparacin de cadenas

Introduccin a la programacin con C#, por Nacho Cabanes

par de letras, usando "foreach".


(4.5.2) Un programa que pida al usuario una frase y la descomponga en
subcadenas separadas por espacios, usando "Split". Luego debe mostrar cada
subcadena en una lnea nueva, usando "foreach".
(4.5.3) Un programa que pida al usuario varios nmeros separados por espacios y
muestre su suma (como el del ejercicio 4.4.7.2), pero empleando "foreach".

minsculas y las de las posiciones pares estn en maysculas, mostrando el

resultado en pantalla. Por ejemplo, a partir de un nombre como "Nacho", la

cadena resultante sera "nAcHo".

(4.4.9.3) Crea un juego del ahorcado, en el que un primer usuario introduzca la

palabra a adivinar, se muestre sta oculta con guiones (-----) y el programa acepte

Revisin 0.99zz Pgina 139

los siguientes datos: Nombre del fichero, Tamao (en KB, un nmero de 0 a
siguientes operaciones:
Revisin 0.99zz Pgina 140

8.000.000.000). El programa mostrar un men que permita al usuario las

de hasta 1000 ficheros (archivos de ordenador). Para cada fichero, debe guardar

adelante).

Se usa con el formato "foreach (variable in ConjuntoDeValores)":

La idea va a ser la siguiente: Crearemos un programa que pueda almacenar datos

de datos, como los arrays y las cadenas de texto (y otras que veremos ms

que adems manipule cadenas.

Vamos a hacer un ejemplo completo que use tablas ("arrays"), registros ("struct") y

Existe una construccin parecida a "for", pensada para recorrer ciertas estructuras

4.5. Recorriendo arrays y cadenas con "foreach"

se acierte la palabra por completo o el usuario agote sus 8 intentos.

correctas cada vez que acierte (por ejemplo, a---a-t-). La partida terminar cuando

4.6. Ejemplo completo

(4.5.1) Un programa que pida tu nombre y lo muestre con un espacio entre cada

que las letras de las posiciones impares (primera, tercera, etc.) estn en

las letras que introduzca el segundo usuario, cambiando los guiones por letras

Ejercicios propuestos:

(4.4.9.2) Un programa que pida una cadena al usuario y la modifique, de modo

string saludo = "Hola";


foreach(char letra in saludo) {
Console.Write("{0}-", letra);
}
Console.WriteLine();

string[] nombres = {"Alberto", "Andrs", "Antonio"};


foreach(string nombre in nombres) {
Console.Write(" {0}", nombre);
}
Console.WriteLine();

public class Ejemplo_04_05a


{
public static void Main()
{
int[] diasMes = {31, 28, 21};
foreach(int dias in diasMes) {
Console.WriteLine("Dias del mes: {0}", dias);
}

using System;

// Ejemplo_04_05a.cs
// Ejemplo de "foreach"
// Introduccin a C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

que todas las vocales se conviertan en "o".

(4.4.9.1) Un programa que pida una cadena al usuario y la modifique, de modo

Ejercicios propuestos:

string cadenaNormal;
cadenaNormal = cadenaModificable.ToString();
Console.WriteLine("Cadena normal a partir de ella: {0}",
cadenaNormal);

public class Ejemplo_04_04_09a


{
public static void Main()
{
StringBuilder cadenaModificable = new StringBuilder("Hola");
cadenaModificable[0] = 'M';
Console.WriteLine("Cadena modificada: {0}",
cadenaModificable);

using System;
using System.Text; // Usaremos un System.Text.StringBuilder

// Ejemplo_04_04_09a.cs
// Cadenas modificables con "StringBuilder"
// Introduccin a C#, por Nacho Cabanes

cadena "convencional" usando "ToString":

que hacamos en ciertas ocasiones con los Arrays), y se pueden convertir a una

Introduccin a la programacin con C#, por Nacho Cabanes

// Ejemplo_04_06a.cs
// Tabla con muchos struct y men para manejarla
// Introduccin a C#, por Nacho Cabanes

Con todo esto, nuestro fuente quedara as:

Revisin 0.99zz Pgina 141

aadir, deberamos asegurarnos antes de que todava tenemos hueco disponible.

consideracin: hemos limitado el nmero de fichas a 1000, as que, si nos piden

comprobar varias opciones con "switch", etc. Aun as, haremos una ltima

El resto del programa no es difcil: sabemos leer y comparar textos y nmeros,

programador en un lenguaje como C#).

(esta segunda alternativa es la que se suele considerar "ms natural" para un

for (i=0; i<n; i++) { /* ... ms rdenes ... */ }

o bien algo como

for (i=0; i<=n-1; i++) { /* ... ms rdenes ... */ }

posicin 0 hasta la n-1, haciendo algo como

Por otra parte, para revisar todas las fichas existentes, recorreremos desde la

nueva ficha en la posicin "n".

aadiremos en la posicin 2; en general, si tenemos "n" fichas, aadiremos cada

primera) en la posicin 0; si tenemos dos fichas, sern la 0 y la 1, luego

ira la siguiente: si tenemos 0 fichas, deberemos almacenar la siguiente (la

el nmero de fichas que tenemos almacenadas, y as sabremos en qu posicin

espacio para 1000 datos, pero iremos aadiendo de uno en uno. Basta con contar

La nica complicacin real es que el array no estar completamente lleno: habr

(incluso se debera) hacer.

podra plantear y luego comentaremos alguna de las mejoras que se podra

No debera resultar difcil. Vamos a ver directamente una de las formas en que se

5- Salir de la aplicacin (como no usamos ficheros, los datos se perdern).

4- Ver todos los datos de un cierto fichero (a partir de su nombre)

3- Mostrar ficheros que sean de ms de un cierto tamao (por ejemplo, 2000 KB).

2- Mostrar los nombres de todos los ficheros almacenados

1- Aadir datos de un nuevo fichero

Introduccin a la programacin con C#, por Nacho Cabanes

// Nombre del fichero


// El tamao en KB

Revisin 0.99zz Pgina 142

case 3: // Mostrar segn el tamao


Console.WriteLine("A partir de que tamao quieres ver?");
tamanyoBuscar = Convert.ToInt64( Console.ReadLine() );
for (i=0; i<numeroFichas; i++)
if (fichas[i].tamanyo >= tamanyoBuscar)
Console.WriteLine("Nombre: {0}; Tamao: {1} KB",

case 2: // Mostrar todos


for (i=0; i<numeroFichas; i++)
Console.WriteLine("Nombre: {0}; Tamao: {1} KB",
fichas[i].nombreFich, fichas[i].tamanyo);
break;

case 1: // Aadir un dato nuevo


if (numeroFichas < 1000) { // Si queda hueco
Console.WriteLine("Introduce el nombre del fichero: ");
fichas[numeroFichas].nombreFich = Console.ReadLine();
Console.WriteLine("Introduce el tamao en KB: ");
fichas[numeroFichas].tamanyo = Convert.ToInt32(
Console.ReadLine() );
// Y ya tenemos una ficha ms
numeroFichas++;
} else // Si no hay hueco para ms fichas, avisamos
Console.WriteLine("Mximo de fichas alcanzado (1000)!");
break;

// Hacemos una cosa u otra segn la opcin escogida


switch(opcion) {

opcion = Convert.ToInt32( Console.ReadLine() );

do {
// Menu principal, repetitivo
Console.WriteLine();
Console.WriteLine("Escoja una opcin:");
Console.WriteLine("1.- Aadir datos de un nuevo fichero");
Console.WriteLine("2.- Mostrar los nombres de todos los ficheros");
Console.WriteLine("3.- Mostrar ficheros por encima de un cierto
tamao");
Console.WriteLine("4.- Ver datos de un fichero");
Console.WriteLine("5.- Salir");

public static void Main() {


tipoFicha[] fichas // Los datos en si
= new tipoFicha[1000];
int numeroFichas=0; // Nmero de fichas que ya tenemos
int i;
// Para bucles
int opcion;
// La opcion del menu que elija el usuario
string textoBuscar; // Para cuando preguntemos al usuario
long tamanyoBuscar; // Para buscar por tamao

struct tipoFicha {
public string nombreFich;
public long tamanyo;
};

public class Ejemplo_04_06a {

using System;

Introduccin a la programacin con C#, por Nacho Cabanes

default: // Otra opcion: no vlida


Console.WriteLine("Opcin desconocida!");
break;
}
} while (opcion != 5); // Si la opcion es 5, terminamos

case 5: // Salir: avisamos de que salimos */


Console.WriteLine("Fin del programa");
break;

separados por comas.


Revisin 0.99zz Pgina 143

almacene en un "struct" y luego muestre los tres datos en una misma lnea,

(4.6.1) Un programa que pida el nombre, el apellido y la edad de una persona, los

Ejercicios propuestos:

ficheros.

tecleado, pero eso es lo nico "casi inevitable", porque an no sabemos manejar

cuando salgamos del programa se borrarn todos los datos que habamos

ocurrir muchas ms preguntas que hacerle sobre nuestros datos. Y adems,

ejemplo, una pausa tras mostrar cada 25 datos). Por descontado, se nos pueden

que sera deseable que parase cuando se llenase la pantalla de informacin (por

ocurrir que aparezcan en pantalla tan rpido que no nos d tiempo a leerlos, as

Si nos muestra todos los datos en pantalla y se trata de muchos datos, puede

informacin que slo esos dos apartados de ejemplo que hemos previsto esta vez.

Por supuesto, en un caso real es habitual que cada ficha tenga que guardar ms

Este programa funciona, y hace todo lo que tiene que hacer, pero es mejorable.

fuente ser ms legible con tabulaciones de 4 espacios en vez de 2).

una pgina; recuerda que puedes usar estilo Java si lo prefieres, pero en general el

espacios, en vez de 4, para ocupar menos espacio en papel y caber en el ancho de

anteriores, abre las llaves al final de cada lnea -estilo Java- y usa tabulaciones de 2

(Como quiz hayas notado, este fuente, que es un poco ms largo que los

fichas[
[i].nombreFich, fichas[i].tamanyo);

case 4: // Ver todos los datos (pocos) de un fichero


Console.WriteLine("De qu fichero quieres ver todos los datos?");
textoBuscar = Console.ReadLine();
for (i=0; i<numeroFichas; i++)
if ( fichas[i].nombreFich == textoBuscar )
Console.WriteLine("Nombre: {0}; Tamao: {1} KB",
fichas[i].nombreFich, fichas[i].tamanyo);
break;

break;

Introduccin a la programacin con C#, por Nacho Cabanes

Mostrar las personas de una cierta edad.


Mostrar las personas cuya inicial sea la que el usuario indique.
Salir del programa

x
x
x

apartado tienes algunos), y aplicarlo a este caso concreto.

Revisin 0.99zz Pgina 144

mtodo de ordenacin sencillo, como el "mtodo de burbuja" (en el siguiente

ordenar los datos por nombre. Para ello, debers buscar informacin sobre algn

(4.6.9) Ampliar la base de datos de ficheros (ejemplo 04_06a) para que se permita

cadena vaca.

indicar que no desea modificar un cierto dato, en vez de reemplazarlo por una

esa modificacin, se deber permitir al usuario pulsar Intro sin teclear nada, para

modificar un cierto dato a partir de su nmero (por ejemplo, el dato nmero 3). En

(4.6.8) Mejorar la base de datos de ficheros (ejemplo 04_06a) para que se pueda

despus de ese, y disminuir el contador de la cantidad de datos que tenemos).

borrar un cierto dato (habr que "mover hacia atrs" todos los datos que haba

(4.6.7) Ampliar la base de datos de ficheros (ejemplo 04_06a) para que se pueda

despus "jua" y finalmente "juan").

los datos que lo contienen (por ejemplo, primero los que contienen "j", luego "ju",

usuario ir indicando letra a letra el texto que quiere buscar, y se mostrar todos

(4.6.6) Ampliar el ejercicio anterior (4.6.5) para que la bsqueda sea incremental: el

ayuda de ToUpper o ToLower).

"IndexOf"). Esta bsqueda no debe distinguir maysculas y minsculas (con la

muestre todos los ficheros que contienen ese fragmento (usando "Contains" o

opcin de bsqueda parcial, en la que el usuario indique parte del nombre y se

(4.6.5) Ampliar la base de datos de ficheros (ejemplo 04_06a) para que incluya una

introducir tamaos incorrectos (nmeros negativos) ni nombres de fichero vacos.

(4.6.4) Mejorar la base de datos de ficheros (ejemplo 04_06a) para que no permita

(lgicamente, este men debe repetirse hasta que se escoja la opcin de "salir").

Mostrar la lista de todos los nombres.

pulse Intro sin teclear nada). Entonces deber aparecer un men que permita:

pidiendo los datos uno por uno, hasta que un nombre se introduzca vaco (se

nombre, direccin, telfono, edad (usando una tabla de structs). Deber ir

(4.6.3) Un programa que sea capaz de almacenar los datos de 50 personas:

mes. Terminar de repetirse cuando se teclee 0 como nmero de mes.

mostrar en pantalla los datos de las personas que cumplan los aos durante ese

structs). Despus deber repetir lo siguiente: preguntar un nmero de mes y

mes de nacimiento, y ao de nacimiento (que se deben almacenar en un array de

(4.6.2) Un programa que pida datos de 8 personas: nombre, dia de nacimiento,

Introduccin a la programacin con C#, por Nacho Cabanes

Para i=1 hasta n-1


menor = i
Para j=i+1 hasta n
Si A[j] < A[menor]
menor = j
Si menor <> i
Intercambiar ( A[i], A[menor])

Revisin 0.99zz Pgina 145

(En cada pasada busca el menor, y lo intercambia al final de la pasada)

Seleccin directa

Para i=n descendiendo hasta 2


Para j=2 hasta i
Si A[j-1] > A[j]
Intercambiar ( A[j-1], A[j])

(Nota: algunos autores hacen el bucle exterior creciente y otros decreciente, as:)

Para i=1 hasta n-1


Para j=i+1 hasta n
Si A[i] > A[j]
Intercambiar ( A[i], A[j])

(Intercambiar cada pareja consecutiva que no est ordenada)

Mtodo de burbuja

ejemplo que los pruebe:

apariencia que tiene el algoritmo, y luego juntando los tres mtodos en un

Veremos tres de estos mtodos simples de ordenacin, primero mirando la

cuales comentaremos ms adelante.

mtodos claramente ms efectivos, pero ms difciles de programar, alguno de los

no repasar todos los datos si ya estaban parcialmente ordenados), as como

Existen ligeras mejoras (por ejemplo, cambiar uno de los "for" por un "while", para

necesarias un milln de comparaciones (1.000 x 1.000).

datos existen. Por tanto, para un array con 1.000 datos, podran llegar ser

pasada quede ordenado un nico dato, y habr que dar dan tantas pasadas como

mayora de ellos se basan en dos bucles "for" anidados, de modo que en cada

eficientes, pero son fciles de programar. La falta de eficiencia se refiere a que la

conseguirlo, existen varios algoritmos sencillos, que no son especialmente

Es muy frecuente querer ordenar datos que tenemos en un array. Para

4.7. Ordenaciones simples

Introduccin a la programacin con C#, por Nacho Cabanes

if (datos[i] > datos[j])

for(j=i+1; j < n; j++)


{

Revisin 0.99zz Pgina 146

// BURBUJA
// (Intercambiar cada pareja consecutiva que no est ordenada)
// Para i=1 hasta n-1
//
Para j=i+1 hasta n
//
Si A[i] > A[j]
//
Intercambiar ( A[i], A[j])
Console.WriteLine("Ordenando mediante burbuja... ");
for(i=0; i < n-1; i++)
{
foreach (int dato in datos) // Muestro datos
Console.Write("{0} ",dato);
Console.WriteLine();

int[] datos = {5, 3, 14, 20, 8, 9, 1};


int i,j,datoTemporal;
int n=7; // Numero de datos

public static void Main()


{

public class Ejemplo_04_07a


{

using System;

// Ejemplo_04_07a.cs
// Ordenaciones simples
// Introduccin a C#, por Nacho Cabanes

Un programa de prueba podra ser:

slo al final de cada pasada, pero no entraremos en ms detalles).

(Es mejorable, no intercambiando el dato que se mueve con cada elemento, sino

Para i=2 hasta n


j=i-1
mientras (j>=1) y (A[j] > A[j+1])
Intercambiar ( A[j], A[j+1])
j = j - 1

desplazarlo hasta su posicin correcta).

(Comparar cada elemento con los anteriores -que ya estn ordenados- y

Insercin directa

saldra a ser algo como "if (menor !=i)"

distinto de otro, de modo que equivale al "!=" de C#. La penltima lnea en C#

Nota: el smbolo "<>" se suele usar en pseudocdigo para indicar que un dato es

Introduccin a la programacin con C#, por Nacho Cabanes

foreach (int dato in datos2) // Muestro datos finales


Console.Write("{0} ",dato);
Console.WriteLine();

}
Console.Write("Ordenado:");

if (i != menor)
{
datoTemporal = datos2[i];
datos2[i] = datos2[menor];
datos2[menor] = datoTemporal;
}

int menor = i;
for(j=i+1; j < n; j++)
if (datos2[j] < datos2[menor])
menor = j;

// Para i=1 hasta n-1


//
menor = i
//
Para j=i+1 hasta n
//
Si A[j] < A[menor]
//
menor = j
//
Si menor <> i
//
Intercambiar ( A[i], A[menor])
Console.WriteLine("Ordenando mediante seleccin directa... ");
int[] datos2 = {5, 3, 14, 20, 8, 9, 1};
for(i=0; i < n-1; i++)
{
foreach (int dato in datos2) // Muestro datos
Console.Write("{0} ",dato);
Console.WriteLine();

// SELECCIN DIRECTA:
// (En cada pasada busca el menor, y lo intercambia al final de la

foreach (int dato in datos) // Muestro datos finales


Console.Write("{0} ",dato);
Console.WriteLine();

Revisin 0.99zz Pgina 147

// INSERCION DIRECTA:
// (Comparar cada elemento con los anteriores -que ya estn
ordenados// y desplazarlo hasta su posicin correcta).
// Para i=2 hasta n
//
j=i-1
//
mientras (j>=1) y (A[j] > A[j+1])
//
Intercambiar ( A[j], A[j+1])
//
j = j - 1
Console.WriteLine("Ordenando mediante insercin directa... ");

pasada)

datoTemporal = datos[i];
datos[i] = datos[j];
datos[j] = datoTemporal;

}
Console.Write("Ordenado:");

Introduccin a la programacin con C#, por Nacho Cabanes

Ordenando mediante insercin directa...


5 3 14 20 8 9 1
3 5 14 20 8 9 1
3 5 14 20 8 9 1
3 5 14 20 8 9 1
3 5 8 14 20 9 1
3 5 8 9 14 20 1
Ordenado:1 3 5 8 9 14 20

Ordenando mediante seleccin directa...


5 3 14 20 8 9 1
1 3 14 20 8 9 5
1 3 14 20 8 9 5
1 3 5 20 8 9 14
1 3 5 8 20 9 14
1 3 5 8 9 20 14
Ordenado:1 3 5 8 9 14 20

Ordenando mediante burbuja...


5 3 14 20 8 9 1
1 5 14 20 8 9 3
1 3 14 20 8 9 5
1 3 5 20 14 9 8
1 3 5 8 20 14 9
1 3 5 8 9 20 14
Ordenado:1 3 5 8 9 14 20

Y su resultado sera:

Revisin 0.99zz Pgina 148

foreach (int dato in datos3) // Muestro datos finales


Console.Write("{0} ",dato);
Console.WriteLine();

}
Console.Write("Ordenado:");

j = i-1;
while ((j>=0) && (datos3[j] > datos3[j+1]))
{
datoTemporal = datos3[j];
datos3[j] = datos3[j+1];
datos3[j+1] = datoTemporal;
j--;
}

int[
[] datos3 = {5, 3, 14, 20, 8, 9, 1};
for(i=1; i < n; i++)
{
foreach (int dato in datos3) // Muestro datos
Console.Write("{0} ",dato);
Console.WriteLine();

Introduccin a la programacin con C#, por Nacho Cabanes

// Primero generamos datos al azar


Console.Write("Generando... ");
Random r = new Random();
for(i=0; i < n; i++)
datos[i] = r.Next(1, n*2);

public static void Main()


{
const int n = 1000;
int[] datos = new int[n];
int i,j,datoTemporal;

public class Ejemplo_04_07b


{

using System;

// Ejemplo_04_07b.cs
// Bsqueda binaria
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 149

bsqueda lineal har 10 comparaciones o menos. Se podra implementar as:

bsqueda lineal har 500 comparaciones como media, mientras que una

puede suponer una enorme ganancia en velocidad: si tenemos 1.000 datos, una

entre un conjunto de datos que tiene la mitad de tamao que el anterior. Esto

superior (o en la inferior), y as sucesivamente, de modo que cada vez se busca

buscado es mayor que el del punto central, se busca esta vez slo en la mitad

ellos empleando la bsqueda binaria: se comienza por el punto central; si el valor

Una vez que los datos estn ordenados, podemos buscar uno concreto dentro de

encuentre el dato buscado o un un dato mayor que l.

ordenado, la bsqueda no se har hasta el final de los datos, sino hasta que se

usuario pueda "preguntar" si un cierto valor est en el array. Como el array est

(4.7.4) Amplia el ejercicio anterior, para aadir una segunda fase en la que el

separados por espacios en blanco). Terminar cuando el usuario teclee "fin".

aadir cada nuevo dato (todos los datos se mostrarn en la misma lnea,

array, mantenga el array ordenado continuamente y muestre el resultado tras

(4.7.3) Un programa que pida al usuario varios nmeros, los vaya aadiendo a un

">", sino "CompareTo").

alfabticamente (recuerda que para comparar cadenas no podrs usar el smbolo

(4.7.2) Un programa que pida al usuario 5 nombres y los muestre ordenados

ordenados de menor a mayor. Escoge el mtodo de ordenacin que prefieras.

(4.7.1) Un programa que pida al usuario 6 nmeros en coma flotante y los muestre

Ejercicios propuestos:

Introduccin a la programacin con C#, por Nacho Cabanes

{3},"+

2;

Revisin 0.99zz Pgina 150

" centro {4}:{5}",


limiteInferior, limiteSuperior,
datos[limiteInferior], datos[limiteSuperior],
puntoMedio, datos[puntoMedio]);
// Compruebo si hemos acertado
if (datos[puntoMedio] == valorBuscado)
{
Console.WriteLine("Encontrado!");
terminado = true;
}
// O si se ha terminado la bsqueda
else if (limiteInferior == limiteSuperior-1)
{
Console.WriteLine("No encontrado");
terminado = true;
}
// Si no hemos terminado, debemos seguir buscando en una mitad
if ( datos[puntoMedio] < valorBuscado )
limiteInferior = puntoMedio;
else
limiteSuperior = puntoMedio;

// Aviso de dnde buscamos


Console.WriteLine("Buscando entre pos {0} y {1}, valores {2} y

while(! terminado)
{
int puntoMedio = limiteInferior+(limiteSuperior-limiteInferior) /

int limiteInferior = 0;
int limiteSuperior = 999;
bool terminado = false;

// Y comenzamos a buscar
int valorBuscado = 1001;
Console.WriteLine("Buscando si aparece {0}...", valorBuscado);

// Mostramos los datos


foreach (int dato in datos)
Console.Write("{0} ",dato);
Console.WriteLine();

// Luego los ordenamos mediante burbuja


Console..Write("Ordenando... ");
for(i=0; i < n-1; i++)
{
for(j=i+1; j < n; j++)
{
if (datos[i] > datos[j])
{
datoTemporal = datos[i];
datos[i] = datos[j];
datos[j] = datoTemporal;
}
}
}

Introduccin a la programacin con C#, por Nacho Cabanes

en

la

que

nos

encontrar

las

llaves

completos

de

Revisin 0.99zz Pgina 151

4.8. Otros editores ms avanzados: Notepad++ y Geany

separados por espacios en blanco). Terminar cuando el usuario teclee "fin".

aadir cada nuevo dato (todos los datos se mostrarn en la misma lnea,

un array, mantenga el array ordenado continuamente y muestre el resultado tras

ordenar: un programa que pida al usuario varios nmeros, los vaya aadiendo a

(4.7.6) Crea una variante del ejercicio 4.7.3, pero usando esta vez Array.Sort para

Ejercicios propuestos:

foreach (int dato in datos) // Muestro datos finales


Console.Write("{0} ",dato);
Console.WriteLine();

Revisin 0.99zz Pgina 152

permite compilar y ejecutar nuestros programas sin necesidad de salir del editor:

cambio tiene menos "plugins" para ampliar sus funcionalidades) es Geany, que s

Por eso, un segundo editor que puede resultar an ms interesante (aunque a

Run, si tenemos una versin en ingls).

using System;

public class Ejemplo_04_07c


{
public static void Main()
{
int[] datos = {5, 3, 14, 20, 8, 9, 1};
Array.Sort(datos); // Ordeno

compilacin, ya sea volviendo a la pantalla de consola o desde el men Ejecutar (o

El problema de Notepad++ es que sigue siendo necesario teclear la orden de

cdigo, tiene soporte para mltiples ventanas, etc.

bloques

permite tabular y des-tabular

en la que nos encontramos,

emparejadas, realza la lnea

para corregir errores), ayuda

encontramos (lo que es til

columna

muestra el nmero de lnea y

destaca la sintaxis en colores,

Notepad++, que es gratuito,

editor de texto un poco ms avanzado. Por ejemplo, en Windows podemos usar

Ahora que conocemos los fundamentos, puede ser el momento de pasar a un

Introduccin a la programacin con C#, por Nacho Cabanes

// Ejemplo_04_07c.cs
// Array.Sort
// Introduccin a C#, por Nacho Cabanes

problemas...

forma ms corta posible de hacer un ejercicio, sino de que aprendas a resolver

hace todo por nosotros... pero recuerda que no (slo) se trata de que conozcas la

Y no se puede ordenar de forma ms sencilla? S, existe un "Array.Sort" que

medio de la mitad inferior del array, y as sucesivamente.

punto medio del array; si nuestro dato es menor, se vuelve a probar en el punto

lineal (desde el principio), use "bsqueda binaria": se comenzar a comparar con el

(4.7.5) Realiza una variante del ejercicio 4.7.4, que en vez de hacer una bsqueda

Ejercicios propuestos:

Introduccin a la programacin con C#, por Nacho Cabanes

Lo podemos solucionar abriendo un fuente en lenguaje C# y entrando al men


"Construir", en la opcin "Establecer comandos de construccin":

Ejecutar. Es que adems, en caso de error de compilacin, se nos mostrar la lista

de errores y se destacar (con un subrayado rojo) las lneas causantes de esos

Revisin 0.99zz Pgina 153

pgina oficial (geany.org) pero no podremos compilar desde l directamente,

habamos instalado Mono previamente). En Windows es fcil descargarlo desde su

gestor de paquetes (Synaptic o el que sea) y todo suele funcionar a la primera (si

La instalacin de Geany en Linux es trivial: basta descargarlo usando nuestro

resultados:

de nuestro programa se quedar pausada para que podamos comprobar los

Si, por el contrario, todo ha sido correcto, la ventana que nos muestra la ejecucin

Revisin 0.99zz Pgina 154

indique el nombre del ejecutable que habremos obtenido al compilar.

escribiremos la ruta de "mono.exe" seguida por "%e.exe", para que a Mono se le

detallar a Mono el nombre de nuestro fichero actual. En la casilla "Ejecutar",

nuestro compilador Mono (mcs.exe) seguida por "%f" para indicar que hay que

Si queremos utilizar Mono: en la primera casilla, pondremos la ruta completa de

escribir el comando para compilar y la del comando para ejecutar.

Nos aparecer una ventana de la que nos interesan dos casillas: la que permite

porque lo habitual es que no sepa en qu ruta se encuentra nuestro compilador.

No es slo que la barra de herramientas tenga botones para Compilar y para

errores:

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

programas lleguen a ese nivel de complejidad.

Revisin 0.99zz Pgina 155

ampliada, Xamarin Studio), que veremos un poco ms adelante, cuando nuestros

caso de Visual Studio, Sharp Develop y MonoDevelop (o su versin modernizada y

tamao, en los que intervendrn varios ficheros fuente de forma simultnea. Es el

entornos integrados, que usaremos dentro de poco para programas de mayor

el Bloc de Notas. Van desde editores sencillos como Notepad2 o Scite hasta

gastar dinero y que harn tu rutina de programador mucho ms cmoda que con

Por supuesto, existen otros muchos editores gratuitos, que puedes utilizar sin

fichero (costumbre poco recomendable para un fuente de un programa).

correctamente incluso si hubiramos escrito algn espacio en el nombre del

Nota: Las comillas dobles que rodean a "%e.exe" (y a "%f") permiten que se lance

"%e.exe"

lance directamente el ejecutable recin creado:

En este caso, en la casilla "Ejecutar" bastar con escribir "%e.exe", para que se

creemos un fuente en C# desde ese editor.

que configurarlo una vez en Geany y se utilizar automticamente cada vez que

primeros programas, pero una vez que usamos editores ms avanzados, slo hay

Esto habra sido muy trabajoso para compilar desde lnea de comando nuestros

C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc "%f"

nombre del fichero que estamos editando:

con "%f" para decir a Geany que cuando lance el compilador debe indicarle el

compilador se llama "csc.exe", y, al igual que para Mono, la lnea debe terminar

"v2.0.50727" para la versin 2; puede haber varias versiones instaladas). El

una carpeta que indica el nmero de versin de la plataforma .Net (por ejemplo,

o "Framework64" (segn si queremos usar la versin de 32 bits o de 64 bits), en

C:), en la carpeta de Windows, subcarpeta "Microsoft.NET", dentro de "Framework"

incluido con Windows, y que se encontrar en el disco de sistema (habitualmente

De forma alternativa, podemos usar el propio compilador de ".Net" que viene

Introduccin a la programacin con C#, por Nacho Cabanes

Podremos repartir el trabajo, para que cada persona se encargue de

d ese "trozo de programa".


Revisin 0.99zz Pgina 156

muy pronto. Despus, entre llaves indicaremos todos los pasos que queremos que

palabras reservadas, como "public static void", cuyo significado iremos viendo

de unos parntesis vacos, como hacamos con "Main", y precedindolo por ciertas

hecho, la forma bsica de definir una funcin ser indicando su nombre seguido

programa" son funciones, incluyendo el propio cuerpo de programa, Main. De

En C#, al igual que en C y los dems lenguajes derivados de l, todos los "trozos de

5.2. Conceptos bsicos sobre funciones

que ms se usa es el de funciones.

o "funciones". En el lenguaje C y sus derivados (entre los que est C#), el nombre

Esos "trozos" de programa son lo que suele llamar "subrutinas", "procedimientos"

sean ms sencillos).

pronto veremos una alternativa que hace que el reparto y la integracin

individual de cada persona (aunque para proyectos realmente grandes,

realizar un "trozo de programa", y finalmente se integrar el trabajo

Evitaremos mucho cdigo repetitivo.

contener todos los detalles de cmo se hace cada cosa.

El "programa principal" ser ms fcil de leer, porque no necesitar

realizar una funcin breve y concreta.

Cada "trozo de programa" independiente ser ms fcil de programar, al

varias ventajas:

trozos ms pequeos, que sean ms fciles de resolver. Esto nos puede suponer

A partir de ahora vamos a empezar a intentar descomponer los problemas en

mejor forma de actuar cuando se trata de algo ms complicado.

pasos. Esto es razonable cuando los problemas son sencillos, pero puede no ser la

un cierto problema, y hemos creado programas a partir de cada uno de esos

Hasta ahora hemos estado pensando los pasos que deberamos dar para resolver

5.1. Diseo modular de programas: Descomposicin


modular

5. Introduccin a las funciones

Introduccin a la programacin con C#, por Nacho Cabanes

LeerDatosDeFichero();
Revisin 0.99zz Pgina 157

datos simple como las que hicimos en el tema anterior, podra ser simplemente:

Como ejemplo ms detallado, la parte principal de una agenda o de una base de

public static void Main()


{
Saludar();
Console.WriteLine("Nada ms por hoy...");
}

public static void Saludar()


{
Console.Write("Bienvenido al programa ");
Console.WriteLine("de ejemplo");
Console.WriteLine("Espero que ests bien");
}

public class Ejemplo_05_02a


{

using System;

// Ejemplo_05_02a.cs
// Funcion "Saludar"
// Introduccin a C#, por Nacho Cabanes

"Saludar" seran parte de nuestra "class", es decir, el fuente completo sera as:

Un detalle importante: tanto la funcin habitual "Main" como la nueva funcin

As conseguimos que nuestro programa principal sea ms fcil de leer.

public static void Main()


{
Saludar(();

funcin:

Ahora desde dentro del cuerpo de nuestro programa, podramos "llamar" a esa

public static void Saludar(()


{
("Bienvenido al programa ");
Console.Write(
Console.WriteLine(("de ejemplo");
("Espero que ests bien");
Console.WriteLine(
}

mensajes en la pantalla:

Por ejemplo, podramos crear una funcin llamada "Saludar", que escribiera varios

Introduccin a la programacin con C#, por Nacho Cabanes

MostrarMenu();
opcion = PedirOpcion();
switch( opcion ) {
case 1: BuscarDatos(); break;
case 2: ModificarDatos(); break;
case 3: AnadirDatos(); break;
...

Revisin 0.99zz Pgina 158

tomara como "double", que permite mayor precisin... pero a cambio nosotros

como un "float", porque de lo contrario, al ver que tiene cifras decimales, lo

(recordemos que el sufijo "f" sirve para indicar al compilador que trate ese nmero

EscribirNumeroReal(2.3f);

Y esta funcin se podra usar desde el cuerpo de nuestro programa as:

public static void EscribirNumeroReal( float n )


{
Console.WriteLine( n.ToString("#.###") );
}

interese (que podra ser con exactamente 3 decimales). Lo podramos hacer as:

resultar til crear una funcin auxiliar que nos los muestre con el formato que nos

Por ejemplo, si escribimos en pantalla nmeros reales con frecuencia, nos puede

nombre.

uno de ellos, deberemos indicar su tipo de datos (por ejemplo "int") y luego su

del parntesis que sigue al nombre de la funcin, separados por comas. Para cada

que queremos que trabaje. Los llamaremos "parmetros" y los indicaremos dentro

Es muy frecuente que nos interese indicarle a nuestra funcin ciertos datos con los

5.3. Parmetros de una funcin

precedidas por la palabra "static").

entre varias funciones debern estar fuera de todas ellas, y debern estar

modo que el "Main" sea breve y ms legible (Pista: las variables que se compartan

(5.2.3) Descompn en funciones la base de datos de ficheros (ejemplo 04_06a), de

formato por 3 filas con 3 asteriscos cada una. Incluye un "Main" para probarla.

(5.2.2) Crea una funcin llamada "DibujarCuadrado3x3", que dibuje un cuadrado

25 lneas en blanco. Crea tambin un "Main" que permita probarla.

(5.2.1) Crea una funcin llamada "BorrarPantalla", que borre la pantalla dibujando

Ejercicios propuestos:

do {

Introduccin a la programacin con C#, por Nacho Cabanes

funciones deban comenzar con una letra minscula.

lenguaje Java es habitual seguir el convenio de que los nombres de las

palabra "public"). Este criterio depende del lenguaje. Por ejemplo, en

alternativas y el motivo para usarlas, nuestras funciones comienzan con la

por una letra mayscula (y recordemos que, hasta que conozcamos las

En C# se recomienda que los elementos pblicos se escriban comenzando

verbo.

Ya que las funciones expresan acciones, en general su nombre ser un

del ancho y alto que se indiquen como parmetros. Incluye un Main para probarla.

Revisin 0.99zz Pgina 159

Revisin 0.99zz Pgina 160

acostumbrados a manejar: s devuelven un valor, que es el resultado de una

Pero eso no es lo que ocurre con las funciones matemticas que estamos

public class Ejemplo_05_03b


{

public static void EscribirSuma( int a, int b )

"Saludar".

como hacamos hasta ahora con "Main" y como hicimos con nuestra funcin

podemos hacerlo indicando al principio que el tipo de datos va a ser "void" (nulo),

Cuando queremos dejar claro que una funcin no tiene que devolver ningn valor,

5.4. Valor devuelto por una funcin. El valor "void"

using System;

// Ejemplo_05_03b.cs
// Funcion "EscribirSuma"
// Introduccin a C#, por Nacho Cabanes

parmetros podra ser:

De modo que un programa completo de ejemplo para una funcin con dos

Main que pida esos datos al usuario y dibuje el rectngulo.

una letra que tambin se indique como parmetro. Completa el programa con un

rectngulo hueco del ancho y alto que se indiquen como parmetros, formado por

(5.3.3) Crea una funcin "DibujarRectanguloHueco" que dibuje en pantalla un

(5.3.2) Crea una funcin "DibujarRectangulo" que dibuje en pantalla un rectngulo

separarlos entre comas:

public static void EscribirSuma( int a, int b )


{
...
}

Main que permita probarla.

tipo y el nombre para cada uno de ellos (incluso si todos son del mismo tipo), y

del ancho (y alto) que se indique como parmetro. Completa el programa con un

(5.3.1) Crea una funcin "DibujarCuadrado" que dibuje en pantalla un cuadrado

Ejercicios propuestos:

Como se ve en estos ejemplos, se suele seguir un par de convenios:

Como ya hemos anticipado, si hay ms de un parmetro, deberemos indicar el

x= 5.1f;
Console.WriteLine("El primer numero real es: ");
EscribirNumeroReal(x);
Console.WriteLine(" y otro distinto es: ");
EscribirNumeroReal(2.3f);

public static void Main()


{
float x;

public static void EscribirNumeroReal( float n )


{
Console.WriteLine( n.ToString("#.###") );
}

public class Ejemplo_05_03a


{

using System;

// Ejemplo_05_03a.cs
// Funcion "EscribirNumeroReal"
// Introduccin a C#, por Nacho Cabanes

Console.Write( a+b );

Introduccin a la programacin con C#, por Nacho Cabanes

public static void Main()


{
Console.Write("La suma de 4 y 7 es: ");
EscribirSuma(4, 7);
}

pasando un dato "double" a una funcin que espera un "float").

El programa completo podra quedar as:

tendramos un mensaje de error en nuestro programa, diciendo que estamos

Introduccin a la programacin con C#, por Nacho Cabanes

public static void Main()


{
int numero;
int resultado;

public static int Cuadrado ( int n )


{
return n*n;
}

public class Ejemplo_05_04a


{

using System;

// Ejemplo_05_04a.cs
// Funcion "Cuadrado"
// Introduccin a C#, por Nacho Cabanes

Un programa ms detallado de ejemplo podra ser:

nombre expresa qu operacin se va a realizar en la funcin.

Revisin 0.99zz Pgina 161

la funcin sea un verbo. El programa debera ser suficientemente legible si el

En general, en las operaciones matemticas, no ser necesario que el nombre de

resultado = Cuadrado( 5 );

una variable, as:

Podramos usar el resultado de esa funcin como si se tratara de un nmero o de

hasta que avancemos un poco ms.

nmero entero. Eso s, todas nuestras funciones seguirn siendo "public static"

En este caso, nuestra funcin no es "void", sino "int", porque va a devolver un

public static int Cuadrado ( int n )


{
return n*n;
}

as:

ejemplo, podramos crear una funcin para elevar un nmero entero al cuadrado

clculos, para poderlo usar desde cualquier otra parte de nuestro programa. Por

una serie de clculos y nos "devuelvan" (return, en ingls) el resultado de esos

De igual modo, para nosotros tambin ser habitual crear funciones que realicen

nmero).

operacin (por ejemplo, la raz cuadrada de un nmero tiene como resultado otro

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 162

texto. Prueba esta funcin para calcular la primera letra de la frase "Hola".

(5.4.4) Crea una funcin "Inicial", que devuelva la primera letra de una cadena de

cero.

nmero entero con el valor: -1 si el nmero es negativo, 1 si es positivo o 0 si es

(5.4.3) Crea una funcin llamada "Signo", que reciba un nmero real, y devuelva un

que recibir como parmetros. El resultado ser otro nmero entero.

(5.4.2) Crea una funcin "Menor" que calcule el menor de dos nmeros enteros

funcin para calcular el cubo de 3.2 y el de 5.

se indique como parmetro. El resultado deber ser otro nmero real. Prueba esta

(5.4.1) Crea una funcin "Cubo" que calcule el cubo de un nmero real (float) que

Ejercicios propuestos:

string ejemplo = "Aqu no llegamos";


return ejemplo;

public static string Inalcanzable()


{
return "Aqu s llegamos";

"cdigo inalcanzable", como en el siguiente ejemplo:

hacer que una funcin mal diseada haga que el compilador nos d un aviso de

En cuanto se alcance un "return", se sale de la funcin por completo. Eso puede

Como se ve en este ejemplo, una funcin puede tener ms de un "return".

public static float Mayor ( float n1, float n2 )


{
if (n1 > n2)
return n1;
else
return n2;
}

dos nmeros reales as:

segundo ejemplo, podemos hacer una funcin que nos diga cul es el mayor de

Podremos devolver cualquier tipo de datos, no slo nmeros enteros. Como

numero=
= 5;
resultado = Cuadrado(numero);
Console.WriteLine("El cuadrado del numero {0} es {1}",
numero, resultado);
Console.WriteLine(" y el de 3 es {0}", Cuadrado(3));

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 163

que calcule la potencia de un nmero entero (un nmero elevado a otro), y el

Vamos a ver el uso de variables locales con un ejemplo. Crearemos una funcin

"atributos"

"variables globales" sino datos especficos del problema, que llamaremos

que muchas veces tendremos datos compartidos, que no sern realmente

negativos de esas variables que se comparten entre varias funciones, adems de

el hecho de descomponer un programa en varias clases minimiza los efectos

otros lenguajes ms antiguos, como C, porque, como veremos en el prximo tema,

Aun as, esta restriccin es menos grave en lenguajes modernos, como C#, que en

parmetros de cada funcin y los valores devueltos, como en el anterior ejemplo.

distintos trozos de programa no es a travs de variables globales, sino usando los

trozo de programa pueda afectar al resto. La forma correcta de pasar datos entre

programa trabaje con sus propios datos, y ayudamos a evitar que un error en un

locales (lo ideal sera que todas lo fueran). As hacemos que cada parte del

En general, deberemos intentar que la mayor cantidad de variables posible sean

cundo no ser necesario).

deber llevar siempre la palabra "static" (dentro de poco veremos el motivo real y

acceder desde cualquier parte. Por ahora, para nosotros, una variable global

todos los "bloques" de programa, ser una "variable global", a la que se podr

Por el contrario, si declaramos una variable al comienzo del programa, fuera de

programa. Es lo que llamaremos "variables locales".

slo ese bloque las conocer, no se podrn usar desde ningn otro bloque del

Las variables se pueden declarar dentro de un bloque (una funcin), y entonces

distinta segn donde las declaremos.

programas tienen varios "bloques", as que las variables se comportarn de forma

Hasta ahora, hemos declarado las variables dentro de "Main". Ahora nuestros

5.5. Variables locales y variables globales

un cuadrado que tenga como lado el nmero que se ha indicado como parmetro.

entero y calcule y muestre en pantalla el valor del permetro y de la superficie de

3 3 3 3 3

Console.WriteLine("{0} elevado a {1} vale {2}",


num1, num2, Potencia(num1,num2));

Console.WriteLine("Introduzca el exponente: ");


num2 = Convert.ToInt32( Console.ReadLine() );

Console.WriteLine("Introduzca la base: ");


num1 = Convert.ToInt32( Console.ReadLine() );

i=5;

obtendramos un

Revisin 0.99zz Pgina 164

modificarlo), slo desde "Main". Este ejemplo no contiene ninguna variable global.

la funcin "potencia" no podemos acceder a su valor (ni para leerlo ni para

mensaje de error. De igual modo, "num1" y "num2" son locales para "Main": desde

"Main" no existen. Si en "Main" intentramos hacer

En este caso, las variables "temporal" e "i" son locales a la funcin "potencia": para

return temporal; // Al final, obtengo el valor que buscaba

public static void Main()


{
int num1, num2;

for(int i=1; i<=nExponente; i++) // Multiplico "n" veces


temporal *= nBase;
// Para aumentar el valor temporal

public static int Potencia(int nBase, int nExponente)


{
int temporal = 1;
// Valor inicial que voy incrementando

public class Ejemplo_05_05a


{

using System;

// Ejemplo_05_05a.cs
// Ejemplo de funcin con variables locales
// Introduccin a C#, por Nacho Cabanes

usaremos la orden "for" para multiplicar tantas veces como haga falta:

cosas como "6 elevado a 100" (o en general nmeros que pueden ser grandes),

(multiplicamos 5 veces el 3 por s mismo). En general, como nos pueden pedir

ser a base de multiplicaciones, es decir:

de texto. Prueba esta funcin para calcular la ltima letra de la frase "Hola".
3 elevado a 5

cuerpo del programa que la use. La forma de conseguir elevar un nmero a otro

(5.4.5) Crea una funcin "UltimaLetra", que devuelva la ltima letra de una cadena

(5.4.6) Crea una funcin "MostrarPerimSuperfCuadrado" que reciba un nmero

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

public class Ejemplo_05_06a


{

using System;

// Ejemplo_05_06a.cs
// Dos variables locales con el mismo nombre
// Introduccin a C#, por Nacho Cabanes

comprobarlo con un ejemplo:

Revisin 0.99zz Pgina 165

Qu ocurre si damos el mismo nombre a dos variables locales distintas? Vamos a

5.6. Los conflictos de nombres en las variables

**

***

****

indicado. Por ejemplo, si la letra es * y la anchura es 4, debera escribir

"tringulo" formado por esa letra, que tenga como anchura inicial la que se ha

(5.5.6) Crea una funcin "Tringulo" que reciba una letra y un nmero, y escriba un

123 la suma sera 6.

devuelva como resultado la suma de sus dgitos. Por ejemplo, si el nmero fuera

(5.5.5) Crea una funcin "SumaCifras" que reciba un numero cualquiera y que

2 veces).

la cadena es "Barcelona" y la letra es 'a', debera devolver 2 (porque la "a" aparece

devuelva la cantidad de veces que dicha letra aparece en la cadena. Por ejemplo, si

(5.5.4) Crea una funcin "ContarLetra", que reciba una cadena y una letra, y

booleano "true" si es un nmero primo o "false" en caso contrario.

(5.5.3) Crea una funcin "EsPrimo", que reciba un nmero y devuelva el valor

el 3 deber llegar desde "3x0=0" hasta "3x10=30").

nmero entero, y escriba la tabla de multiplicar de ese nmero (por ejemplo, para

(5.5.2) Crea una funcin "EscribirTablaMultiplicar", que reciba como parmetro un

Prubalo con un programa que pida al usuario un ao entre 1800 y 2100.

necesario, volvrselo a pedir en caso de error, y devolver un valor correcto.

aceptable. Deber pedir al usuario que introduzca el valor tantas veces como sea

se debe mostrar en pantalla, el valor mnimo aceptable y el valor mximo

(5.5.1) Crea una funcin "PedirEntero", que reciba como parmetros el texto que

Ejercicios propuestos:

una palabra reservada en C#, que no podremos usar como nombre de variable).

(Nota: el parmetro no se llama "base" sino "nBase" porque la palabra "base" es

Introduccin a la programacin con C#, por Nacho Cabanes

public static void Main()


{
Console.WriteLine("n vale {0}", n);
CambiaN();
Console.WriteLine("Ahora n vale {0}", n);
}

public static void CambiaN()


{
n ++;
}

static int n = 7;

public class Ejemplo_05_06b


{

using System;

// Ejemplo_05_06b.cs
// Una variable global
// Introduccin a C#, por Nacho Cabanes

todas ellas:

Revisin 0.99zz Pgina 166

Si la variable es "global", declarada fuera de estas funciones, s ser accesible por

un bloque ("mbito") distinto.

funcionamiento del programa, siguen siendo distintas, porque cada una est en

de "Main". El hecho de que las dos variables tengan el mismo nombre no afecta al

Por qu? Sencillo: tenemos una variable local dentro de "cambiaN" y otra dentro

n vale 5
Ahora n vale 5

El resultado de este programa es:

public static void Main()


{
int n = 5;
Console.WriteLine("n vale {0}", n);
CambiaN();
Console.WriteLine("Ahora n vale {0}", n);
}

public static void CambiaN()


{
int n = 7;
n ++;
}

Introduccin a la programacin con C#, por Nacho Cabanes

dichos datos.

Revisin 0.99zz Pgina 167

modificamos algo, estamos cambiando una copia de los datos originales, no

valor", es decir, la funcin no recibe los datos originales, sino una copia de ellos. Si

Revisin 0.99zz Pgina 168

llamar a una funcin que tenga parmetros por referencia si los parmetros no

que no existe en otros lenguajes, como los "parmetros de salida". No podemos

de lenguajes de programacin. En el caso de C# existe alguna posibilidad adicional

La posibilidad de pasar parmetros por valor y por referencia existe en la mayora

public static void Intercambia(ref int x, ref int y)

que intercambiara los valores de dos variables:

podramos devolver ms de un dato. Por ejemplo, podramos crear una funcin

Esto se debe a que, si no indicamos otra cosa, los parmetros "se pasan por

devolver un valor de una funcin, pero con parmetros pasados por referencia

esa variable que se ha recibido como parmetro.

posibilidad que no se podra conseguir de otra forma: con "return" slo se puede

El hecho de poder modificar valores que se reciban como parmetros abre una

n vale 5
El valor recibido vale 5
y ahora vale 10
Ahora n vale 10

En este caso s se modifica la variable n:

public static void Main()


{
int n = 5;
Console.WriteLine("n vale {0}", n);
Duplicar(ref n);
Console.WriteLine("Ahora n vale {0}", n);
}

public static void Duplicar(ref int x)


{
Console.WriteLine(" El valor recibido vale {0}", x);
x = x * 2;
Console.WriteLine(" y ahora vale {0}", x);
}

public class Ejemplo_05_07b


{

using System;

Vemos que al salir de la funcin, no se conservan los cambios que hagamos a

n vale 5
El valor recibido vale 5
y ahora vale 10
Ahora n vale 5

El resultado de este programa ser:

public static void Main()


{
int n = 5;
Console.WriteLine("n vale {0}", n);
Duplicar(n);
Console.WriteLine("Ahora n vale {0}", n);
}

public static void Duplicar(int x)


{
Console.WriteLine(" El valor recibido vale {0}", x);
x = x * 2;
Console.WriteLine(" y ahora vale {0}", x);
}

public class Ejemplo_05_07a


{

using System;

// Ejemplo_05_07a.cs
// Modificar una variable recibida como parmetro - acercamiento
// Introduccin a C#, por Nacho Cabanes

ejemplo:

// Ejemplo_05_07b.cs
// Modificar una variable recibida como parmetro - correcto
// Introduccin a C#, por Nacho Cabanes

as:

posiblemente el resultado no ser el que esperamos. Vamos a verlo con un

usando la palabra "ref", tanto en la declaracin de la funcin como en la llamada,

Podemos modificar el valor de un dato que recibamos como parmetro, pero

cambio: indicar que la variable se va a pasar "por referencia", lo que se indica

Si queremos que las modificaciones se conserven, basta con hacer un pequeo

Introduccin a la programacin con C#, por Nacho Cabanes

5.7. Modificando parmetros

Introduccin a la programacin con C#, por Nacho Cabanes

compilando y funcionando igual:


Revisin 0.99zz Pgina 169

que "Main" aparezca en primer lugar y "Duplicar" aparezca despus, y seguira

es necesario en C#. Por ejemplo, podramos rescribir el ejemplo 05_07b, de modo

En algunos lenguajes, una funcin debe estar declarada antes de usarse. Esto no

5.8. El orden no importa

cada vez que queramos obtener valores entre dos extremos:

999 es tomar las milsimas de segundo de la hora actual:


Revisin 0.99zz Pgina 170

Tambin, una forma simple de obtener un nico nmero "casi al azar" entre 0 y

// Generamos un nmero entre dos valores dados


// (el segundo lmite no est incluido)
int aleatorio = generador.Next(1, 101);

// Creamos un objeto Random


Random generador = new Random();

crear un objeto de tipo "Random" (una nica vez), y luego llamaremos a "Next"

funciona correctamente.

Generar nmeros al azar ("nmeros aleatorios") usando C# no es difcil: debemos

usando parmetros por referencia. Crea un "Main" que te permita comprobar que

y devuelva las letras N y C (primera letra, y letra situada tras el primer espacio),

(5.7.2) Crea una funcin "Iniciales", que reciba una cadena como "Nacho Cabanes"

partida no sea exactamente igual a la anterior.

y para un juego s suele ser conveniente que haya algo de azar, para que una

que la pruebe.

se encuentran muchas veces entre los ejercicios de programacin ms completos,

nmeros enteros que se le indiquen como parmetro. Crea tambin un programa

no es habitual que podamos permitir que las cosas ocurran al azar. Pero los juegos

En un programa de gestin o una utilidad que nos ayuda a administrar un sistema,

5.9.1. Nmeros aleatorios

5.9. Algunas funciones tiles

public static void Duplicar(ref int x)


{
Console.WriteLine(" El valor recibido vale {0}", x);
x = x * 2;
Console.WriteLine(" y ahora vale {0}", x);
}

public static void Main()


{
int n = 5;
Console.WriteLine("n vale {0}", n);
Duplicar(ref n);
Console.WriteLine("Ahora n vale {0}", n);
}

public class Ejemplo_05_08a


{

using System;

// Ejemplo_05_08a.cs
// Funcin tras Main
// Introduccin a C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

(5.7.1) Crea una funcin "Intercambiar", que intercambie el valor de los dos

Ejercicios propuestos:

que des valores iniciales a "letra1" y "letra2".

Si pruebas este ejemplo, vers que no compila si cambias "out" por "ref", a no ser

public static void Main()


{
char letra1, letra2;
DosPrimerasLetras("Nacho", out letra1, out letra2);
Console.WriteLine("Las dos primeras letras son {0} y {1}",
letra1, letra2);
}

public static void DosPrimerasLetras(string cadena,


out char l1, out char l2)
{
l1 = cadena[0];
l2 = cadena[1];
}

public class Ejemplo_05_07c


{

using System;

// Ejemplo_05_07c.cs
// Parmetros "out"
// Introduccin a C#, por Nacho Cabanes

letra de una frase sera as:

tienen valor inicial. Por ejemplo, una funcin que devuelva la primera y segunda

Introduccin a la programacin con C#, por Nacho Cabanes

Acos(x): Arco coseno


Asin(x): Arco seno
Atan(x): Arco tangente
Atan2(y,x): Arco tangente de y/x (por si x o y son 0)
Ceiling(x): El valor entero superior a x y ms cercano a l
Cos(x): Coseno
Cosh(x): Coseno hiperblico
Exp(x): Exponencial de x (e elevado a x)
Floor(x): El mayor valor entero que es menor que x
Log(x): Logaritmo natural (o neperiano, en base "e")
Log10(x): Logaritmo en base 10
Pow(x,y): x elevado a y
Round(x, cifras): Redondea un nmero
Sin(x): Seno
Sinh(x): Seno hiperblico
Sqrt(x): Raz cuadrada
Tan(x): Tangente
Tanh(x): Tangente hiperblica

x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x

(5.9.1.3) Mejora el programa del ahorcado (4.4.9.3), para que la palabra a adivinar

Revisin 0.99zz Pgina 171

En C# tenemos muchas funciones matemticas predefinidas, como:

5.9.2. Funciones matemticas

primero rellenes y luego dibujes en pantalla.

array de dos dimensiones (con tamaos 24 para el alto y 79 para el ancho), que

pantalla. Para ayudarte para escribir en cualquier coordenada, puedes usar un

(5.9.1.5) Crea un programa que "dibuje" asteriscos en 100 posiciones al azar de la

azar entre -1000 y 1000. Luego deber calcular y mostrar su media.

(5.9.1.4) Crea un programa que genere un array relleno con 100 nmeros reales al

de palabras prefijadas (por ejemplo, nombres de ciudades).

La potencia: para elevar 2 al cubo haramos y = Math.Pow(2, 3);


El valor absoluto: para trabajar slo con nmeros positivos usaramos n =
Math.Abs(x);
x

Revisin 0.99zz Pgina 172

La raz cuadrada de 4 se calculara haciendo x = Math.Sqrt(4);


x
x

situaciones ms variadas, que casi cualquier programador pueda necesitar:

exponenciales. Pero vamos a destacar las que s pueden resultar tiles en

especialmente si interviene la trigonometra o si hay que usar logaritmos o

La mayora de ellas son especficas para ciertos problemas matemticos,

Todas ellas se usan precedidas por "Math."

PI, el nmero "Pi", 3.14159...


x

no sea tecleada por un segundo usuario, sino que se escoja al azar de un "array"

E, el nmero "e", con un valor de 2.71828...


x

y tambin tenemos una serie de constantes como

funciones trigonomtricas, el ngulo se debe indicar en radianes, no en grados)

(casi todos ellos usan parmetros X e Y de tipo "double"; en el caso de las

Abs(x): Valor absoluto

Introduccin a la programacin con C#, por Nacho Cabanes

usuario tendr 6 oportunidades para acertarlo.

(5.9.1.2) Crea un programa que genere un nmero al azar entre 1 y 100. El

nmero al azar entre 1 y 6.

(5.9.1.1) Crea un programa que imite el lanzamiento de un dado, generando un

Ejercicios propuestos:

public class Ejemplo_05_09_01a


{
public static void Main()
{
Random r = new Random();
int aleatorio = r.Next(1, 11);
Console.WriteLine("Un nmero entre 1 y 10: {0}", aleatorio);
int aleatorio2 = r.Next(10, 21);
Console.WriteLine("Otro entre 10 y 20: {0}", aleatorio2);
}
}

using System;

// Ejemplo_05_09_01a.cs
// Nmeros al azar
// Introduccin a C#, por Nacho Cabanes

Vamos a ver un ejemplo, que muestre en pantalla dos nmeros al azar:

"Random" y llamar dos veces a "Next".

tendran el mismo valor; en ese caso, no habra ms remedio que utilizar

aleatorios a la vez, porque los dos se obtendran en el mismo milisegundo y

Pero esta forma simplificada no sirve si necesitamos obtener dos nmeros

int falsoAleatorio = DateTime.Now.Millisecond;

Introduccin a la programacin con C#, por Nacho Cabanes

seno, coseno y tangente. Recuerda que las funciones trigonomtricas esperan que

"coseno de 45 grados" podra ser:

(x1,y1) y (x2,y2), usando la expresin d = raz [ (x1-x2)2 + (y1-y2)2 ].


Revisin 0.99zz Pgina 173

(5.9.2.6) Crea una funcin "Distancia", que calcule la distancia entre dos puntos

mayor que l o menor que l).

encuentra ms cerca de ese dato en valor absoluto (es decir, el ms prximo, sea

guarde en un array, pida un nuevo dato y muestre el valor del array que se

(5.9.2.5) Crea un programa que pida al usuario 5 datos numricos reales, los

mayor" si ninguno lo es.

encuentra ms cerca de ese dato, siendo mayor que l, o el texto "Ninguno es

guarde en un array, pida un nuevo dato y muestre el valor del array que se

(5.9.2.4) Haz un programa que pida al usuario 5 datos numricos enteros, los

x = -b r raz (b 4ac) / (2a)

calcula con

existe, se devolver como valor 100.000 para esa solucin. Pista: la solucin se

Deber devolver los valores de las dos soluciones x1 y x2. Si alguna solucin no

coeficientes a, b y c (por valor), as como las soluciones x1 y x2 (por referencia).

una funcin "CalcularRaicesSegundoGrado", que recibir como parmetros los

+ bx + c = 0. El usuario deber introducir los valores de a, b y c. Se deber crear

(5.9.2.3) Haz un programa que resuelva ecuaciones de segundo grado, del tipo ax

elevar 2 a 1/3.

(por ejemplo, 3 para la raz cbica). Pista: hallar la raz cbica de 2 es lo mismo que

nmero. El usuario deber indicar el nmero (por ejemplo, 2) y el ndice de la raz

(5.9.2.2) Crea un programa que halle cualquier raz (de cualquier orden) de un

introduzca el usuario. Se repetir hasta que introduzca 0.

(5.9.2.1) Crea un programa que halle (y muestre) la raz cuadrada del nmero que

Ejercicios propuestos:

Console.WriteLine("El coseno de 45 grados es: {0}",


Math.Cos(anguloRadianes));

public class Ejemplo_05_09_02a


{
public static void Main()
{
double anguloGrados = 45;
double anguloRadianes = anguloGrados * Math.PI / 180.0;

using System;

siguen, hasta llegar a uno:


Revisin 0.99zz Pgina 174

Y el factorial de un nmero arbitrario es el producto de ese nmero por los que le

1! = 1

El factorial de 1 es 1:

clsico es el "factorial de un nmero":

Dentro de las matemticas tenemos varios ejemplos de funciones recursivas. Uno

reduciendo la complejidad paso a paso hasta llegar a un caso trivial.

mismo problema. Una funcin recursiva es aquella que se "llama a ella misma",

La recursividad consiste en resolver un problema a partir de casos ms simples del

5.10. Recursividad

otras muchas funciones a medida que avancemos.

Console.WriteLine (que es "void", no devuelve nada). Nos iremos encontrando con

Console.ReadLine (que devuelve la cadena que se ha introducido por teclado) o

que hasta ahora hemos llamado "rdenes", son realmente "funciones", como

palabras reservadas (int, float, string, if, switch, for, do, while...), gran parte de lo

En C# hay muchas ms funciones de lo que parece. De hecho, salvo algunas

5.9.3. Pero hay muchas ms funciones

ejercicio 5.9.1.5 y el 5.9.2.9).

seran (12,40). Recuerda que el ngulo se debe indicar en radianes (mira el

yCentro + radio * seno(ngulo). Si tu array es de 24x79, las coordenadas del centro

dimensiones, usando las ecuaciones x = xCentro + radio * coseno(ngulo), y =

(5.9.2.10) Crea un programa que "dibuje" un crculo dentro de un array de dos

luego dibujes en pantalla (mira el ejercicio 5.9.1.5).

coordenada, puedes usar un array de dos dimensiones, que primero rellenes y

para valores de x entre 0 y 72 grados. Para ayudarte para escribir en cualquier

(5.9.2.9) Crea un programa que "dibuje" la grfica de la funcin y = 10 * seno(x*5),

seno(x*5), para valores de x entre 0 y 72 grados.

(5.9.2.8) Crea un programa que muestre los valores de la funcin y = 10 *

son 2*PI radianes.

el ngulo se indique en radianes, no en grados. La equivalencia es que 360 grados

(5.9.2.7) Crea un programa que pida al usuario un ngulo (en grados) y muestre su

Un ejemplo ms avanzado, usando funciones trigonomtricas, que calculase el

// Ejemplo_05_09_02a.cs
// Ejemplo de funciones trigonometricas
// Introduccin a C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 175

disminuir la complejidad del problema acercndolo a ese caso.

"colgado". Debemos encontrar un "caso trivial" que alcanzar, y un modo de

quede dando vueltas todo el tiempo y deje el ordenador (o la tarea actual)

comprobar que hay salida de la funcin, para que nuestro programa no se

Atencin a la primera parte de la funcin recursiva: es muy importante

Dos consideraciones importantes:

public static void Main()


{
int num;
Console.WriteLine("Introduzca un nmero entero: ");
num = Convert.ToInt32(System.Console.ReadLine());
Console.WriteLine("Su factorial es: {0}", Factorial(num));
}

public static long Factorial(int n)


{
if (n==1)
// Aseguramos que termine (caso base)
return 1;
return n * Factorial(n-1); // Si no es 1, sigue la recursin
}

public class Ejemplo_05_10a


{

using System;

// Ejemplo_05_10a.cs
// Funciones recursivas: factorial
// Introduccin a C#, por Nacho Cabanes

programar as:

Esta es la definicin recursiva del factorial, ni ms ni menos. Esto se podra

n! = n (n-1)!

siguiente nmero:

Entonces podemos escribir el factorial de un nmero a partir del factorial del

(n-1)! = (n-1) (n-2) (n-3) ... 3 2 1

Si pensamos que el factorial de n-1 es

(por ejemplo, el factorial de 4 es 4 3 2 1 = 24)

n! = n (n-1) (n-2) ... 3 2 1

Introduccin a la programacin con C#, por Nacho Cabanes

obtener resultados errneos, si usamos nmeros enteros "normales".

grandes: el factorial de 16 es 2.004.189.184, luego a partir de 17 podemos

Los factoriales crecen rpidamente, as que no conviene poner nmeros

primeras letras, que ocurrira con la de la sexta posicin).

Revisin 0.99zz Pgina 176

cmo pasar del caso "n-1" al caso "n" (por ejemplo, si ya has invertido las 5

base (qu longitud debera tener una cadena para que sea trivial darle la vuelta) y

recursiva se llamar "Invertir(cadena)". Como siempre, analiza cul ser el caso

cadena de caracteres (por ejemplo, a partir de "Hola" devolvera "aloH"). La funcin

(5.10.6) Crea un programa que emplee recursividad para dar la vuelta a una

elementos de un vector. El planteamiento ser muy similar al del ejercicio anterior.

(5.10.5) Crea un programa que emplee recursividad para calcular el mayor de los

primeros).

elemento, cmo podras emplear esta informacin para conocer la suma de los 7

ejemplo, si conoces la suma de los 6 primeros elementos y el valor del sptimo

sumar para que dicha suma sea trivial) y cmo pasar del caso "n-1" al caso "n" (por

hasta). Nuevamente, piensa cul ser el caso base (cuntos elementos podras

usando una funcin recursiva que tendr la apariencia: SumaVector(v, desde,

elementos de un vector de nmeros enteros, desde su posicin inicial a la final,

(5.10.4) Crea un programa que emplee recursividad para calcular la suma de los

cada elemento es la suma de los dos anteriores).

serie Fibonacci (en la que los dos primeros elementos valen 1, y para los restantes,

(5.10.3) Crea un programa que emplee recursividad para calcular un nmero de la

"de forma iterativa"), usando la orden "for".

nmero entero a otro nmero entero de forma NO recursiva (lo que llamaremos

(5.10.2) Como alternativa, crea una funcin que calcule el valor de elevar un

ejemplo, si sabes el valor de 54, cmo hallaras el de 55 a partir de l).

puede calcular de forma trivial) y cmo pasar del caso "n-1" al caso "n" (por

debe crear de forma recursiva. Piensa cul ser el caso base (qu potencia se

nmero entero (por ejemplo, 5 elevado a 3 = 5 3 = 5 5 5 = 125). Esta funcin se

(5.10.1) Crea una funcin que calcule el valor de elevar un nmero entero a otro

Ejercicios propuestos:

recursividad.

ayudarn a descubrir otros ejemplos de situaciones en las que se puede aplicar la

problema se podr expresar de forma recursiva. Los ejercicios propuestos te

se pueden expresar a partir de otro ms sencillo. En muchos de esos casos, ese

Qu utilidad tiene esto? Ms de la que parece: muchos problemas complicados

Introduccin a la programacin con C#, por Nacho Cabanes

un 0 si no ha habido ningn error, u otro cdigo distinto en caso de que s exista

as:

ciertas opciones que le indicamos como argumentos. Por ejemplo, bajo Linux o

le indicamos son "-l" y "*.cs".

Revisin 0.99zz Pgina 177

En este caso, la orden sera "ls", y las dos opciones (argumentos o parmetros) que

ls l *.cs

de ficheros que terminan en .cs haciendo

public static int Main(string[] args)

ha funcionado correctamente u otro cdigo en caso contrario):

Revisin 0.99zz Pgina 178

"return" cuando nos interese (igual que antes, por convenio, devolviendo 0 si todo

declarndolo como "void", sino como "int", y empleando entonces la orden

Una forma alternativa de que "Main" indique errores al sistema operativo es no

IF ERRORLEVEL 1 ECHO Ha habido un error en el programa

y Windows se puede leer desde un fichero BAT o CMD usando "IF ERRORLEVEL",

Es muy frecuente que un programa llamado desde la "lnea de comandos" tenga

cualquier otro sistema operativo de la familia Unix, podemos ver la lista detallada

Este valor se podra comprobar desde el sistema operativo. Por ejemplo, en MsDos

5.11. Parmetros y valor de retorno de "Main"

algn error.

Es decir, entre parntesis indicamos un cierto cdigo, que suele ser (por convenio)

que ordene un array usando este mtodo.

Environment.Exit(1);

como

punto, podemos usar la orden "Environment.Exit". Su manejo habitual es algo

Por otra parte, si queremos que nuestro programa se interrumpa en un cierto

for (int i = 0; i < args.Length; i++)


{
System.Console.WriteLine("El parametro {0} es: {1}",
i, args[i]);
}

la longitud ("Length") del array:

habitualmente un array cuyo tamao no conocemos: con un "for" que termine en

Para conocer esos parmetros lo haramos de la misma forma que se recorre

static void Main(


(string[] args)

Se hace indicando un parmetro especial en Main, un array de strings:

Pues bien, estas opciones que se le pasan al programa se pueden leer desde C#.

Ahora la orden sera "dir", y el parmetro es "*.cs".

dir *.cs

La orden equivalente en MsDos y en el intrprete de comandos de Windows sera

Introduccin a la programacin con C#, por Nacho Cabanes

recursiva es cuando se llega a un array de tamao 0 1. Implementa una funcin

recursiva a Quicksort para cada una de las dos mitades. El caso base de la funcin

queden a su izquierda y los mayores a su derecha; finalmente, se llama de forma

luego se recoloca el array de modo que los elementos menores que el pivote

por tomar un elemento del array, llamado "pivote" (por ejemplo, el punto medio);

siguiente idea: para ordenar un array entre dos posiciones "i" y "j", se comienza

(5.10.11) El algoritmo de ordenacin conocido como "Quicksort", parte de la

ninguna O que permita completar la secuencia en orden.

respuesta sera 1. Si recibes "ohla", la respuesta sera 0, porque tras la H no hay

H con la primera O, o bien la segunda H con la segunda O. Si recibes "hobla", la

con la primera O (y con la L y con la A), la primera H con la segunda O, la segunda

y la subcadena "hola", la respuesta sera 4, porque se podra tomar la primera H

formada a partir de sus letras en orden. Por ejemplo, si recibes la palabra "Hhoola"

devuelva cuntas veces aparece la subcadena en la cadena, como subsecuencia

(5.10.10) Crea una funcin que reciba una cadena de texto, y una subcadena, y

letra a letra. Una funcin debe ser iterativa y la otra debe ser recursiva.

de una cadena. No puedes usar "Contains" ni "IndexOf", sino que debes analizar

(5.10.9) Crea dos funciones que sirvan para saber si un cierto texto es subcadena

< n) ; - Si r = 0, el MCD es n.; - Si no, el mximo comn divisor es MCD(n,r).

entero positivo que divide a ambos: - Dividir m por n para obtener el resto r (0 r

y n, tal que m > n, para encontrar su mximo comn divisor, es decir, el mayor

nmeros usando el algoritmo de Euclides: Dados dos nmeros enteros positivos m

(5.10.8) Crear un programa que encuentre el mximo comn divisor de dos

"DABALEARROZALAZORRAELABAD" es un palndromo.

si una cadena de caracteres es simtrica (un palndromo). Por ejemplo,

(5.10.7) Crea, tanto de forma recursiva como de forma iterativa, una funcin diga

Introduccin a la programacin con C#, por Nacho Cabanes

...
return 0;

Por

valor numrico vlido.

Revisin 0.99zz Pgina 179

cdigo 2 si alguno de los dos nmeros con los que se quiere operar no tiene un

(5.11.4) Crea una variante del ejercicio 5.11.3, en la que Main devuelva tambin el

si la operacin indicada no es vlida o 0 cuando s sea una operacin aceptable.

(5.11.3) Crea una variante del ejercicio 5.11.2, en la que Main devuelva el cdigo 1

Ejemplos de su uso sera "calcula 2 + 3" o "calcula 5 * 60".

multiplicar o dividir los dos nmeros que se le indiquen como parmetros.

(5.11.2) Crea una calculadora bsica, llamada "calcula", que deber sumar, restar,

suficientes datos" y devolver un cdigo de error 1.

responder "2" y si se teclea nicamente "suma" deber responder "no hay

ejemplo, si se teclea "suma 2 3" deber responder "5", si se teclea "suma 2"

nmeros que se le indiquen como parmetros en lnea de comandos.

(5.11.1) Crea un programa llamado "suma", que calcule (y muestre) la suma de dos

Ejercicios propuestos:

return 0;

if (args.Length == 0)
{
Console.WriteLine("No ha indicado ningn parmetro!");
Environment.Exit(1);
}

for (int i = 0; i < args.Length; i++)


{
Console.WriteLine("El parmetro {0} es: {1}",
i, args[i]);
}

public class Ejemplo_05_11a


{
public static int Main(string[] args)
{
Console.WriteLine("Parmetros: {0}", args.Length);

using System;

// Ejemplo_05_11a.cs
// Parmetros y valor de retorno de "Main"
// Introduccin a C#, por Nacho Cabanes

Un ejemplo que pusiera todo esto a prueba podra ser:

Introduccin a la programacin con C#, por Nacho Cabanes

de puntos que obtendremos al "destruir" cada "enemigo":

Revisin 0.99zz Pgina 180

aparece una pantalla de bienvenida, que nos recuerda detalles como la cantidad

hay en un juego como el clsico Space Invaders. Cuando entramos al juego,

Como ejemplo, vamos a dedicar un momento a pensar qu elementos ("objetos")

con otro color.

de la descripcin del problema, y subrayar los nombres con un color y los verbos

Una forma de "descubrir" los objetos que forman parte de un programa es partir

colaboran entre s.

recomendable consiste en tratar de verlo como una serie de "objetos" que

Existen varias formas de descomponer un proyecto, pero posiblemente la ms

detalles internos de otros bloques.

bloque tenga unas responsabilidades claras, y que cada bloque no dependa de los

Esta descomposicin no debe ser arbitraria. Por ejemplo, ser deseable que cada

personas.

en varios subprogramas, de forma que podamos repartir el trabajo entre varias

Cuando tenemos que realizar un proyecto grande, ser necesario descomponerlo

6.1. Por qu los objetos?

6. Programacin orientada a objetos

Introduccin a la programacin con C#, por Nacho Cabanes

analizar con ms detalle:

Revisin 0.99zz Pgina 181

Y cuando comenzamos una partida, veremos una pantalla como sta, que vamos a

Introduccin a la programacin con C#, por Nacho Cabanes

Torre defensiva: destruir (un fragmento, en ciertas coordenadas)


Enemigos : mover, disparar, desaparecer
Ovni : mover
Bloque (formado por enemigos) : mover
Disparo : mover, desaparecer
Marcador : mostrar, reiniciar, incrementar puntos
Partida (contiene nave, enemigos, torres, ovni)

x
x
x
x
x
x
x

Revisin 0.99zz Pgina 182

Nave : mover izquierda, mover derecha, disparar, perder vida


x

siguientes objetos y las siguientes acciones:

De la descripcin subrayada de este juego concreto podemos extraer los

objetos.

en otro color), que indicarn las acciones que puede realizar cada uno de esos

podemos descomponer el problema, y los verbos (con otro rotulador de marcar,

subrayamos con un rotulador de marcar), que indicarn los objetos en los que

A partir de esa descripcin, podemos buscar los nombres (puede ayudar si los

informa de cuntos puntos obtenemos al destruir cada tipo de enemigo.

pasamos por una pantalla de "bienvenida", que muestra una animacin que nos

marcador se reinicia al comienzo de cada partida. Antes de cada "partida",

se ir incrementando) y el rcord (mejor puntuacin hasta el momento). El

disparo. Igualmente, hay un "marcador", que muestra la puntuacin actual (que

lado derecho y nos permite obtener puntuacin extra si le impactamos con un

pantalla, en la parte superior de la pantalla, que se mueve del lado izquierdo al

lo destruye. Adems, en ocasiones aparece un "OVNI" en la parte superior de la

nosotros, perderemos una vida; si un disparo nuestro impacta con un enemigo,

pantalla o cuando impactan con algo. Si un disparo del enemigo impacta con

Tanto nuestro disparo como los de los enemigos desaparecen cuando salen de la

de enemigos, que no se diferencian en su comportamiento, pero s en su imagen.

no de forma independiente, sino como un "bloque". En concreto, hay tres "tipos"

disparan) "enemigos". Adems, estos enemigos se mueven de lado a lado, pero

se destruyen poco a poco cuando les impactan los disparos. Nos atacan (nos

que puede disparar. Nuestra nave se esconde detrs de "torres defensivas", que

Nosotros manejamos una "nave", que se puede mover a izquierda y derecha y

de partida):

posiblemente habra que refinar ms adelante, pero que nos servir como punto

podramos hacer una primera descripcin del juego en lenguaje natural (que

Observando la pantalla anterior, o (preferiblemente) tras jugar algunas partidas,

Introduccin a la programacin con C#, por Nacho Cabanes

Juego (formado por bienvenida y partida)

con sus relaciones y sus acciones, se puede expresar

clase "Coche".
Revisin 0.99zz Pgina 183

Civic Type-R con matrcula 0001-AAA sera un objeto concreto perteneciente a la

objetos que tienen una serie de caractersticas comunes. Por ejemplo, un Honda

El nombre "diagrama de clases" se debe a que se llama "clase" a un conjunto de

(simplificado):

mediante un "diagramas de clases", que en nuestro caso podra ser as

Esa serie de objetos,

programadores o analistas pueden llegar a soluciones parcialmente distintas).

(En general, esta descomposicin no tiene por qu ser nica, distintos

Introduccin a la programacin con C#, por Nacho Cabanes

Si as lo elige el jugador, se puede "Lanzar" una "Partida".


En una partida participan una "Nave", cuatro "Torres" defensivas, un

x
x

Una "TorreDefensiva" se puede "Destruir" poco a poco, a partir de un

Cada "Enemigo" individual se puede mover a la derecha, a la izquierda,

pantalla, porque tambin es una subclase de Sprite.

Revisin 0.99zz Pgina 184

una subclase de Sprite. De igual modo, la nave se podr "Dibujar" en

Sprite tiene una coordenada X y una Y, tambin lo tendr el OVNI, que es

sprite "heredarn" las caractersticas de esta clase. Por ejemplo, como un

variables, mientras que los "mtodos" sern funciones. Los subtipos de

de clases se convierte en un programa, los atributos se representarn

pantalla) o "moverse" a una nueva posicin. Cuando toda esta estructura

operaciones (que llamaremos "mtodos") como "dibujarse" (aparecer en

una posicin, dada por sus coordenadas "x" e "y". Ser capaz de hacer

sprite tendr detalles (que llamaremos "atributos") como una "imagen" y

Un "Sprite" es una figura grfica de las que aparecen en el juego. Cada

ms genrico).

ms especfico se indica con las puntas de flecha, que sealan al objeto

concretos de "Sprite" (esa relacin entre un objeto ms genrico y uno

Tanto la "Nave" como las "Torres", los "Enemigos" y el "Ovni" son tipos

disparar.

Nuestra "Nave" se puede mover a la derecha, a la izquierda y puede

x
x

El "Disparo" se puede "Mover" y puede "Desaparecer".

puede disparar o puede desaparecer (cuando un disparo le acierte).

El "BloqueDeEnemigos" se puede "Mover".

impacto en ciertas coordenadas x,y.

El "Ovni" se puede "Mover".

un "Ovni".

podran ser de tres tipos distintos, pero no afinaremos tanto por ahora) y

"BloqueDeEnemigos" formado por varios "Enemigos" (que, a su vez,

La "Bienvenida" se puede "Lanzar" al comienzo del juego.

lnea que une ambas clases, junto a la clase "contenedora").

objeto "contiene" a otros se indica mediante un rombo en el extremo de la

El juego contiene una "Bienvenida" y una "Partida" (ese relacin de que un

tpicamente se leer de arriba a abajo).

El objeto principal de nuestro proyecto se llama "Juego" (el diagrama

parecerse bastante a la descripcin inicial) son:

Algunos de los detalles que se pueden leer de ese diagrama (y que deberan

Introduccin a la programacin con C#, por Nacho Cabanes

Disponemos de herramientas gratuitas como ArgoUML, multiplataforma, que


permite crear distintos tipos de diagramas UML y que permite generar el cdigo
correspondiente al esqueleto de nuestras clases, o Dia, tambin multiplataforma,
pero de uso ms genrico (para crear diagramas de cualquier tipo) y que no
permite generar cdigo por ella misma pero s con la ayuda de Dia2code.

el usuario), "MoverElementos" (para actualizar el movimiento de los

elementos que deban moverse por ellos mismos, como los enemigos o el

OVNI), "ComprobarColisiones" (para ver si dos elementos chocan, como un

disparo y un enemigo, y actualizar el estado del juego segn corresponda),

o "DibujarElementos" (para mostrar en pantalla todos los elementos

(tampoco demasiado simple) y trata de hacer una descripcin como la anterior y


una descomposicin en clases.

tipo de enemigo, otra del OVNI...

ahora, adems de variables (que representan sus detalles internos, y que


llamaremos sus "atributos"), tambin incluirn funciones (las acciones que puede

algunas peculiaridades de los temas que veremos a continuacin, como el manejo

de ficheros en C#.

detalles de la lgica del programa.

un esqueleto del programa, que nosotros rellenaremos despus con los

Algunas de estas herramientas grficas permiten generar automticamente

tambin deberan ser parte del proyecto.

legibilidad o dejar hueco para nuevas clases que hayamos descubierto que

Podemos "pinchar y arrastrar" para recolocar las clases, y as conseguir ms

Revisin 0.99zz Pgina 185

distintos tipos de diagramas para representar los posibles "casos de uso" de una

Modelling Language, lenguaje de modelado unificado). El estndar UML propone

interacciones (adems de otras muchas cosas) se conoce como UML (Unified

La metodologa ms extendida actualmente para disear estos objetos y sus

herramientas informticas tiene varias ventajas adicionales:

dibujar directamente en papel para aclararnos las ideas, pero el empleo de

public void MostrarEstado()


{

public void Cerrar()


{
abierta = false;
}

public void Abrir()


{
abierta = true;
}

int ancho;
// Ancho en centimetros
int alto;
// Alto en centimetros
int color;
// Color en formato RGB
bool abierta; // Abierta o cerrada

public class Puerta


{

As, una clase "Puerta" se podra declarar as:

Revisin 0.99zz Pgina 186

Esto es lo que se conoce como "Encapsulacin".

herramientas grficas que nos ayuden a visualizar las clases y las relaciones que

existen entre ellas, como hemos hecho para el Space Invaders. Tambin se puede

parte de "un todo", en vez de estar separados en distintas partes del programa.

Como curiosidad, cabe mencionar que en los proyectos grandes es habitual usar

realizar ese objeto, que llamaremos sus "mtodos"). Atributos y mtodos formarn

Las clases en C# se definen de forma parecida a los registros (struct), slo que

permitan sentar las bases para proyectos ms complejos, y tambin entender

empezaremos a crear proyectos sencillos en los que colaboren varias clases, que

6.2. Objetos y clases en C#

(6.1.1) Piensa en un juego que conozcas, que no sea demasiado complejo

otra del movimiento del bloque de enemigos, otra de las peculiaridades de cada

Nosotros no vamos a hacer proyectos tan grandes (al menos, no todava), pero s

Ejercicio propuesto:

se podra encargar de crear la pantalla de bienvenida, otra de la lgica del juego,

posteriormente esa estructura e ir creando proyectos ms complejos.

an "no hiciese nada", y entonces comenzaramos a repartir trabajo: una persona

podramos crear un "esqueleto" de programa que compilase correctamente pero

En los prximos ejemplos partiremos de una nica clase en C#, para ampliar

integrar (que es lo que a nosotros nos interesa en este momento), etc.

lgica del juego, como "ComprobarTeclas" (para ver qu teclas ha pulsado

actualizados).

aplicacin, la secuencia de acciones que se debe seguir, las clases que la van a

El propio juego tambin tendr mtodos adicionales, relacionados con la

Faltan detalles, pero no es un mal punto de partida. A partir de este diagrama

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

public void MostrarEstado()


{
Console.WriteLine("Ancho: {0}", ancho);
Console.WriteLine("Alto: {0}", alto);
Console.WriteLine("Color: {0}", color);
Console.WriteLine("Abierta: {0}", abierta);
}

public void Cerrar()


{
abierta = false;
}

public void Abrir()


{
abierta = true;
}

int ancho;
// Ancho en centimetros
int alto;
// Alto en centimetros
int color;
// Color en formato RGB
bool abierta; // Abierta o cerrada

public class Puerta


{

using System;

// Ejemplo_06_02a.cs
// Primer ejemplo de clases
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 187

"Puerta"), muestre su estado, la abra y vuelva a mostrar su estado:

Vamos a completar un programa de prueba que use un objeto de esta clase (una

Puerta p = new Puerta();


p.Abrir();
p.MostrarEstado();

palabra "new", igual que hacamos con los "arrays":

Para declarar estos objetos que pertenecen a la clase "Puerta", usaremos la

correctamente).

(y adems, nos pueden "mostrar su estado", para comprobar que todo funciona

alto, un color, y un estado (abierta o no abierta), y adems se podrn abrir o cerrar

Como se puede observar, los objetos de la clase "Puerta" tendrn un ancho, un

} // Final de la clase Puerta

Console..WriteLine("Ancho: {0}", ancho);


Console.WriteLine("Alto: {0}", alto);
Console.WriteLine("Color: {0}", color);
Console.WriteLine("Abierta: {0}", abierta);

Introduccin a la programacin con C#, por Nacho Cabanes

La clase "Ejemplo_06_02a", que representa a nuestra aplicacin.

La clase "Puerta", que es el nuevo objetos con el que vamos a practicar.

Revisin 0.99zz Pgina 188

parte de una clase (los "atributos") tienen un valor inicial predefinido: 0 para los

Se puede ver que en C# (pero no en todos los lenguajes), las variables que forman

Vamos a abrir...
Ancho: 0
Alto: 0
Color: 0
Abierta: True

Valores iniciales...
Ancho: 0
Alto: 0
Color: 0
Abierta: False

El resultado de ese programa es el siguiente:

importante por ahora, puedes ignorar ese aviso).

has declarado "alto", "ancho" y "color", pero no las ests utilizando; no es

(Nota: al compilar, puede que obtengas algn "Aviso" -warning- que te dice que

anteriores, sino dos clases distintas:

Este fuente ya no contiene una nica clase (class), como todos nuestros ejemplos

Console.WriteLine("Vamos a abrir...");
p.Abrir();
p.MostrarEstado();

Console.WriteLine();

Console.WriteLine("Valores iniciales...");
p.MostrarEstado();

public static void Main()


{
Puerta p = new Puerta();

public class Ejemplo_06_02a


{

} // Final de la clase Puerta

Introduccin a la programacin con C#, por Nacho Cabanes

los detalles internos de nuestra clase sin que afecte a su uso.

"ocultacin de datos". Supondr ventajas como que podremos cambiar

valor tambin usando una funcin. Esto es lo que se conoce como

usando mtodos auxiliares (por ejemplo, nuestro "Abrir"), y que se lea su

se acceda directamente a los atributos, sino que siempre se modifiquen

Los puristas de la Programacin Orientada a Objetos recomiendan que no

caso, no lo ser desde Ejemplo_06_02a).

pblico, sino privado, y no ser accesible desde otras clases (en nuestro

El atributo "abierta" no tiene delante la palabra "public"; por lo que no es

ser:
Revisin 0.99zz Pgina 189

As, una nueva versin del programa, que incluya ejemplos de Get y Set, podra

public void SetAncho(int nuevoValor)


{
ancho = nuevoValor;
}

public int GetAncho()


{
return ancho;
}

"propiedades", que veremos ms adelante):

los atributos (en C# existe una forma alternativa de hacerlo, usando

crearemos funciones auxiliares GetXXX y SetXXX que permitan acceder al valor de

palabras inglesas "Get" y "Set" para leer y cambiar un valor, respectivamente. As,

cmo llamar a a estos mtodos en espaol, por lo que es frecuente usar las

CambiarAncho, que lo reemplazase por otro valor. No hay un convenio claro sobre

podramos crear un mtodo LeerAncho, que nos devolviera su valor, y un mtodo

Por ejemplo, para conocer y modificar los valores del "ancho" de una puerta,

el programa principal, por dos motivos:

Aun as, en nuestro caso no podemos hacer directamente "p.abierta = true" desde

registros (struct).

de cada uno por el nombre de la variable y por un punto, como hacamos con los

Vemos tambin que se accede a los mtodos y a los datos precediendo el nombre

booleanos.

nmeros, una cadena vaca para las cadenas de texto, "false" para los datos

Introduccin a la programacin con C#, por Nacho Cabanes

Console.WriteLine("Vamos a abrir...");
p.Abrir();
p.SetAncho(80);
p.MostrarEstado();

Console.WriteLine();

Console.WriteLine("Valores iniciales...");
p.MostrarEstado();

public static void Main()


{
Puerta p = new Puerta();

public class Ejemplo_06_02b


{

} // Final de la clase Puerta

public void MostrarEstado()


{
Console.WriteLine("Ancho: {0}", ancho);
Console.WriteLine("Alto: {0}", alto);
Console.WriteLine("Color: {0}", color);
Console.WriteLine("Abierta: {0}", abierta);
}

public void SetAncho(int nuevoValor)


{
ancho = nuevoValor;
}

public int GetAncho()


{
return ancho;
}

public void Cerrar()


{
abierta = false;
}

public void Abrir()


{
abierta = true;
}

int ancho;
// Ancho en centimetros
int alto;
// Alto en centimetros
int color;
// Color en formato RGB
bool abierta; // Abierta o cerrada

public class Puerta


{

using System;

// Ejemplo_06_02b.cs
// Clases, get y set
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 190

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 191

tenga el mismo nombre: que la clase Puerta se encuentre en el fichero "Puerta.cs".

Es recomendable (aunque no obligatorio) que cada clase est en un fichero que

hecho en el curso hasta ahora, no era necesario, porque eran muy simples).

fichero fuente, de forma que se puedan localizar con rapidez (en los que hemos

En un proyecto grande, es recomendable que cada clase est en su propio

6.3. Proyectos a partir de varios fuentes

Main de prueba.

"cilindrada" (nmero entero), potencia (nmero real). No hace falta que crees un

(6.2.4) Crea una clase "Coche", con atributos "marca" (texto), "modelo" (texto),

valores a sus tres atributos y luego los muestre.

public int GetAncho()


{
return ancho;

public void Cerrar()


{
abierta = false;
}

public void Abrir()


{
abierta = true;
}

int ancho;
// Ancho en centimetros
int alto;
// Alto en centimetros
int color;
// Color en formato RGB
bool abierta; // Abierta o cerrada

public class Puerta


{

using System;

tambin un Main (en la misma clase), que cree un objeto de la clase Libro, d

primera clase podra ser sta:

Revisin 0.99zz Pgina 192

Vamos a dividir en dos fuentes el ltimo ejemplo y a ver cmo se compilara. La

ms avanzado y que usaremos con frecuencia a partir de ahora: Visual Studio.

compilar desde "lnea de comandos" y luego lo haremos con un entorno mucho

tarea especialmente cmoda. Por eso, veremos un primer ejemplo de cmo

Geany permite crear "proyectos" formados por varios fuentes, pero no resulta una

teclear una orden como la anterior, pero no supone ninguna gran ganancia;

Notepad++ y Geany: Notepad++ tiene un men "Ejecutar", que nos permite

En general, esto no lo podremos hacer de forma sencilla desde editores como

mcs fuente1.cs fuente2.cs fuente3.cs -out:ejemplo.exe

Mono:

(fuente1.exe). Podemos cambiar el nombre del ejecutable con la opcin "-out" de

En ese caso, el ejecutable obtenido tenda el nombre del primero de los fuentes

mcs fuente1.cs fuente2.cs fuente3.cs

nombres de todos ellos. Por ejemplo, con Mono sera

// Puerta.cs
// Clases, get y set
// Introduccin a C#, por Nacho Cabanes

strings) y mtodos Get y Set adecuados para leer su valor y cambiarlo. Prepara

Introduccin a la programacin con C#, por Nacho Cabanes

Para compilar un programa formado por varios fuentes, basta con indicar los

clase "Libro", que contendr atributos "autor", "titulo", "ubicacion" (todos ellos

(6.2.3) Para guardar informacin sobre libros, vamos a comenzar por crear una

(en la misma clase), que cree un objeto de la clase Juego y lo lance.

para salir" y se parar hasta que el usuario pulse Intro. Prepara tambin un Main

parmetros, que escriba en pantalla "Bienvenido a Console Invaders. Pulse Intro

anterior, crea una clase Juego,que slo contenga un mtodo Lanzar, void, sin

(6.2.2) Tras leer la descripcin de Space Invaders que vimos en el apartado

pedir que saluden.

que crear dos objetos de tipo Persona, les asignar un nombre a cada uno y les

clase llamada PruebaPersona. Esta clase deber contener slo la funcin Main,

que escribir en pantalla "Hola, soy " seguido de su nombre. Crea tambin una

cambiar el valor del nombre. Finalmente, tambin tendr un mtodo "Saludar",

mtodo "SetNombre", de tipo void y con un parmetro string, que permita

deber tener un atributo "nombre", de tipo string. Tambin deber tener un

(6.2.1) Crea una clase llamada Persona, en el fichero "persona.cs". Esta clase

Ejercicios propuestos:

antes de cada funcin: a partir de ahora, slo Main ser "static".

ms adelante, pero de momento perderemos la costumbre de escribir "static"

que no lo hace en los mtodos de la clase "Puerta". Veremos el motivo un poco

Tambin puede desconcertar que en "Main" aparezca la palabra "static", mientras

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 193

VisualStudio (del que existe una versin gratuita, conocida como Express), que nos

entorno ms avanzado, como SharpDevelop (que adems es gratuito) o

Aun as, para estos proyectos formados por varias clases, lo ideal es usar algn

mcs ejemplo06_03a.cs puerta.cs -out:ejemploPuerta.exe

Y lo compilaramos con:

Console.WriteLine("Vamos a abrir...");
p.Abrir();
p.SetAncho(80);
p.MostrarEstado();

Console.WriteLine();

Console.WriteLine("Valores iniciales...");
p.MostrarEstado();

public static void Main()


{
Puerta p = new Puerta();

public class Ejemplo_06_03a


{

using System;

// Ejemplo_06_03a.cs
// Usa la clase Puerta
// Introduccin a C#, por Nacho Cabanes

Y la segunda clase podra ser:

} // Final de la clase Puerta

public void MostrarEstado()


{
Console.WriteLine("Ancho: {0}", ancho);
Console.WriteLine("Alto: {0}", alto);
Console.WriteLine("Color: {0}", color);
Console.WriteLine("Abierta: {0}", abierta);
}

public void SetAncho(int nuevoValor)


{
ancho = nuevoValor;
}

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 194

y al cabo de un instante, tendremos un nuevo icono en nuestro escritorio:

deberemos decir en qu carpeta queremos instalarlo, comenzar a copiar archivos

Como es habitual, el siguiente paso ser aceptar el contrato de licencia, despus

ver una ventana parecida a sta:

La instalacin comenzar al hacer doble clic en el fichero descargado. Deberamos

algn error).

en "fase beta" (pruebas previas a la versin definitiva, as que puede contener

momento de escribir este texto tambin existe una versin 5.0, pero todava est

para las versiones 2.0 a 4.5.1 de la plataforma .Net, ocupa unos 15 Mb. En el

oficial (http://www.icsharpcode.net/OpenSource/SD/Download/). La versin 4.4,

Comenzamos por descargar el fichero de instalacin del entorno, desde su pgina

para Windows.

alternativa muy similar, pero algo ms sencilla, llamada SharpDevelop, disponible

puede requerir un equipo relativamente potente, vamos a comenzar por ver una

lo que un programador novel como nosotros puede necesitar. Aun as, como

complejidad es Visual Studio, de Microsoft, que en su versin Express incluye todo

El entorno de desarrollo ms conocido para crear programas de una cierta

errores...

rpidamente, que marquen dentro del propio editor la lnea en la que estn los

permitan crear todas las clases con comodidad, saltar de una clase a clase otra

Introduccin a la programacin con C#, por Nacho Cabanes

"File", en la opcin "New Solution":

Revisin 0.99zz Pgina 195

En nuestro caso, comenzaremos por crear una "Nueva solucin", desde el men

que hemos realizado, y nos permite crear uno nuevo:

de SharpDevelop, que nos muestra la lista de los ltimos proyectos ("soluciones")

Cuando hagamos doble clic en nuestro nuevo icono, veremos la pantalla principal

.Net (se puede descargar gratuitamente desde la web de Microsoft).

Windows XP quiz necesite que instalemos una versin reciente de la plataforma

La instalacin debera ser muy sencilla en Windows Vista y superiores, pero en

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 196

esqueleto de aplicacin que nosotros slo tendramos que completar:

Application) en C#. Deberemos escribir tambin el nombre, y aparecer un

De estos tipos, el nico que conocemos es una "Aplicacin de Consola" (Console

esqueleto vaco que despus iramos rellenando:

Se nos mostrar los tipos de proyectos para los que se nos podra crear un

Introduccin a la programacin con C#, por Nacho Cabanes

programa con el botn "Generar":

Revisin 0.99zz Pgina 197

Cuando hayamos terminado de realizar nuestros cambios, podemos compilar el

"Tools" (herramientas):

aparezcan en espaol. Lo haremos desde "Options" (opciones), al final del men

Podemos cambiar el idioma del interfaz, para que todos los mens y opciones

Introduccin a la programacin con C#, por Nacho Cabanes

Elemento:

Revisin 0.99zz Pgina 198

ventana izquierda, "Proyectos") y escogiendo las opciones Agregar / Agregar

conseguimos pulsando el botn derecho sobre el nombre del proyecto (en la

trata de varios fuentes, basta con ir aadiendo nuevas clases al proyecto. Lo

As prepararamos y lanzaramos un programa formado por un solo fuente. Si se

del fuente, para que ste se detenga hasta que pulsemos la tecla Intro).

leerla, nos puede interesar aadir provisionalmente una lnea ReadLine() al final

(Si la ventana de nuestro programa se cierra tan rpido que no tenemos tiempo de

ido bien, podremos ejecutar nuestro programa para verlo funcionando:

subrayaran en rojo las lneas correspondientes de nuestro programa; si todo ha

Si hubiera algn error, se nos avisara en la parte inferior de la pantalla, y se

Introduccin a la programacin con C#, por Nacho Cabanes

completar.

Revisin 0.99zz Pgina 199

y obtendramos un nuevo esqueleto vaco (esta vez sin "Main"), que deberamos

deberemos indicar:

Normalmente, el tipo de elemento que nos interesar ser una clase, cuyo nombre

Introduccin a la programacin con C#, por Nacho Cabanes

acceder a los ficheros de instalacin.


Revisin 0.99zz Pgina 200

ISO de DVD", deberemos grabarla en un DVD o extraerla con 7-zip o WinRar para

que se reciban los ficheros necesarios. Si, por el contrario, descargamos la "imagen

principio, y necesitaremos estar conectados a Internet durante la instalacin para

Si escogemos el instalador basado en Web, descargaremos un pequeo fichero al

lo suficientemente moderna).

en algn punto intermedio, si nuestra versin de la plataforma "punto net" no es

que se complete el proceso (puede ser necesario tener que reiniciar el ordenador

fichero, hacer doble clic para comenzar (si descargamos y esperar un momento a

La instalacin es muy similar a la de SharpDevelop: poco ms que descargar el

Windows Desktop-)

(En nuestro caso, se tratara de la versin Express para escritorio de Windows -

http://www.visualstudio.com/es-es/products/visual-studio-express-vs

de:

visto. La versin Express, que es gratuita para uso personal, se puede descargar

una cierta fluidez. Instalar y emplear este entorno es muy similar a lo que hemos

Si nuestro equipo es moderno, posiblemente nos permitir usar Visual Studio con

ejecutara de la misma forma que cuando estaba integrado por una nica clase.

Nuestro programa, que ahora estara formado por dos clases, se compilara y se

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 201

proyectos existentes, escogeramos crear una "Aplicacin de consola":

En ella tenemos la opcin de crear un "Nuevo proyecto". De entre los tipos de

escogemos otras paletas de colores):

(para Visual Studio 2013; puede ser ligeramente distinta en otras versiones o si

La pantalla principal, una vez completada la instalacin, debera ser similar a sta

interfaces de usuario).

principiante, como las pruebas de rendimiento o automatizacin de tests para

Ultimate, con ms caractersticas adicionales (que no necesitars siendo un

tambin a otras versiones ms potentes de Visual Studio, como Professional y

"Academic Alliance" de Microsoft (MSDNAA), posiblemente tendrs acceso gratuito

Si eres estudiante y tu centro de estudios est adscrito a programas como la

Introduccin a la programacin con C#, por Nacho Cabanes

"Agregar clase" del men "Proyecto":


Revisin 0.99zz Pgina 202

clases usando la ventana de la derecha ("Explorador de soluciones") o la opcin

Si nuestro programa va a estar formado por varios fuentes, podramos aadir ms

botn "Aceptar", con lo que debera aparecer un esqueleto de programa vaco:

En la parte inferior escribiremos el nombre de nuestro proyecto, y pulsaremos el

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 203

herramientas, utilizaremos la combinacin de teclas Ctrl+F5.

Para conseguirlo, en vez de pulsar el botn "Iniciar" de la barra de

de modo que la ejecucin se pause al terminar, igual que ocurre en Geany.

La mayora de versiones de Visual Studio permiten lanzar nuestro programa

corriente elctrica.

el trabajo en caso de fallo del sistema operativo o del suministro de

riesgo de que no se haya llegado a guardar nuestro proyecto, y perdamos

Guardar cuando nosotros lo deseemos. Si no lo hacemos, corremos el

automticamente, sino que deberemos usar explcitamente la opcin de

memoria": si pulsamos el botn de Iniciar, nuestro proyecto no se guarda

Segn la versin de Visual Studio, puede ser que "compile desde

las lneas incorrectas a medida que las tecleemos.

No es necesario compilar para saber los errores: se irn marcando en rojo

comparado con el de SharpDevelop, que conviene tener en cuenta:

Hay alguna diferencia ms en el manejo normal de Visual Studio Express,

podemos lanzarlo haciendo clic en el botn "Iniciar ":

fuente, que en este caso no contiene "Main". Cuando el programa est listo,

Que, al igual que en el caso de SharpDevelop, nos mostrara el esqueleto de un

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 204

para jugar". El mtodo Lanzar de la clase Partida escribir en pantalla "sta sera la

clase Bienvenida escribir en pantalla "Bienvenido a Console Invaders. Pulse Intro

lanzar y luego un objeto de la clase "Partida" y lo lanzar. El mtodo Lanzar de la

escribir nada en pantalla, sino que crear un objeto de la clase "Bienvenida" y lo

"Bienvenida" y una clase "Partida". El mtodo "Lanzar" de la clase Juego, ya no

para Visual Studio o SharpDevelop. Adems de la clase "Juego", crea una clase

(6.3.4) Ampla el esqueleto del ConsoleInvaders (ejercicio 6.2.2): crea un proyecto

a una segunda clase llamada "PruebaDeLibro" y desaparecer de la clase Libro.

(6.3.3) Crea un proyecto a partir de la clase Libro (ejercicio 6.2.3). El "Main" pasar

un nombre y les pedir que saluden.

contener slo la funcin Main, que crear dos objetos de tipo Persona, les asignar

clase llamada PruebaPersona, en el fichero "pruebaPersona.cs". Esta clase deber

que escribir en pantalla "Hola, soy " seguido de su nombre. Crea tambin una

cambiar el valor del nombre. Finalmente, tambin tendr un mtodo "Saludar",

mtodo "SetNombre", de tipo void y con un parmetro string, que permita

deber tener un atributo "nombre", de tipo string. Tambin deber tener un

ficheros: Crea una clase llamada Persona, en el fichero "persona.cs". Esta clase

(6.3.2) Modifica el fuente del ejercicio 6.2.1 (clase Persona), para dividirlo en dos

todo funciona correctamente.

(6.3.1) Crea un proyecto con las clases Puerta y Ejemplo_06_03a. Comprueba que

Ejercicio propuesto:

ejemplo, Synaptic en el caso de Ubuntu y de Linux Mint).

instalar apenas en un par de clics con el gestor de paquetes del sistema (por

equipo que ha creado Mono. Se trata de MonoDevelop, que se debera poder

VisualStudio, pero tiene una alternativa muy similar, desarrollada por el mismo

Quien trabaja con Linux o con Mac, no podr emplear SharpDevelop ni

Introduccin a la programacin con C#, por Nacho Cabanes

Puedes usar

// Ejemplo_06_04a.cs

using System;

Revisin 0.99zz Pgina 206

Un programa de prueba, que ampliase el anterior para incluir un "portn", podra

del portn. En el prximo apartado veremos cmo acceder a esos datos.

Puedes observar que ese "MostrarEstado" no dice nada sobre el ancho ni el alto

public new void MostrarEstado()


{
Console.WriteLine("Portn.");
Console.WriteLine("Bloqueada: {0}", bloqueada);
}

en qu momento ser adecuado usar cada una de ellas.

programa como vlido; ms adelante veremos que existe una alternativa a "new" y

incluimos la palabra "new", el compilador mostrar un "warning", pero dar el

que ya existe ese mtodo y que sabemos seguro que lo queremos redefinir (si no

declarar y aadir la palabra "new" para indicar al compilador de C# que sabemos

nos diga tambin si la puerta est bloqueada. Para eso, basta con volverlo a

algo que ya exista. Por ejemplo, nos puede interesar que "MostrarEstado" ahora

No tenemos por qu heredar todo tal y como era; tambin podemos "redefinir"

En este ejemplo, la clase Puerta no cambiara nada.

lo tiene por ser un "descendiente" de Puerta.

que un Portn tendr un cierto ancho, o un color, o que se puede abrir: todo eso

que ya habamos definido para Puerta. Por eso, no hace falta indicar nuevamente

ser:

Revisin 0.99zz Pgina 205

Introduccin a la programacin con C#, por Nacho Cabanes

Con "public class Porton: Puerta" indicamos que Porton debe "heredar" todo lo

public void Desbloquear()


{
bloqueada = false;
}

public void Bloquear()


{
bloqueada = true;
}

bool bloqueada;

public class Porton : Puerta


{

// Porton.cs
// Clase que hereda de Puerta
// Introduccin a C#, por Nacho Cabanes

atributo y nuevos mtodos para bloquear y desbloquear:

color, abierto o no), pero adems se podr bloquear, lo que supondr un nuevo

"Puerta". Un portn tendr las mismas caractersticas que una puerta (ancho, alto,

existente. Por ejemplo, vamos a crear una clase "Porton" a partir de la clase

Vamos a ver ahora cmo definir una nueva clase de objetos a partir de otra ya

6.4. La herencia

y potencia, y luego mostrar en pantalla el valor de esos datos.

que crear un objeto de tipo coche, pedir al usuario su marca, modelo, cilindrada

clase Coche, existir una clase PruebaDeCoche, que contendr la funcin "Main",

(6.3.7) Crea un proyecto a partir de la clase Coche (ejercicio 6.2.4): adems de la

juego.

finalmente esperar a que el usuario pulse Intro para terminar la falsa sesin de

600) y la dibujar, crear un enemigo en las coordenadas (100, 80) y lo dibujar, y

El mtodo Lanzar de la clase Partida crear una nave en las coordenadas (500,

Crea tambin clase Enemigo, con los mismos atributos. Su imagen podra ser "][".

Console.SetCursorPosition(x,y) para situarte en unas coordenadas de pantalla.

tenga un valor entre 0 y 79, y la Y entre 0 y 24).

pantalla (como esta versin es para consola, la X tendr que rebajarse para que

mueva a una nueva posicin, y un mtodo Dibujar, que muestre esa imagen en

caracteres, como "/\"). Tambin tendr un mtodo MoverA(nuevaX, nuevaY) que lo

pensando en una pantalla de 1024x768), e imagen (un string formado por dos

Nave, con atributos "x" e "y" (nmeros enteros, "x" de 0 a 1023 e "y" entre 0 y 767,

(6.3.6) Ampla el esqueleto del ConsoleInvaders (ejercicio 6.3.5): Crea una clase

Bienvenida-Partida hasta que el usuario escoja Salir.

ha elegido Jugar. El mtodo Lanzar de la clase Juego repetir la secuencia

la clase Bienvenida, que devuelva "true" si el usuario ha escogido Salir o "false" si

usar "Console.Clear();" si quieres borrar la pantalla. Aade un mtodo "GetSalir" a

salir = true;". El cdigo de la tecla Intro es " ConsoleKey.Enter". Tambin puedes

"ConsoleKeyInfo tecla = Console.ReadKey(); if (tecla.Key == ConsoleKey.Escape)

Intro para jugar o ESC para salir". Puedes comprobar si se pulsa ESC con

de la clase Bienvenida escribir en pantalla "Bienvenido a Console Invaders. Pulse

(6.3.5) Ampla el esqueleto del ConsoleInvaders (ejercicio 6.3.4): El mtodo Lanzar

Intro.

pantalla de juego. Pulse Intro para salir" y se parar hasta que el usuario pulse

Introduccin a la programacin con C#, por Nacho Cabanes

Se

crear

una

nueva

clase

PersonaInglesa,

en

el

fichero

Esta clase deber heredar las caractersticas de la clase


Crear tambin una clase llamada PruebaPersona2, en el

Puerta, incluyendo sus "descendientes", como un Porton. Esto se puede conseguir


usando otro mtodo de acceso: "protected". Todo lo que declaremos como

(6.4.1) Crea un proyecto con las clases Puerta, Portn y Ejemplo_06_04a. Prueba

que todo funciona correctamente.


Revisin 0.99zz Pgina 207

Slo querramos que esos datos estuvieran disponibles para todos los tipos de

Ejercicios propuestos:

Revisin 0.99zz Pgina 208

"ocultacin de detalles", que hace nuestros programas sean ms fciles de


mantener.

que sean accesibles desde cualquier sitio, debemos recordar la mxima de

"ancho" y el "alto", pero esa no es la solucin ms razonable, porque no queremos

Nos podramos sentir tentados de declarar como "public" los atributos como el

ser pblico, porque nuestras clases y su "Main" lo han sido siempre hasta ahora.

Hemos manejado con frecuencia la palabra "public", para indicar que algo debe

ninguna otra clase, ni siquiera desde Porton.

considera en C# si no decimos lo contrario), por lo que no son accesibles desde

como el "ancho" y el "alto" estaban declarados como "privados" (es lo que se

Nuestro ejemplo todava no funciona correctamente: los atributos de una Puerta,

6.5. Visibilidad

tanto Coche como Moto heredarn de ella.

Vehiculo contendr todos los atributos y mtodos que antes estaban en Coche, y

"Vehiculo", de la que heredarn "Coche" y una nueva clase "Moto". La clase

(6.4.5) Ampla el proyecto de la clase Coche (ejercicio 6.3.7): Crea una clase

ahora).

los atributos y mtodos que son comunes a las antiguas (todos los existentes, por

"Sprite", de la que heredarn "Nave" y "Enemigo". La nueva clase contendr todos

(6.4.4) Ampla el esqueleto del ConsoleInvaders (ejercicio 6.3.6): Crea una clase

Get y Set.

contendr slo un atributo "paginas", nmero entero, con sus correspondientes

de la que Libro heredar todos sus atributos y mtodos. Ahora la clase Libro

(6.4.3) Ampla el proyecto del ejercicio 6.3.3 (Libro): crea una clase "Documento",

nombre, les pedir que saluden y pedir a la persona inglesa que tome t.

crear dos objetos de tipo Persona y uno de tipo PersonaInglesa, les asignar un

fichero "pruebaPersona2.cs". Esta clase deber contener slo la funcin Main, que

"Estoy tomando t".

"Persona", y aadir un mtodo "TomarTe", de tipo void, que escribir en pantalla

"personaInglesa.cs".

cambia.

(6.4.2) Crea una variante ampliada del ejercicio 6.3.2. En ella, la clase Persona no

Introduccin a la programacin con C#, por Nacho Cabanes

Ahora el portn...
Portn.
Bloqueada: True

Vamos a abrir...
Ancho: 80
Alto: 0
Color: 0
Abierta: True

Valores iniciales...
Ancho: 0
Alto: 0
Color: 0
Abierta: False

Y su resultado sera:

Console.WriteLine("Ahora el portn...");
Porton p2 = new Porton();
p2.SetAncho(300);
p2.Bloquear();
p2.MostrarEstado();

Console.WriteLine();

Console.WriteLine("Vamos a abrir...");
p.Abrir();
p.SetAncho(80);
p.MostrarEstado();

Console.WriteLine();

Console.WriteLine("Valores iniciales...");
p.MostrarEstado();

public static void Main()


{
Puerta p = new Puerta();

public class Ejemplo_06_04a


{

using System;

// Portn, que hereda de Puerta


// Introduccin a C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

int ancho;
//
int alto;
//
int color;
//
bool abierta; //

Ancho en centimetros
Alto en centimetros
Color en formato RGB
Abierta o cerrada

Console.WriteLine("Ahora el portn...");

Console.WriteLine();

Console.WriteLine("Vamos a abrir...");
p.Abrir();
p.SetAncho(80);
p.MostrarEstado();

Console.WriteLine();

Console.WriteLine("Valores iniciales...");
p.MostrarEstado();

public static void Main()


{
Puerta p = new Puerta();

public class Ejemplo_06_05a


{

using System;

// Ejemplo_06_05a.cs
// Portn, que hereda de Puerta, con "protected"
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 209

de ella, y que adems contuviese un pequeo "Main" de prueba podra ser:

As, un nico fuente completo que declarase la clase Puerta, la clase Porton a partir

hayamos indicados

lenguajes se considere pblico (en vez de privado) un atributo cuya visibilidad no

adelante programamos en otros lenguajes, porque puede ocurrir que en otros

ayudar a detectar errores con mayor facilidad y como costumbre por si ms

general, ser preferible usar "private" a no escribir nada, por legibilidad, para

privado, podemos usar la palabra "private", en vez de "public" o "protected". En

Si quisiramos dejar claro que algn elemento de una clase debe ser totalmente

public void Abrir()


...

protected
protected
protected
protected

public class Puerta


{

ms:

"protected" ser accesible por las clases derivadas de la actual, pero por nadie

Introduccin a la programacin con C#, por Nacho Cabanes

int ancho;
//
int alto;
//
int color;
//
bool abierta; //

Ancho en centimetros
Alto en centimetros
Color en formato RGB
Abierta o cerrada

public class Porton : Puerta

// Porton.cs
// Clase que hereda de Puerta
// Introduccin a C#, por Nacho Cabanes

// ------------------------------------------

} // Final de la clase Puerta

public void MostrarEstado()


{
Console.WriteLine("Ancho: {0}", ancho);
Console.WriteLine("Alto: {0}", alto);
Console.WriteLine("Color: {0}", color);
Console.WriteLine("Abierta: {0}", abierta);
}

public void SetAncho(int nuevoValor)


{
ancho = nuevoValor;
}

public int GetAncho()


{
return ancho;
}

public void Cerrar()


{
abierta = false;
}

public void Abrir()


{
abierta = true;
}

protected
protected
protected
protected

public class Puerta


{

// Puerta.cs
// Clases, get y set
// Introduccin a C#, por Nacho Cabanes

// ------------------------------------------

Porton p2 = new Porton();


p2.SetAncho(300);
p2.Bloquear();
p2.MostrarEstado();

Revisin 0.99zz Pgina 210

Introduccin a la programacin con C#, por Nacho Cabanes

public new void MostrarEstado()


{
Console.WriteLine("Portn.");
Console.WriteLine("Ancho: {0}", ancho);
Console.WriteLine("Alto: {0}", alto);
Console.WriteLine("Color: {0}", color);
Console.WriteLine("Abierta: {0}", abierta);
Console.WriteLine("Bloqueada: {0}", bloqueada);
}

public void Desbloquear()


{
bloqueada = false;
}

public void Bloquear()


{
bloqueada = true;
}

bool bloqueada;

tambin

una

clase

llamada

PruebaPersona3,

en

el

fichero

"

Revisin 0.99zz Pgina 211

el usuario pulse Intro sin hacer nada, sino que ahora usar un do-while que

atributos sean "protected". El mtodo Lanzar de la clase Partida no esperar hasta

"MoverIzquierda", que disminuya su X en 10 unidades. Necesitars hacer que esos

Nave con un mtodo "MoverDerecha", que aumente su X en 10 unidades, y un

(6.5.4) Ampla el esqueleto del ConsoleInvaders (ejercicio 6.4.4): Ampla la clase

Documento y de la clase Libro sern "protegidos".

public Puerta(int an, int al)


{
ancho = an;
alto = al;
color = 0xFFFFFF;
abierta = false;
}
Revisin 0.99zz Pgina 212

ejemplo, puede haber otro constructor que nos permita indicar el ancho y el alto:

(6.5.3) Retoca el proyecto del ejercicio 6.4.3 (Libro): los atributos de la clase

Podemos tener ms de un constructor, cada uno con distintos parmetros. Por

tome t.

public Puerta()
{
ancho = 100;
alto = 200;
color = 0xFFFFFF;
abierta = false;
}

valores iniciales de 100 para el ancho, 200 para el alto, etc., podra ser as:

tipo de retorno. Por ejemplo, un "constructor" para la clase Puerta que le diera los

Un constructor se declara usando el mismo nombre que el de la clase, y sin ningn

reservar memoria si fuera necesario, para leer informacin desde fichero, etc.

un objeto de una clase, y se suele usar para dar esos valores iniciales, para

Un constructor es una funcin especial, que se pone en marcha cuando se crea

Esto se puede conseguir declarando un "constructor" para la clase.

Pero puede ocurrir que nosotros deseemos dar valores iniciales que no sean cero.

defecto para los atributos. Por ejemplo, para un nmero entero, se le da el valor 0.

Hemos visto que al declarar una clase, automticamente se dan valores por

6.6. Constructores y destructores

sern "protegidos" y los mtodos sern "pblicos".

(6.5.5) Mejora el proyecto de la clase Coche (ejercicio 6.4.5): todos los atributos

("Console.Clear();").

acabas de crear). Al principio de cada pasada del do-while se borrar la pantalla

Si se pulsan las flechas, la nave se mover a un lado o a otro (con los mtodos que

mover la nave: sus cdigos son ConsoleKey.LeftArrow y ConsoleKey. RightArrow).

compruebe si pulsa ESC (para salir) o flecha izquierda o flecha derecha (para

Introduccin a la programacin con C#, por Nacho Cabanes

asignar un nombre, les pedir que saluden y pedir a la persona inglesa que

de tipo Persona, dos de tipo PersonaInglesa, uno de tipo PersonaItaliana, les

pruebaPersona3.cs", que deber contener slo la funcin Main y crear un objeto

crea

"Persona", pero redefinir el mtodo "Saludar", para que escriba en pantalla "Ciao";

fichero "personaItaliana.cs", que deber heredar las caractersticas de la clase

"Hi, I am " seguido de su nombre; se crear una nueva clase PersonaItaliana, en el

modificar para que redefina el mtodo "Saludar", para que escriba en pantalla

siguientes caractersticas: La clase Persona no cambia; la clase PersonaInglesa se

(6.5.2) Ampla las clases del ejercicio 6.4.2, creando un nuevo proyecto con las

System" en cada fuente.

un fichero separado. Como podrs comprobar, ahora necesitars un "using

(6.5.1) Crea un proyecto a partir del ejemplo 06.05a, en el que cada clase est en

Ejercicios propuestos:

Introduccin a la programacin con C#, por Nacho Cabanes

int ancho;
//
int alto;
//
int color;
//
bool abierta; //

Ancho en centimetros
Alto en centimetros
Color en formato RGB
Abierta o cerrada

public Puerta(int an, int al)


{

public Puerta()
{
ancho = 100;
alto = 200;
color = 0xFFFFFF;
abierta = false;
}

protected
protected
protected
protected

public class Puerta


{

// ------------------------------------------

Console.WriteLine();
Console.WriteLine("Para la segunda puerta...");
p2.MostrarEstado();

Console.WriteLine();
Console.WriteLine("Vamos a abrir...");
p.Abrir();
p.MostrarEstado();

Console.WriteLine("Valores iniciales...");
p.MostrarEstado();

public static void Main()


{
Puerta p = new Puerta();
Puerta p2 = new Puerta(90,220);

public class Ejemplo_06_06a


{

using System;

// Ejemplo_06_06a.cs
// Constructores
// Introduccin a C#, por Nacho Cabanes

puertas con caractersticas iniciales distintas podra ser:

Revisin 0.99zz Pgina 213

Un programa de ejemplo que usara estos dos constructores para crear dos

new Puerta(90,220);" tendr 90 como ancho y 220 como alto.

tendr de ancho 100 y de alto 200, mientras que si lo declaramos con "Puerta p2 =

Ahora, si declaramos un objeto de la clase puerta con "Puerta p = new Puerta();"

Introduccin a la programacin con C#, por Nacho Cabanes

nombre.
Revisin 0.99zz Pgina 214

constructor alternativo para esta clase que permita escoger cualquier otro

del de PersonaInglesa, que prefijar su nombre a "John". Crea tambin un

constructores. Los constructores de casi todas las clases estarn vacos, excepto

(6.6.1) Ampliar las clases del ejercicio 6.5.2, para que todas ellas contengan

Ejercicios propuestos:

~Puerta()
{
// Liberar memoria
// Cerrar ficheros
}

especificador de acceso ("public" ni ningn otro), como ocurre en este ejemplo:

pero precedido por el smbolo "~", y no tiene tipo de retorno, ni parmetros, ni

Un destructor se crear con el mismo nombre que la clase y que el constructor,

necesitarn.

tampoco sabemos). Nuestros programas son tan sencillos que todava no los

sabemos manejar memoria dinmica) o para cerrar ficheros abiertos (que

pudiramos haber reservado en nuestra clase (no es nuestro caso, porque an no

"destructor" para una clase, que se encargue de liberar la memoria que

Nota: al igual que existen los "constructores", tambin podemos crear un

} // Final de la clase Puerta

public void MostrarEstado()


{
Console.WriteLine("Ancho: {0}", ancho);
Console.WriteLine("Alto: {0}", alto);
Console.WriteLine("Color: {0}", color);
Console.WriteLine("Abierta: {0}", abierta);
}

public void Cerrar()


{
abierta = false;
}

public void Abrir()


{
abierta = true;
}

ancho = an;
alto = al;
color = 0xFFFFFF;
abierta = false;

Introduccin a la programacin con C#, por Nacho Cabanes

(6.7.2) Ampla el proyecto del ejercicio 6.6.2 (Libro): la clase Libro tendr un
segundo constructor que permita dar valores al autor y el ttulo, pero no a la
ubicacin, que tomar el valor por defecto "No detallada".
(6.7.3) Ampla el esqueleto del ConsoleInvaders (6.6.3): La clase Nave tendr un
segundo constructor, sin parmetros, que prefijar su posicin inicial a (500,600).
La clase Enemigo tendr un segundo constructor, con parmetros X e Y, para
poder colocar un enemigo en cualquier punto desde Main.
(6.7.4) Crea dos nuevos mtodos en la clase Vehiculo (ejercicio 6.6.4): uno llamado
Circular, que fijar su "velocidad" (un nuevo atributo) a 50, y otro Circular(v), que
fijar su velocidad al valor que se indique como parmetro.

(6.6.2) Ampla el proyecto del ejercicio 6.5.3 (Libro): la clase Libro tendr un

constructor que permita dar valores al autor, el ttulo y la ubicacin.

(6.6.3) Ampla el esqueleto del ConsoleInvaders (ejercicio 6.5.4): La clase Enemigo

tendr un constructor, sin parmetros, que prefijar su posicin inicial. El

constructor de la clase Nave recibir como parmetros las coordenadas X e Y

iniciales, para que se puedan cambiar desde el cuerpo del programa. Elimina las

variables xNave e yNave de la clase Partida, que ya no sern necesarias.

(6.6.4) Mejora el proyecto de la clase Coche (ejercicio 6.5.5): aade un atributo

"cantidadDeRuedas" a la clase Vehiculo, junto con sus Get y Set. El constructor de

la clase Coche le dar el valor 4 y el constructor de la clase Moto le dar el valor 2.

se llama a los constructores de las clases base, empezando por la ms general y

en distinta cantidad, o porque incluso se aplique a distintos objetos.

adelante, cuando hablemos de "funciones virtuales".

tiempo de ejecucin. Es algo que nos encontraremos un poco ms

compilacin a qu mtodo se debe llamar, y lo tiene que descubrir en

ese caso el compilador puede llegar a no ser capaz de saber en tiempo de

del ejemplo 06_05a, que se puede aplicar a una puerta o a un portn), y en

aplica a distintos objetos de una misma jerarqua (como el "MostrarEstado"

El caso opuesto es el "polimorfismo puro", en el que un mismo mtodo se

compilacin a qu mtodo se debe llamar.

tipo de polimorfismo en el que el compilador sabe en tiempo de

de "sobrecarga" (tambin conocida como "polimorfismo ad-hoc"). Es un

parmetros, y se comportan de forma que puede ser distinta, son ejemplos

"Puerta(int ancho, int alto)", que se llaman igual pero reciben distintos

En nuestro ltimo ejemplo (06_06a), los dos constructores "Puerta()" y

persona cuando salude.

Revisin 0.99zz Pgina 215

mtodo Saludar, que reciba un parmetro, que ser el texto que debe decir esa

(6.7.1) A partir de las clases del ejercicio 6.6.1, aade a la clase "Persona" un nuevo

Ejercicios propuestos:

public class Animal

// ------------------

Gato a4
= new Gato();
Console.WriteLine();

Perro a3
= new Perro();
Console.WriteLine();

GatoSiames a2 = new GatoSiames();


Console.WriteLine();

public class Ejemplo_06_08a


{
public static void Main()
{
Animal a1
= new Animal();
Console.WriteLine();

using System;

// Ejemplo_06_08a.cs
// Orden de llamada a los constructores
// Introduccin a C#, por Nacho Cabanes

GatoSiames, como se ve en este ejemplo:

Revisin 0.99zz Pgina 216

"Animal", el orden de ejecucin de los constructores sera: Animal, Gato,

"GatoSiams", que deriva de una clase "Gato", que a su vez procede de una clase

terminando por la ms especfica. Por ejemplo, si creamos una clase

Cuando creamos objetos de una clase derivada, antes de llamar a su constructor

puede tener varias formas, ya sea porque reciba distintos tipos de parmetros y/o

Existen dos tipos especialmente importantes de polimorfismo:

6.8. Orden de llamada de los constructores

El concepto de "polimorfismo" se refiere a que una misma funcin (un mtodo)

6.7. Polimorfismo y sobrecarga

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

public Animal()
{
Console.WriteLine("Ha nacido un animal");
}

(6.8.1) Crea un nico fuente que contenga las siguientes clases:

Ejercicios propuestos:

Ha nacido un animal
Ha nacido un gato

Ha nacido un animal
Ha nacido un perro

Ha nacido un animal
Ha nacido un gato
Ha nacido un gato siams

Ha nacido un animal

El resultado de este programa es:

public class GatoSiames: Gato


{
public GatoSiames()
{
Console.WriteLine("Ha nacido un gato siams");
}
}

// ------------------

public class Gato: Animal


{
public Gato()
{
Console.WriteLine("Ha nacido un gato");
}
}

// ------------------

public class Perro: Animal


{
public Perro()
{
Console.WriteLine("Ha nacido un perro");
}
}

// ------------------

Revisin 0.99zz Pgina 217

Introduccin a la programacin con C#, por Nacho Cabanes

cada una de esas clases.

Una clase "PruebaDeTrabajadores", que cree un objeto perteneciente a

escriba en pantalla "Soy ingeniero informtico".

Una clase IngenieroInformatico, que derive de Ingeniero, cuyo constructor

pantalla "Soy ingeniero".

Una clase Ingeniero, que derive de Trabajador, cuyo constructor escriba en

pantalla "Soy analista".

Una clase Analista, que derive de Trabajador, cuyo constructor escriba en

en pantalla "Soy programador".

Una clase Programador, que derive de Trabajador, cuyo constructor escriba

trabajador".

Una clase Trabajador, cuyo constructor escriba en pantalla "Soy un

Revisin 0.99zz Pgina 218

prueba que defina un coche y una moto, y comprueba su funcionamiento.

te avise del momento en que se entra a cada constructor. Crea un programa de

(6.8.4) Crea una versin alternativa de las clases Vehiculo, Coche, Moto (6.7.4), que

funcionamiento.

"Creando nave en posicin indicada por el usuario", segn el caso. Comprueba su

constructores de Nave escriba en pantalla "Creando nave en posicin prefijada" o

que el constructor de Sprite escriba en pantalla "Creando sprite" y los

(6.8.3) Crea una versin alternativa del esqueleto del ConsoleInvaders (6.7.3) en la

funcionamiento.

constructor de Libro escriba en pantalla "Creando libro". Comprueba su

constructor de Documento escriba en pantalla "Creando documento" y el

(6.8.2) Crea una variante del proyecto Libro (ejercicio 6.7.2) en la que el

Introduccin a la programacin con C#, por Nacho Cabanes

esa clase, lo podramos conseguir as:

public class Ejemplo_07_01a


{
public static void Main()
{
Console.WriteLine("Pulsa Intro para borrar");
Console.ReadLine();

public class Hardware


{
public static void BorrarPantalla()
{
for (byte i = 0; i < 25; i ++)
Console.WriteLine();
}
}

using System;

Revisin 0.99zz Pgina 219

clase "Hardware" sin necesidad de crear primero un objeto perteneciente a

ejemplo, si queremos que se pueda usar la funcin "BorrarPantalla" de una

podra usar sin necesidad de declarar ningn objeto de la clase. Por

"static", indica que es un "mtodo de clase", es decir, un mtodo que se

De igual modo, si un mtodo (una funcin) est precedido por la palabra

la cantidad ms frecuente).

todos los coches que podamos encontrar tendrn 4 ruedas, aunque esa sea

habitual, y por eso casi nunca usaremos atributos "static" (por ejemplo, no

se podra declarar como "static". En el mundo real, esto es muy poco

para cualquier objeto que pertenezca a esa clase (cualquier coche). Por eso,

podramos suponer que el atributo "numeroDeRuedas" va a tener el valor 4

los objetos de la clase. Por ejemplo, si hablamos de coches convencionales,

que es una "variable de clase", es decir, que su valor es el mismo para todos

La palabra "static" delante de un atributo (una variable) de una clase, indica

// Ejemplo_07_01a.cs
// Mtodos "static"
// Introduccin a C#, por Nacho Cabanes

nuestros objetos no los estamos declarando como "static". Vamos a ver el motivo:

creamos en el tema 5. En cambio, los mtodos (funciones) que pertenecen a

acompaado de la palabra "static". Lo mismo ocurra con las funciones que

Desde un principio, nos hemos encontrado con que "Main" siempre iba

7.1. La palabra "static"

7. Utilizacin avanzada de clases

Introduccin a la programacin con C#, por Nacho Cabanes

acceder a sus mtodos desde "Main":

Ampla

el

ejemplo

07_01a

con

un

funcin

llamada

contrario que en el ejercicio 7.1.1, esta versin no ser "static".


Revisin 0.99zz Pgina 220

escriba centrado horizontalmente el texto que se le indique como parmetro. Al

(7.1.2) Ampla el ejemplo 07_01b con un funcin llamada "EscribirCentrado", que

indique como parmetro.

"EscribirCentrado", que escriba centrado horizontalmente el texto que se le

(7.1.1)

Ejercicios propuestos:

public class Ejemplo_07_01b


{
public static void Main()
{
Console.WriteLine("Pulsa Intro para borrar");
Console.ReadLine();
Hardware miPantalla = new Hardware();
miPantalla.BorrarPantalla();
Console.WriteLine("Borrado!");
}
}

public class Hardware


{
public void BorrarPantalla()
{
for (byte i = 0; i < 25; i ++)
Console.WriteLine();
}
}

using System;

"static"

Declarar un objeto de la clase correspondiente, y entonces s podremos

"clases").

desde "Main" (como hicimos en el tema 5, cuando an no conocamos las

declaradas como "static", por lo que podrn ser utilizadas directamente

Que todas las dems funciones de nuestro fuente tambin estn

// Ejemplo_07_01b.cs
// Alternativa a 07_01a, sin mtodos "static"
// Introduccin a C#, por Nacho Cabanes

Por eso, como nuestro "Main" debe ser static, deberemos siempre elegir entre:

Desde una funcin "static" no se puede llamar a otras funciones que no lo sean.

Hardware.
.BorrarPantalla();
Console.WriteLine("Borrado!");

Introduccin a la programacin con C#, por Nacho Cabanes

public class Perro: Animal


{

// ------------------

public class Animal


{
public Animal()
{
Console.WriteLine("Ha nacido un animal");
}
}

// ------------------

public class Ejemplo_07_02a


{
public static void Main()
{
Perro[] misPerros = new Perro[5];
for (byte i = 0; i < 5; i ++)
misPerros[i] = new Perro();
}
}

using System;

// Ejemplo_07_02a.cs
// Array de objetos
// Introduccin a C#, por Nacho Cabanes

Un fuente completo de ejemplo podra ser

Perro[
[] misPerros = new Perro[5];
for (byte i = 0; i < 5; i ++)
misPerros[i] = new Perro();

del apartado 6.8 y crear un array de 5 perros as:

Revisin 0.99zz Pgina 221

luego para cada uno de los elementos. Por ejemplo, podramos partir del ejemplo

Deberemos usar "new" dos veces: primero para reservar memoria para el array, y

ese caso, podemos almacenar todos ellos en un "array".

que necesitemos manipular varios objetos pertenecientes a la misma clase. En

Es muy frecuente que no nos baste con tener un nico objeto de una clase, sino

7.2. Arrays de objetos

descompuesta en funciones), en la que los mtodos y variables no sean "static".

(7.1.3) Crea una nueva versin del ejercicio 5.2.3 (base de datos de ficheros,

Introduccin a la programacin con C#, por Nacho Cabanes

nacido
nacido
nacido
nacido
nacido
nacido
nacido
nacido
nacido
nacido

un
un
un
un
un
un
un
un
un
un

animal
perro
animal
perro
animal
perro
animal
perro
animal
perro

// Ejemplo_07_02b.cs

Un ejemplo ms detallado:

misAnimales[0] = new Perro();


misAnimales[1] = new Gato();
misAnimales[2] = new GatoSiames();

Animal[] misAnimales = new Animal[3];

ellos sern perros, otros gatos, etc.),

Revisin 0.99zz Pgina 222

que realmente contenga objetos de distintas subclases (en este caso, unos de

Adems, existe una peculiaridad curiosa: podemos crear un array de "Animales",

reciba los parmetros X e Y.

distinta coordenada X). Necesitars un nuevo constructor en la clase Enemigo, que

en una misma fila (todos compartirn una misma coordenada Y, pero tendrn

(7.2.3) Ampla el esqueleto del ConsoleInvaders (6.7.3), para que haya 10 enemigos

ver los datos de los ya existentes.

hasta 1.000 libros. Main mostrar un men que permita aadir un nuevo libro o

(7.2.2) Ampla el proyecto Libro (ejercicio 6.7.2), de modo que permita guardar

tres objetos.

relacionadas), en la que no se cree un nico objeto de cada clase, sino un array de

(7.2.1) Crea una versin ampliada del ejercicio 6.8.1 (clase Trabajador y

Ejercicio propuesto:

Ha
Ha
Ha
Ha
Ha
Ha
Ha
Ha
Ha
Ha

y su salida en pantalla, que recuerda a la del apartado 6.8, sera

public Perro()
{
Console.WriteLine("Ha nacido un perro");
}

Introduccin a la programacin con C#, por Nacho Cabanes

misAnimales[7] = new Animal();

public class GatoSiames: Gato


{
public GatoSiames()
{

// ------------------

public class Gato: Animal


{
public Gato()
{
Console.WriteLine("Ha nacido un gato");
}
}

// ------------------

public class Perro: Animal


{
public Perro()
{
Console.WriteLine("Ha nacido un perro");
}
}

// ------------------

public class Animal


{
public Animal()
{
Console.WriteLine();
Console.WriteLine("Ha nacido un animal");
}
}

// ------------------

for (byte i=3; i<7; i++)


misAnimales[i] = new Perro();

misAnimales[0] = new Perro();


misAnimales[1] = new Gato();
misAnimales[2] = new GatoSiames();

public class Ejemplo_07_02b


{
public static void Main()
{
Animal[] misAnimales = new Animal[8];

using System;

// Array de objetos de distintas clases


// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 223

Introduccin a la programacin con C#, por Nacho Cabanes

Console..WriteLine("Ha nacido un gato siams");

Revisin 0.99zz Pgina 224

sea un string de letras, como "}{" o "XX"). Si estas imgenes no se muestran

usar una "imagen" diferente. Puedes usar la "imagen" que quieras (siempre que

filas). Cada tipo de enemigos ser una subclase de Enemigo, que se distinguir por

enemigos de un mismo tipo, pero distinto del tipo de los elementos de las otras

enemigos, y un array que contenga 3x10 enemigos (3 filas, cada una con 10

(7.2.6) Ampla el esqueleto del ConsoleInvaders (7.2.3), para que haya tres tipos de

usar el constructor adecuado.

preguntar al usuario si desea guardar un documento genrico o un libro, para

1000 documentos de cualquier tipo. A la hora de aadir un documento, se

(7.2.5) Ampla el proyecto Libro (ejercicio 7.2.2), de modo que permita guardar

clase.

relacionadas), crea un array de trabajadores en el que no sean todos de la misma

(7.2.4) A partir del ejemplo 07.02b y del ejercicio 6.8.1 (clase Trabajador y

Ejercicios propuestos:

primera. Pronto veremos los posibles problemas y la forma de solucionarlos.

Si los objetos tienen otros mtodos, no slo el constructor, no todo funcionar a la

Ha nacido un animal

Ha nacido un animal
Ha nacido un perro

Ha nacido un animal
Ha nacido un perro

Ha nacido un animal
Ha nacido un perro

Ha nacido un animal
Ha nacido un perro

Ha nacido un animal
Ha nacido un gato
Ha nacido un gato siams

Ha nacido un animal
Ha nacido un gato

Ha nacido un animal
Ha nacido un perro

La salida de este programa sera:

Introduccin a la programacin con C#, por Nacho Cabanes

public class Animal


{

// ------------------

misAnimales[0].Hablar();
misAnimales[1].Hablar();
misAnimales[2].Hablar();

misAnimales[0] = new Perro();


misAnimales[1] = new Gato();
misAnimales[2] = new Animal();

// Ahora los creamos desde un array


Animal[] misAnimales = new Animal[3];

// Linea en blanco, por legibilidad


Console.WriteLine();

miPerro.Hablar();
miGato.Hablar();
miAnimal.Hablar();

public class Ejemplo_07_03a


{
public static void Main()
{
// Primero creamos un animal de cada tipo
Perro miPerro = new Perro();
Gato miGato = new Gato();
Animal miAnimal = new Animal();

using System;

// Ejemplo_07_03a.cs
// Array de objetos, sin "virtual"
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 225

despus comentaremos qu ocurre al ejecutarlo y cmo solucionarlo:

nico mtodo "Hablar", que se redefinir en cada una de las clases hijas, y

Vamos a verlo con un ejemplo que, en vez de tener constructores, va a tener un

correctamente... pero con los mtodos podemos encontrar problemas.

una de las clases derivadas, y hemos visto que los constructores se llaman

clase base en el momento de definirlo, pero insertando realmente objetos de cada

En el ejemplo anterior hemos visto cmo crear un array de objetos, usando slo la

7.3. Funciones virtuales. La palabra "override"

solucionaremos en el siguiente apartado.

correctamente en pantalla al lanzar una partida, no te preocupes, lo

Introduccin a la programacin con C#, por Nacho Cabanes

miPerro.Hablar();
miGato.Hablar();
miAnimal.Hablar();

Perro miPerro = new Perro();


Gato miGato = new Gato();
Animal miAnimal = new Animal();

se consigue con este fragmento:

Revisin 0.99zz Pgina 226

gato debera decir "Miau" y un animal genrico debera comunicarse. Eso es lo que

La primera parte era de esperar: si creamos un perro, debera decir "Guau", un

Estoy comunicndome...
Estoy comunicndome...
Estoy comunicndome...

Guau!
Miauuu
Estoy comunicndome...

La salida de este programa es:

eso es lo que deseas". Equivale a un "s, s que estoy redefiniendo este mtodo").

algo como "ests redifiniendo este mtodo; aade la palabra new para indicar que

void Hablar" sirve simplemente para anular un "warning" del compilador, que dice

(Recuerda que, como vimos en el apartado 6.4, ese "new" que aparece en "new

public new void Hablar()


{
Console.WriteLine("Miauuu");
}

public class Gato: Animal


{

// ------------------

public class Perro: Animal


{
public new void Hablar()
{
Console.WriteLine("Guau!");
}
}

// ------------------

public void Hablar()


{
Console.WriteLine("Estoy comunicndome...");
}

Introduccin a la programacin con C#, por Nacho Cabanes

public class Ejemplo_07_03b


{
public static void Main()
{
// Primero creamos un animal de cada tipo
Perro miPerro = new Perro();
Gato miGato = new Gato();
Animal miAnimal = new Animal();

using System;

// Ejemplo_07_03b.cs
// Array de objetos, con "virtual"
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 227

dejar claro que debe reemplazar al mtodo "virtual" original), as:

subclases), y emplear en las clases hijas la palabra "override" en vez de "new" (para

indicar al compilador que ese mtodo probablemente ser redefinido en las

La forma de conseguirlo es declarar ese mtodo "Hablar" como "virtual" (para

clases hijas, y que, en ese caso, debe prevalecer lo que indiquen las clases hijas.

el mtodo "Hablar" que se usa en la clase Animal quiz sea redefinido por otras

Para conseguir este comportamiento, debemos indicar a nuestro compilador que

pudiera contener distintos tipos de animales.

un array de perros y otros de gatos, sino poder crear un array de animales, y que

Generalmente, no ser esto lo que queramos. Sera interesante no necesitar crear

Guau!
Miauuu
Estoy comunicndome...
Revisin 0.99zz Pgina 228

un array de animales, pero cada uno "Habla" como corresponde a su especie:

El resultado de este programa ya s es el que posiblemente desebamos: tenemos

public override void Hablar()


{
Console.WriteLine("Miauuu");
}

public class Gato: Animal


{

// ------------------

public class Perro: Animal


{
public override void Hablar()
{
Console.WriteLine("Guau!");
}
}

// ------------------

public class Animal


{
public virtual void Hablar()
{
Console.WriteLine("Estoy comunicndome...");
}
}

// ------------------

pesar de que hayamos indicado que se trata de un Perro u otra subclase distinta.

hace lo que corresponde a un Animal genrico (dice "Estoy comunicndome"), a

misAnimales[0].Hablar();
misAnimales[1].Hablar();
misAnimales[2].Hablar();

misAnimales[0] = new Perro();


misAnimales[1] = new Gato();
misAnimales[2] = new Animal();

// Ahora los creamos desde un array


Animal[] misAnimales = new Animal[3];

Introduccin a la programacin con C#, por Nacho Cabanes

// Linea en blanco, por legibilidad


Console.WriteLine();

miPerro..Hablar();
miGato.Hablar();
miAnimal.Hablar();

Es decir, como la clase base es "Animal", y el array es de "animales", cada elemento

misAnimales[0].Hablar();
misAnimales[1].Hablar();
misAnimales[2].Hablar();

misAnimales[0] = new Perro();


misAnimales[1] = new Gato();
misAnimales[2] = new Animal();

Animal[
[] misAnimales = new Animal[3];

segundo es un gato y el tercero es un animal genrico:

pesar de que despus digamos que el primer elemento del array es un perro, el

En cambio, si creamos un array de animales, no se comporta correctamente, a

Introduccin a la programacin con C#, por Nacho Cabanes

La nave que

Revisin 0.99zz Pgina 229

ampliarlas. En ese caso, no hace falta que volvamos a teclear todo lo que haca el

completo las posibilidades del mtodo equivalente de la superclase, sino

Puede ocurrir que en un mtodo de una clase hija no nos interese redefinir por

7.4. Llamando a un mtodo de la clase "padre"

maneja el usuario debe ser blanca.

puedes usar Console.ForegroundColor = ConsoleColor.Green;).

tipo de enemigos debe ser de un color distinto. (Nota: para cambiar colores

imgenes correctas de los enemigos, usando "virtual" y "override". Adems, cada

(7.3.5) Ampla el esqueleto de ConsoleInvaders (7.2.6) para que muestre las

como debe.

Recuerda usar "virtual" y "override" si en un primer momento no se comporta

La opcin de mostrar datos llamar a los correspondientes mtodos ToString.

mostrar tambin el nmero de pginas de un libro y la procedencia de un artculo.

aadir Artculos o Libros, no documentos genricos. El mtodo ToString deber

Articulo, que aada el campo "procedencia". El cuerpo del programa permitir

formada por ttulo, autor y ubicacin, separados por guiones. Crea una clase

clase Libro, tendrn un mtodo ToString, que devuelva una cadena de texto

(7.3.4) Ampla el proyecto Libro (ejercicio 7.2.5): tanto la clase Documento como la

"new".

(7.3.3) Crea una variante del ejercicio anterior (7.3.2), que use "override" en vez de

usando "new" y probndolo desde "Main".

clase, y exista un mtodo "Saludar" que se redefina en todas las clases hijas,

que se cree un nico array "de trabajadores", que contenga un objeto de cada

(7.3.2) Crea una variante del ejercicio 7.2.2 (array de Trabajador y derivadas), en la

en la que se cree un nico array que contenga personas de varios tipos.

(7.3.1) Crea una versin ampliada del ejercicio 6.5.1 (Persona, PersonaInglesa, etc),

Ejercicios propuestos:

o estructura similar (como las "listas", que veremos ms adelante).

programa, y especialmente si todos esos objetos van a ser parte de un nico array

trivial, sino que vamos a tener objetos de varias clases coexistiendo en el

"override" en las clases derivada, especialmente si no se trata de un programa

es habitual que realmente lo que necesitemos sea "virtual" en la clase base y

de que deberamos aadir la palabra "new" porque estamos redefiniendo algo...

Nota: Esto que nos acaba de ocurrir va a ser frecuente. Si el compilador nos avisa

Guau!
Miauuu
Estoy comunicndome...

Introduccin a la programacin con C#, por Nacho Cabanes

// Linea en blanco

public class GatoSiames: Gato

// ------------------

public class Gato: Animal


{
public void Hablar()
{
Console.WriteLine("Miauuu");
}
}

// ------------------

public class Animal


{
// Todos los detalles estn en las subclases
}

// ------------------

miGato.Hablar();
Console.WriteLine();
miGato2.Hablar();

public static void Main()


{
Gato miGato = new Gato();
GatoSiames miGato2 = new GatoSiames();

public class Ejemplo_07_04a


{

using System;

// Ejemplo_07_04a.cs
// Ejemplo de clases: Llamar a la superclase
// Introduccin a C#, por Nacho Cabanes

Este podra ser un fuente completo:

public new void Hablar()


{
base.Hablar();
Console.WriteLine("Pfff");
}

pero diciendo "Pfff" despus, as:

Revisin 0.99zz Pgina 230

Por ejemplo, podemos hacer que un Gato Siams hable igual que un Gato normal,

de la palabra "base".

mtodo de la clase base, sino que podemos llamarlo directamente, precedindolo

Introduccin a la programacin con C#, por Nacho Cabanes

public new void Hablar()


{
base.Hablar();
Console.WriteLine("Pfff");
}

los tres tipos de enemigos deben basarse en ste.

Revisin 0.99zz Pgina 231

un nico constructor que reciba las coordenadas X e iniciales. Los constructores de

(7.4.4) Ampla el esqueleto de ConsoleInvaders (7.3.5) para que en Enemigo haya

Articulo.

clase Libro se apoye en el de la clase Documento, y tambin lo haga el de la clase

(7.4.3) Refina el proyecto Libro (ejercicio 7.3.4), para que el mtodo ToString de la

todas las clases hijas se apoye en el de la clase "Trabajador".

(7.4.2) Crea una versin ampliada del ejercicio 7.4.1, en la que el constructor de

de todas las clases hijas se apoye en el de la clase "Trabajador".

(7.4.1) Crea una versin ampliada del ejercicio 7.3.3, en la que el mtodo "Hablar"

Ejercicios propuestos:

parmetros).

constructor sin parmetros de Rectangulo, no en el que tiene x e y como

(Si no hacemos esto, el constructor de RectanguloRelleno se basara en el

public RectanguloRelleno (int x,, int y )


: base (x,
, y))
{
// Pasos adicionales
// que no da un rectangulo "normal"
}

equivalente de la clase "Rectangulo", lo haramos as:

"RectanguloRelleno" que recibe las coordenadas "x" e "y" se base en el constructor

hereda de otra clase "Rectangulo" y queremos que el constructor de

de una clase derivada. Por ejemplo, si tenemos una clase "RectanguloRelleno" que

Tambin podemos llamar a un constructor de la clase base desde un constructor

Miauuu
Pfff

Miauuu

Su resultado sera

Introduccin a la programacin con C#, por Nacho Cabanes

preferible usar otro nombre en los parmetros:


Revisin 0.99zz Pgina 232

En muchos casos, podemos evitar este uso de "this". Por ejemplo, normalmente es

public void Escribir()


{
Console.SetCursorPosition(x,y);
Console.WriteLine(texto);
}

public Titulo(int x, int y, string texto)


{
this.x = x;
this.y = y;
this.texto = texto;
}

public class Titulo


{
private int x;
private int y;
private string texto;

// ------------------

public class Ejemplo_07_05a


{
public static void Main()
{
Titulo t = new Titulo(38,5,"Hola");
t.Escribir();
}
}

using System;

// Ejemplo_07_05a.cs
// Primer ejemplo de uso de "this": parmetros
// Introduccin a C#, por Nacho Cabanes

Un fuente completo sera as:

public void MoverA (int x,


, int y))
{
this.x = x;;
this.y = y;;
}

que stos:

uso es dar valor a los atributos, incluso si los parmetros tienen el mismo nombre

Podemos hacer referencia al objeto que estamos usando, con "this". Un primer

7.5. La palabra "this": el objeto actual

Introduccin a la programacin con C#, por Nacho Cabanes

public class Titulo


{

// ------------------

public class Ejemplo_07_05b


{
public static void Main()
{
Titulo t = new Titulo(38,5,"Hola");
t.Escribir();
}
}

using System;

// Ejemplo_07_05b.cs
// Segundo ejemplo de uso de "this": constructores
// Introduccin a C#, por Nacho Cabanes

Nuevamente, podramos hacer un fuente completo de ejemplo:

Revisin 0.99zz Pgina 233

public class Jugador1 : Jugador

// ------------------

public class Jugador


{
protected Jugador adversario;
}

// ------------------

public class Ejemplo_07_05c


{
public static void Main()
{
Jugador1 j1 = new Jugador1();
Jugador2 j2 = new Jugador2();
}
}

using System;

// Ejemplo_07_05c.cs
// Dos clases que se usan mutuamente: recursividad indirecta
// Introduccin a C#, por Nacho Cabanes

valor de X.

este otro constructor, que recibe X e Y, y que se basa en el anterior para fijar el

Jugador2, y lo contrario para el otro jugador, as:

Revisin 0.99zz Pgina 234

"adversario" como atributo, y que el Jugador1 indique que su adversario es de tipo

entre s, y nos podramos sentir tentados de hacer que la clase Jugador tenga un

Jugador, heredar de ella las clases Jugador1 y Jugador2, que sern muy parecidas

otros. Por ejemplo, en un juego de 2 jugadores, podramos tener una clase

La palabra "this" se usa mucho tambin para que unos objetos "conozcan" a los

public void Escribir()


{
Console.SetCursorPosition(x,y);
Console.WriteLine(texto);
}

public Titulo(int nuevaY, string txt)


: this (40-txt.Length/2, nuevaY, txt)
{
}

public Titulo(int nuevaX, int nuevaY, string txt)


{
x = nuevaX;
y = nuevaY;
texto = txt;
}

private int x;
private int y;
private string texto;

Introduccin a la programacin con C#, por Nacho Cabanes

coordenada X (y que podra prefijar la Y al valor 0, por ejemplo), y tambin existe

En ese ejemplo, existira un constructor de RectanguloRelleno que recibiera slo la

public RectanguloRelleno (int x,, int y ) : this (x)


)
{
fila = y;
;
// Pasos adicionales
}

a partir de otro que tenga distintos parmetros:

Pero "this" tiene tambin otros usos. Por ejemplo, podemos crear un constructor

public void MoverA (int nuevaX,


, int nuevaY)
)
{
x = nuevaX;;
y = nuevaY;;
}

Y en ese caso se puede (y se suele) omitir "this":

public void MoverA (int nuevaX,


, int nuevaY)
)
{
this.x = nuevaX;
;
this.y = nuevaY;
;
}

Introduccin a la programacin con C#, por Nacho Cabanes

public Jugador1()
{
adversario = new Jugador2();
}

public void SetAdversario(Jugador nuevoAdversario)


{
adversario = nuevoAdversario;

public class Jugador


{
protected Jugador adversario;

// ------------------

public class Ejemplo_07_05d


{
public static void Main()
{
Jugador j1 = new Jugador();
Jugador j2 = new Jugador();
j1.SetAdversario(j2);
j2.SetAdversario(j1);
}
}

using System;

// Ejemplo_07_05d.cs
// Dos clases que se usan mutuamente: "Main" coordina
// Introduccin a C#, por Nacho Cabanes

jugador quin es su adversario:

Revisin 0.99zz Pgina 235

programa principal), es que sea el programa principal el que indique a cada

Una alternativa mucho menos peligrosa (pero que, a cambio, complica el

memoria que est reservada para llamadas recursivas.

un nuevo jugador2 y as sucesivamente, hasta finalmente desbordar la zona de

ste crea un nuevo jugador1 (en vez de utilizar el ya existente), que a su vez crea

estamos creando una recursividad indirecta sin fin: el jugador1 crea un jugador2,

lanzando una excepcin de desbordamiento de pila (Stack Overflow), porque

Pero este programa se queda colgado un instante, hasta terminar finalmente

public class Jugador2 : Jugador


{
public Jugador2()
{
adversario = new Jugador1();
}
}

// ------------------

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 236

queremos que se puedan comunicar con la clase contenedora, deberemos usar

(las "puertas" no saben otros detalles de la "casa" a la que pertenecen). Si

"puertas"), pero las clases contenidas no saben nada de la clase que las contiene

contenedora sabe los detalles de las clases contenidas (la "casa" conoce a sus

Hay que recordar que, en general, cuando una clase contiene a otras, la clase

public void SetAdversario(Jugador nuevoAdversario)


{
adversario = nuevoAdversario;
}

// Y yo soy su adversario
adversario.SetAdversario( this );

public Jugador(Jugador adversario)


{
// Mi adversario es el que me indican
SetAdversario( adversario );

public Jugador()
{
}

public class Jugador


{
protected Jugador adversario;

// ------------------

public class Ejemplo_07_05e


{
public static void Main()
{
Jugador j1 = new Jugador(); // Creado sin ms detalles
Jugador j2 = new Jugador(j1); // Indicando su adversario
}
}

using System;

// Ejemplo_07_05e.cs
// Dos clases que se usan mutuamente: "this"
// Introduccin a C#, por Nacho Cabanes

cambio de complicar ligeramente las clases auxiliares:

ese "yo" equivaldr a un "this". En general, eso simplificar el programa principal, a

Otra alternativa es que un Jugador le pueda decir a otro "yo soy tu adversario", y

Introduccin a la programacin con C#, por Nacho Cabanes

como parmetros:

"new", o provocaremos una recursividad indirecta sin fin, como en el primer

Revisin 0.99zz Pgina 237

mtodo llamado "operador +", y que devolvera un dato esttico del tipo con el

No entraremos mucho ms en detalle, pero la idea es que redefiniramos un

simplemente " matriz3 = matriz1 + matriz2"

hacer algo como "matriz3 = suma( matriz1, matriz2 )" podramos hacer

creado, de forma ms cmoda y legible. As, para sumar dos matrices, en vez de

significado, para poder sumar (por ejemplo) objetos que nosotros hayamos

Pues bien, en C# se puede "sobrecargar" operadores, es decir, redefinir su

sumar dos nmeros.

operaciones. Por ejemplo, el operador "+" se usa para indicar que queremos

Los "operadores" son los smbolos que se emplean para indicar ciertas

7.6. Sobrecarga de operadores

misma clase, prefijando unas coordenadas que te parezcan las ms adecuadas.

sin parmetros de la clase Nave se apoye en el constructor con parmetros de la

(7.5.4) Ampla el esqueleto de ConsoleInvaders (7.4.4), de modo que el constructor

puertas.

programa de prueba que cree una casa y muestre sus datos y los de sus tres

ancho y su alto y la superficie de la casa en la que se encuentran. Crea un

puertas tendrn un ancho, un alto y un mtodo "MostrarEstado" que muestre su

"MostrarEstado" que escriba su superficie. Cada casa debe contener 3 puertas. Las

(7.5.3) Crea una clase Casa, con una superficie (por ejemplo, 90 m 2) y un mtodo

Revisin 0.99zz Pgina 238

parmetros y otro constructor que reciba slo el numerador. Crea un mtodo

numerador y un denominador. Crea un constructor que reciba ambos datos como

(7.6.3) Crea una clase "Fraccion", que represente a una fraccin, formada por un

operador "+" como forma alternativa de realizar esa operacin.

argumento. Crea un mtodo que permita sumar un complejo a otro, y redefine el

datos, as como mtodos que permitan saber los valores de su mdulo y su

Crea tambin mtodos "get" y "set" para leer y modificar los valores de dichos

"imaginaria"). Incluye un constructor que reciba ambos datos como parmetros.

represente a un nmero complejo (formado por una parte "real" y una parte

(7.6.2) Si has estudiado los "nmeros complejos", crea una clase "Complejo", que

cambiar su valor).

crear mtodos "get" y "set" para leer los valores de posiciones de la matriz y para

sobrecargar el operador "+", pero no el operador "[]", de modo que tendrs que

posicin, escribir la matriz en pantalla y sumar dos matrices. (Nota: en C# puedes

mtodos para indicar el valor que hay en una posicin, leer el valor de una

(7.6.1) Desarrolla una clase "Matriz", que represente a una matriz de 3x3, con

Ejercicios propuestos:

una posicin.

mtodos Get para acceder a una posicin y mtodos Set para cambiar el valor de

corchetes estn entre los que no podremos cambiar. En su lugar, deberas crear

elemento de la matriz, pero C# no permite redefinir cualquier operador, y los

puedes pensar en sobrecargar los operadores [ y ] para acceder a un cierto

Eso s, debes tener presente que "no todo se puede redefinir". Por ejemplo,

Matriz matriz3 = matriz1 + matriz2;

simplemente

tres puertas.

Desde "Main", calcularamos una matriz como suma de otras dos haciendo

return nuevaMatriz;

otro mtodo "MostrarEstado" que escriba "Casa" y luego muestre el estado de sus

for (int x=0; x < tamanyo; x++)


for (int y=0; y < tamanyo; y++)
nuevaMatriz[x, y] = mat1[x, y] + mat2[x, y];

que muestre su ancho y su alto. Crea una clase Casa, que contenga 3 puertas y

(7.5.2) Crea una clase Puerta con un ancho, un alto y un mtodo "MostrarEstado"

"Nombre no detallado" al nombre de esa persona.

parmetro el nombre de esa persona. La versin sin parmetros asignar el valor

parmetros de la clase "Trabajador" se apoye en otro constructor que reciba como

(7.5.1) Crea una versin ampliada del ejercicio 7.4.2, en la que el constructor sin

Ejercicios propuestos:

public static Matriz operator +(Matriz mat1, Matriz mat2)


{
Matriz nuevaMatriz = new Matriz();

que estamos (por ejemplo, una Matriz) y recibira dos datos de ese mismo tipo

"this" para que la conozcan, en vez de crear una nueva clase contenedora con

ejemplo.

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

ejemplo, subir una persiana inmediatamente o hacer que la calefaccin se


encienda todos los das desde las 19h hasta las 23h, a una cierta temperatura).
(7.7.6) Completa el proyecto Libro (ejercicio 7.4.3), para que las clases de datos
tengan un mtodo "Contiene", que reciba un texto y devuelva el valor booleano
"true" cuando ese texto est contenido en el ttulo o en el autor (y en la
procedencia, para los artculos). El Main deber permitir al usuario realizar

Escribir, que escriba la fraccin en la forma "3 / 2". Redefine los operadores "+", "-",

"*" y "/" para que permitan realizar las operaciones habituales con fracciones.

(7.6.4) Crea una clase "Vector3", que represente a un vector en el espacio de 3

dimensiones. Redefine los operadores "+" y "-" para sumar y restar dos vectores,

"*" para hallar el producto escalar de dos vectores y "%" para calcular su producto

vectorial.

(7.7.8) Crea en el proyecto Libro una clase ListaDeDocumentos, que oculte a Main
los detalles de que internamente se trata de un array: deber permitir opciones
como aadir un documento, obtener los datos de uno de ellos, buscar entre la
lista de todos ellos, etc. Los criterios de diseo quedan a tu criterio. Por ejemplo,
puedes hacer que la bsqueda devuelve un array con los nmeros de ficha

La mejor forma de aplicar todos los conocimientos sobre clases y de ponerlos a

prueba es crear algn proyecto de una cierta complejidad, que incluya diferentes

clases, herencia, arrays de objetos, comunicacin entre dichos objetos, etc. Aqu

tienes unos cuantos ejercicios propuestos, sin solucin (y para los que no existir

una solucin nica):

Inicialmente estar desactivado, y lo volver a estar cuando llegue al margen de la


pantalla.
(7.7.11) En ConsoleInvaders, crea un mtodo "ColisionaCon" en la clase Sprite, que
reciba otro Sprite como parmetro y devuelva el valor booleano "true" si ambos
sprites estn "chocando" o "false" en caso contrario. Tendrs que pensar qu
relacin habr entre las coordenadas X e Y de ambos sprites para que "choquen".
(7.7.12) En ConsoleInvaders, crea una clase Ovni, con un nuevo tipo de Enemigo
que no estar siempre activo. Su mtodo Mover har que se mueva hacia la
derecha si ya est activo o, en caso contrario, que genere un nmero al azar para
decidir si debe activarse.
(7.7.13) En ConsoleInvaders, comprueba colisiones entre el disparo y el Ovni. Si
hay colisin, desaparecern ambos y el jugador obtendr 50 puntos.

laberinto de fondo, cuyas paredes no se puedan "pisar" (la clase Laberinto puede

tener mtodos que informen sobre si el jugador podra moverse a ciertas

coordenadas X e Y). Si el personaje toca a un enemigo, acabar la partida y se

regresar a la pantalla de bienvenida.

(7.7.4) Crea un proyecto "Laberintos", a partir del proyecto "Laberinto", aadiendo

premios que recoger, tres vidas para nuestro personaje y varios laberintos

distintos que recorrer.

(7.7.5) Crea un proyecto "SistemaDomotico", que simule un sistema domtico para

automatizar ciertas funciones en una casa: apertura y cierre de ventanas y

puertas, encendido de calefaccin, etc. Adems de esos elementos fsicos de la

casa, tambin existir un panel de control, desde el que el usuario podra controlar

Revisin 0.99zz Pgina 239

Revisin 0.99zz Pgina 240

nico disparo, y no se podr volver a disparar si est activo (en pantalla).

aadiendo tres enemigos que se muevan de lado a lado de forma autnoma y un

el resto de elementos, as como programar el comportamiento del sistema (por

hacia arriba hasta que desaparezca por la parte superior de la pantalla. Existir un

proyecto

(7.7.3) Crea un proyecto "Laberinto", a partir del proyecto "PersonajeMovil",

el

ConsoleInvaders) como alternativa a Console.ReadLine.

en

tecla (Espacio, por ejemplo), aparecer un disparo encima de la nave, y se mover

ya

(7.7.10) Crea una clase Disparo en ConsoleInvaders. Cuando el usuario pulse cierta

usado

Console.Readkey

habrs

enemigo). En cada pasada por el bucle de juego debers llamar a Mover.

Si quieres que el movimiento sea ms suave, puedes investigar sobre

posiblemente

comprobar la posicin inicial del primer enemigo y la posicin final del ltimo

movimiento quedan a tu criterio, pero podran ser "wasd" o las flechas del cursor.

(que

todo el bloque hacia la derecha y la izquierda de forma alternativa (debers

mover a un personaje (que puede ser representado por una letra X). Las teclas de

clase

Dibujar, que mostrar todo el array en pantalla, y un mtodo Mover, que mover

una

bienvenida, una pantalla de crditos y una partida, en la que el usuario podr

con

que se simplifique la lgica de la clase Partida. Esta clase tendr un mtodo

(7.5.4),

podra ampliar para crear un juego de plataformas. Existir una pantalla de

ConsoleInvaders

(7.7.2) Crea un proyecto "PersonajeMovil", que ser un esqueleto sobre el que se

de

correctamente.

esqueleto

"BloqueDeEnemigos", que ser la que contenga el array de enemigos, de modo

el

(7.7.9)

principio del tema 6. El proyecto no ser jugable, pero deber compilar

Ampla

ficha que cumpla con esos criterios.

(7.7.1) Crea un proyecto "Space Invaders" con todas las clases que vimos al

encontrados, o un array con el contenido de esas fichas, o el contenido la siguiente

interesante, como la de modificar datos, borrarlos u ordenarlos.

7.7. Proyectos completos propuestos

(7.7.7) Aade al proyecto Libro cualquier otra funcionalidad que te parezca

bsquedas, aprovechando esta nueva funcionalidad.

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

ellas.

Revisin 0.99zz Pgina 241

jugador y que se van rompiendo poco a poco cada vez que un disparo impacta con

(7.7.18) En ConsoleInvaders, aade las "torres defensivas", que protegen al

mostrarn en la pantalla de bienvenida.

las "mejores puntuaciones", que se actualizarn al terminar cada partida y se

(7.7.17) En ConsoleInvaders, crea la estructura que sea necesaria para almacenar

de presentacin.

desaparecer. Si se pierden las 3 vidas, acaba la partida y se volver a la pantalla

uno de esos disparos impacta con la nave, se perder una vida y el disparo

Ajusta la frecuencia de disparos, de modo que el juego contine siendo jugable. Si

una nueva clase o ampliar las funcionalidades de la clase Disparo que ya tienes).

puedan disparar (los disparos de los enemigos "va hacia abajo"; piensa si crear

(7.7.16) En ConsoleInvaders, aade la posibilidad de que algunos enemigos al azar

puntuacin y la cantidad de vidas restantes (que por ahora, siempre ser 3).

(7.7.15) En ConsoleInvaders, aade una clase "Marcador", que muestre la

obtendr 10 puntos.

enemigos. Si el disparo toca algn enemigo, ambos desaparecern y el jugador

(7.7.14) En ConsoleInvaders, comprueba colisiones entre el disparo y el bloque de

Introduccin a la programacin con C#, por Nacho Cabanes

Leer datos de l o escribir datos en l.


Cerrar el fichero.

x
x

// Para StreamWriter

pertenece a la clase File.


Revisin 0.99zz Pgina 242

El fichero de texto lo creamos con el mtodo (esttico) CreateText, que

podemos escribir informacin.

StreamWriter es la clase que representa a un fichero de texto en el que

Hay varias cosas que comentar sobre este programa:

fichero = File.CreateText("prueba.txt");
fichero.WriteLine("Esto es una lnea");
fichero.Write("Esto es otra");
fichero.WriteLine(" y esto es continuacin de la anterior");
fichero.Close();

public class Ejemplo_08_01a


{
public static void Main()
{
StreamWriter fichero;

using System;
using System.IO;

// Ejemplo_08_01a.cs
// Escritura en un fichero de texto
// Introduccin a C#, por Nacho Cabanes

Vamos a ver un ejemplo, que cree un fichero de texto y escriba algo en l:

un dispositivo que sea slo de lectura.

intentemos abrir un fichero que realmente no exista, o que tratemos de escribir en

tendremos que comprobar los posibles errores. Por ejemplo, puede ocurrir que

Eso s, no siempre conseguiremos realizar esas operaciones, as que adems

Abrir el fichero.

pasos:

Cuando queramos manipular un fichero, siempre deberemos hacerlo en tres

8.1. Escritura en un fichero de texto

8. Manejo de ficheros

Introduccin a la programacin con C#, por Nacho Cabanes

dato sin guardar.

Finalmente, debemos cerrar el fichero con Close, o podra quedar algn

hacemos en la consola.

Para escribir en el fichero, empleamos Write y WriteLine, al igual que

// Para StreamWriter

// Para StreamWriter

Revisin 0.99zz Pgina 243

public class Ejemplo_08_01c


{
public static void Main()
{
using (StreamWriter fichero = new StreamWriter("prueba.txt"))
{
fichero.WriteLine("Esto es una lnea");
fichero.Write("Esto es otra");
fichero.WriteLine(" y esto es continuacin de la anterior");
}
}
}

using System;
using System.IO;

// Ejemplo_08_01c.cs
// Escritura en un fichero de texto, con "using"
// Introduccin a C#, por Nacho Cabanes

que lee datos del fichero, de esta forma:

punto) de cerrar el fichero, empleando la orden "using" para delimitar el bloque

Existe otra sintaxis, ms compacta, que nos permite olvidarnos (hasta cierto

public class Ejemplo_08_01b


{
public static void Main()
{
StreamWriter fichero = new StreamWriter("prueba.txt");
fichero.WriteLine("Esto es una lnea");
fichero.Write("Esto es otra");
fichero.WriteLine(" y esto es continuacin de la anterior");
fichero.Close();
}
}

using System;
using System.IO;

// Ejemplo_08_01b.cs
// Escritura en un fichero de texto, con constructor
// Introduccin a C#, por Nacho Cabanes

constructor que reciba el nombre de fichero, as:

Una forma alternativa de crear el fichero es no usar "File.CreateText", sino un

Introduccin a la programacin con C#, por Nacho Cabanes

// Para StreamReader

Si queremos abrir un fichero que ya existe, usaremos OpenText, en lugar de


x

// Ejemplo_08_02b.cs
// Lectura de un fichero de texto, con constructor
Revisin 0.99zz Pgina 244

Nuevamente, deberemos cerrar el fichero al terminar de usarlo.


x

Nuevamente, podemos usar un constructor en vez de OpenText:

Para leer del fichero, usaramos ReadLine, como hacamos en la consola.


x

CreateText.

Para leer de un fichero no usaremos StreamWriter, sino StreamReader.


x

Las diferencias son:

fichero = File.OpenText("prueba.txt");
linea = fichero.ReadLine();
Console.WriteLine( linea );
Console.WriteLine( fichero.ReadLine() );
fichero.Close();

public class Ejemplo_08_02a


{
public static void Main()
{
StreamReader fichero;
string linea;

using System;
using System.IO;

// Ejemplo_08_02a.cs
// Lectura de un fichero de texto
// Introduccin a C#, por Nacho Cabanes

La estructura de un programa que leyera de un fichero de texto sera parecida a:

8.2. Lectura de un fichero de texto

vuelquen a un fichero de texto al terminar la ejecucin del programa.

(8.1.3) Amplia el proyecto Libro (ejercicio 7.7.8), de modo que todos los datos se

programa.

que todos los datos se vuelquen a un fichero de texto al terminar la ejecucin del

(8.1.2) Crea una versin de la base de datos de ficheros (ejercicio 5.2.3), de modo

la frase introducida sea "fin" (esa frase no deber guardarse en el fichero).

guarde en un fichero de texto llamado "registroDeUsuario.txt". Terminar cuando

(8.1.1) Crea un programa que vaya leyendo las frases que el usuario teclea y las

Ejercicios propuestos:

Introduccin a la programacin con C#, por Nacho Cabanes

// Para StreamReader

// Para StreamReader

contenido, de principio a fin.


Revisin 0.99zz Pgina 245

Normalmente no querremos leer slo una frase del fichero, sino procesar todo su

8.3. Lectura hasta el final del fichero

alternativa de "using".

(8.2.3) Crea una versin alternativa del ejercicio 8.2.2, empleando la sintaxis

StreamReader.

(8.2.2) Crea una versin alternativa del ejercicio 8.2.1, usando el constructor de

ejercicio 8.1.1 y las muestre en pantalla. Usa OpenText para abrirlo.

(8.2.1) Crea un programa que lea las tres primeras lneas del fichero creado en el

Ejercicios propuestos:

public class Ejemplo_08_02c


{
public static void Main()
{
using (StreamReader fichero = new StreamReader("prueba.txt"))
{
string linea = fichero.ReadLine();
Console.WriteLine( linea );
Console.WriteLine( fichero.ReadLine() );
}
}
}

using System;
using System.IO;

// Ejemplo_08_02c.cs
// Lectura de un fichero de texto, con "using"
// Introduccin a C#, por Nacho Cabanes

o bien utilizar la sintaxis alternativa, con la palabra "using":

public class Ejemplo_08_02b


{
public static void Main()
{
StreamReader fichero = new StreamReader("prueba.txt");
string linea = fichero.ReadLine();
Console.WriteLine( linea );
Console.WriteLine( fichero.ReadLine() );
fichero.Close();
}
}

using System;
using System.IO;

// Introduccin a C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

si

queremos

procesar

todo

fichero.Close();

un

fichero,

esta

lectura

Revisin 0.99zz Pgina 246

try-catch para que el programa no falle en el momento inicial, en el que quiz

se lean desde fichero (si existe) en el momento de lanzar el programa (puedes usar

(8.3.4) Ampla la base de datos de ficheros (ejercicio 8.1.2), de modo que los datos

fichero.

mostrarn las siguientes 24 lneas, y as sucesivamente hasta que termine el

lneas, para que d tiempo a leerlo. Cuando el usuario pulse la tecla Intro, se

pantalla el contenido de ese fichero, haciendo una pausa despus de cada 24

(8.3.3) Prepara un programa que pregunte un nombre de fichero y muestre en

(8.3.2) Crea una variante del ejemplo 08_03a, empleando "using" en vez de "Close".

"File.OpenText".

(8.3.1) Crea una variante del ejemplo 08_03a, empleando un constructor en vez de

Ejercicios propuestos:

Esos cambios sern parte de los ejercicios propuestos.

Por supuesto, podras emplear el constructor o "using" para acceder al fichero.

fichero = File.OpenText("prueba.txt");
do
{
linea = fichero.ReadLine();
if (linea != null)
Console.WriteLine( linea );
}
while (linea != null);

using System;
using System.IO;
public class Ejemplo_08_03a
{
public static void Main()
{
StreamReader fichero;
string linea;

// Ejemplo_08_03a.cs
// Lectura de un fichero de texto completo
// Introduccin a C#, por Nacho Cabanes

comprobacin debera ser repetitiva, as:

Habitualmente,

ha podido leer y que, por tanto estamos en el final del fichero.

una lnea, y comprobar si el resultado ha sido "null", lo que nos indicara que no se

En un fichero de texto, la forma de saber si hemos llegado al final es intentar leer

Introduccin a la programacin con C#, por Nacho Cabanes

fichero "log.txt", que puede existir anteriormente (y que no deber borrarse, sino
aadir al final de su contenido). Cada sesin acabar cuando el usuario pulse Intro

forma:

using System;
using System.IO;

// Ejemplo_08_04b.cs
// Aadir a un fichero de texto, con constructor y "using"
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 247

"true" para aadir (o "false" para sobreescribir el fichero, si ya existiera):

pero entonces tendremos que emplear un segundo parmetro booleano, que ser

Tambin podemos usar un constructor para aadir datos a un fichero existente,

fichero = File.AppendText("prueba2.txt");
fichero.WriteLine("Segunda lnea");
fichero.Close();

fichero = File.CreateText("prueba2.txt");
fichero.WriteLine("Primera lnea");
fichero.Close();

public class Ejemplo_08_04a


{
public static void Main()
{
StreamWriter fichero;

using System;
using System.IO;

// Ruta absoluta
// Ruta relativa

Revisin 0.99zz Pgina 248

"sumas.txt", que se encontrar en un subdirectorio llamado "resultados". Cada vez

su suma (con el formato "20 + 3 = 23") en pantalla y en un fichero llamado

(8.5.1) Crea un programa que pida al usuario pares de nmeros enteros y escriba

Ejercicios propuestos:

string nombreFichero = @"d:\ejemplos\ejemplo1.txt";

ser necesario delimitar los caracteres de control:

podemos indicar una arroba (@) justo antes de abrir las comillas, y entonces no

Como esta sintaxis puede llegar a resultar incmoda, en C# existe una alternativa:

string nombreFichero = "d:\\ejemplos\\ejemplo1.txt";


string nombreFichero2 = "..\\datos\\configuracion.txt";

escribir dichas barras invertidas repetidas, as:

que se usa en las cadenas de C y los lenguajes que derivan de l, deberemos

para separar los nombres de los directorios, coincide con el carcter de control

Debemos recordar que, como la barra invertida que se usa en sistemas Windows

el nombre de fichero incluya tambin la ruta.

Si un fichero al que queremos acceder se encuentra en otra carpeta, basta con que

8.5. Ficheros en otras carpetas

sin teclear nada.

(8.4.1) Un programa que pida al usuario que teclee frases, y las almacene en el

informacin, cerrarlo, y luego volverlo a abrir para aadir datos, de la siguiente

// Ejemplo_08_04a.cs
// Aadir a un fichero de texto
// Introduccin a C#, por Nacho Cabanes

Ejercicios propuestos:

AppendText ("aadir texto"). Por ejemplo, podramos crear un fichero, guardar

La idea es sencilla: en vez de abrirlo con CreateText ("crear texto"), usaremos

8.4. Aadir a un fichero existente

lnea del fichero ser la 1, la segunda ser la 2, y as sucesivamente).

contengan esa frase. Cada frase se debe preceder del nmero de lnea (la primera

una frase a buscar, y que muestre en pantalla todas las lneas de ese fichero que

(8.3.6) Crea un programa que pida al usuario el nombre de un fichero de texto y

desde fichero (si existe) en el momento de poner el programa en marcha.

(8.3.5) Amplia el proyecto Libro (ejercicio 8.1.3), de modo que los datos se lean

using (StreamWriter fichero = new StreamWriter("prueba2.txt", true))


{
fichero.WriteLine("Segunda lnea");
}

public class Ejemplo_08_04b


{
public static void Main()
{
using (StreamWriter fichero = new StreamWriter("prueba2.txt", false))
{
fichero.WriteLine("Primera lnea");
}

todava no existan datos en fichero; dentro de poco veremos formas alternativas

de saber si existe).

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

problema que podemos tener al acceder a un fichero. Puede ocurrir que no

Por ello, una forma ms eficaz de comprobar si ha existido algn tipo de error es

// Ejemplo_08_06a.cs
// Saber si un fichero existe
// Introduccin a C#, por Nacho Cabanes

booleana de control.
Revisin 0.99zz Pgina 249

(8.6.2) Mejora el ejemplo 08_06a para que no use "while (true)", sino una variable

muestre un mensaje de aviso en caso de que no sea as.

(8.6.1) Mejora el ejercicio 8.3.4 para que compruebe antes si el fichero existe, y

Ejercicios propuestos:

while (true) // Interrumpimos desde dentro con "break"


{
Console.Write( "Nombre del fichero (\"fin\" para terminar)? ");
nombre = Console.ReadLine();
if (nombre == "fin")
break;
if ( File.Exists(nombre) )
{
fichero = File.OpenText( nombre );
Console.WriteLine("Su primera linea es: {0}",
fichero.ReadLine() );
fichero.Close();
}
else
Console.WriteLine( "No existe!" );
}

public class Ejemplo_08_06a


{
public static void Main()
{
StreamReader fichero;
string nombre;

using System;
using System.IO;

por ejemplo).

de intentar abrirlo:

try
{

fichero = File.OpenText(nombre);
do
{
linea = fichero.ReadLine();
if (linea != null)
Console.WriteLine( linea );
Revisin 0.99zz Pgina 250

Console.WriteLine("Introduzca el nombre del fichero");


nombre = Console.ReadLine();

public class Ejemplo_08_07a


{
public static void Main()
{
StreamReader fichero;
string nombre;
string linea;

using System;
using System.IO;

// Ejemplo_08_07a.cs
// Excepciones y ficheros (1)
// Introduccin a C#, por Nacho Cabanes

programa, podra ser:

en caso de error se limitara a mostrar un mensaje de error y a abandonar el

un primer ejemplo, que mostrara todo el contenido de un fichero de texto y que

y los mensajes de error y/o acciones correctoras estarn en el bloque "catch". As,

Tpicamente, los pasos que puedan ser problemticos irn dentro del bloque "try"

del tema 2.

comprobar las posibles "excepciones", con las que ya tuvimos un contacto al final

intentemos escribir en un dispositivo que sea slo de lectura (como un CD-ROM,

Una primera solucin es usar "File.Exists(nombre)", para comprobar si est, antes

tengamos permiso para acceder al fichero, a pesar de que exista, o que

El uso de "File.Exists" nos permite saber si el fichero existe, pero ese no es el nico

que introduzcamos un nombre incorrecto.

8.7. Ms comprobaciones de errores: excepciones

el prximo apartado.

que ya nos habamos encontrado en el tema 3 y que veremos con ms detalle en

Otra forma de comprobar si un fichero existe o no es usar "excepciones", con las

Introduccin a la programacin con C#, por Nacho Cabanes

falle en caso de que el fichero no se encuentre donde nosotros esperamos o de

realmente si el fichero existe o no, lo que puede suponer que nuestro programa

Hasta ahora, estamos intentando abrir ficheros para lectura, pero sin comprobar

8.6. Saber si un fichero existe

de los resultados de las ejecuciones anteriores.

que se ejecute el programa, deber aadir los nuevos resultados a continuacin

Introduccin a la programacin con C#, por Nacho Cabanes

se

pudo

encontrar

el

archivo

ruta

del

fichero

es

demasiado

El disco puede estar lleno (IOException).

"PathTooLongException").

La

"IOException").
larga

(excepcin

de

tipo

El fichero existe y es de slo lectura (se lanzar una excepcin del tipo

public class Ejemplo_08_07b


{
public static void Main()
{
StreamWriter fichero;
string nombre;

using System;
using System.IO;

// Ejemplo_08_07b.cs
// Excepciones y ficheros (2)
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 251

que podamos dar pasos ms adecuados para solucionar el problema:

que una simple "Exception", de forma que el mensaje de aviso sea ms concreto, o

As, dentro de cada bloque "catch" podramos indicar una excepcin ms concreta

excepciones como stas:

"catch". Por ejemplo, en el caso de que queramos crear un fichero, podemos tener

recuperarse del error y seguir adelante, para lo que se suelen crear varios bloques

excepciones a la vez", sino crear un anlisis para cada caso, que permita

Pero, como ya vimos, generalmente lo razonable no es interceptar "todas las

Introduzca el nombre del fichero


prueba
Ha
habido
un
error:
No
'C:\Fuentes\nacho\prueba'.

El resultado, si ese fichero no existe, sera algo como

}
catch (Exception exp)
{
Console.WriteLine("Ha habido un error: {0}", exp.Message);
return;
}

fichero.Close();

}
while (linea != null);

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 252

resultado de dichos clculos (con la forma "15 * 6 = 90"). Debe controlar los

operacin a realizar con ellos (+, -, *, /) y guarde en un fichero "calculadora.txt" el

(8.7.3) Un programa que pida al usuario repetidamente pares de nmeros y la

pedirlo, en vez de interrumpir la ejecucin.

teclea un dato no numrico, el programa deber mostrar un aviso y volver a

segundo nmero, y muestre el resultado de la correspondiente operacin. Si se

(8.7.2) Un programa que pida al usuario un nmero, una operacin (+, -, *, /) y un

fichero de origen no exista, o que el fichero de destino no se pueda crear.

convertido a maysculas. Se debe controlar los posibles errores, como que el

un fichero de destino, y que vuelque al segundo fichero el contenido del primero,

(8.7.1) Un programa que pida al usuario el nombre de un fichero de origen y el de

Ejercicios propuestos:

un texto).

queremos esperamos que introduzca un nmero, pero, en lugar de ello, tecleado

como cuando no se puede convertir un dato a un cierto tipo (por ejemplo, si

"trycatch" para comprobar ciertos errores relacionados con la entrada de datos,

(realmente, como un fichero de entrada y otro de salida), se puede usar

Hay que recordar que, como la consola se comporta como un fichero de texto

las ltimas que analicemos, y las ms especficas debern ser las primeras.

Las excepciones ms generales (IOException y, sobre todo, Exception) debern ser

fichero = File.CreateText(nombre);
fichero.WriteLine( linea );
fichero.Close();

}
catch (PathTooLongException e)
{
Console.WriteLine("Nombre demasiado largo!");
}
catch (IOException e)
{
Console.WriteLine("No se ha podido escribir!");
Console.WriteLine("El error exacto es: {0}", e.Message);
}

try
{

Console.Write("Introduzca el nombre del fichero: ");


nombre = Console.ReadLine();
Console.Write("Introduzca la frase a guardar: ");
linea = Console.ReadLine();

string linea;
;

Introduccin a la programacin con C#, por Nacho Cabanes

vamos

ver

cmo

abrir

un

fichero

(no

de error, o un dato que podramos convertir a byte si la lectura ha sido correcta,


as:

Fichero lgico. Es un identificador que aparece dentro de nuestro

programa, y que permite acceder a un fichero fsico. Por ejemplo, si

fichero lgico.

Revisin 0.99zz Pgina 253

Revisin 0.99zz Pgina 254

datos desde un fichero que ya existe:

ms o menos ordenada. Esto ocurre en las imgenes, los ficheros de sonido, de

video, etc.

nos interesar un nico modo, que ser "FileMode.Open", que nos permite leer

ficheros en los que la informacin est estructurada como una secuencia de bytes,

recibir dos parmetros: el nombre del fichero y el modo de apertura. Por ahora,

Podemos usar tambin un constructor para acceder al fichero. Este constructor

}
catch (Exception e)
{
Console.WriteLine("Error: "+e.Message);
return;
}

Los ficheros de texto son habituales, pero es an ms frecuente encontrarnos con

de cada lnea de texto, as que no podremos saltar hasta una cierta lnea).

de texto en general no podremos hacerlo, porque no sabremos el tamao

que comenzaremos a hacer pronto, en los ficheros binarios (en un fichero

fichero directamente, sin necesidad de recorrer todo lo anterior. Es algo

Acceso aleatorio: Cuando podemos saltar hasta cualquier posicin del

ficheros de texto.

video o de cassette). Es lo que estamos haciendo hasta ahora en los

fichero si queremos llegar hasta cierto punto (como ocurre con las cintas de

fichero = File.OpenRead(nombre);
unDato = (byte) fichero.ReadByte();
Console.WriteLine("El byte leido es un {0}",
unDato);
fichero.Close();

try
{

Acceso secuencial: Cuando debemos "recorrer" todo el contenido de un

de esos "apartados" de un registro se conoce como "campo".

Console.WriteLine("Introduzca el nombre del fichero");


nombre = Console.ReadLine();

public class Ejemplo_08_09a


{
public static void Main()
{
FileStream fichero;
string nombre;
byte unDato;

using System;
using System.IO;

datos de una persona: nombre, direccin, e-mail, telfono, etc. Cada uno

Registro: Un bloque de datos que forma un "todo", como el conjunto de los

utilizando siempre una misma variable).

estn guardados en distintos ficheros fsicos, pero los abramos y los leamos

ficheros fsicos (por ejemplo, los mapas de los niveles de un juego, que

tambin podemos usar un nico fichero lgico para acceder a distintos

StreamReader para leer de l y un StreamWriter para escribir en l), y

fichero fsico mediante dos o ms ficheros lgicos (por ejemplo, un

por qu existir una correspondencia "1 a 1": puede que accedamos a un

Equivalencia entre fichero lgico y fichero fsico. No necesariamente tiene

// Ejemplo_08_09a.cs
// Ficheros binarios: lectura de un byte con FileStream
// Introduccin a C#, por Nacho Cabanes

Esta clase tiene un mtodo ReadByte, que devuelve un entero con valor -1 en caso

"agenda.txt".

declaramos "StreamReader fichero1", esa variable "fichero1" representa un

utilizar la clase FileStream, diseada para acceder a un byte o a bloques de bytes.

Fichero fsico. Es un fichero que existe realmente en el disco, como

8.9. Leer un byte de un fichero binario

acercamiento,

necesariamente de texto) y leer el primer byte que contiene. Comenzaremos por

primer

Como

y que es necesario conocer:

un fichero de sonido MP3.

informacin almacenada en ciertos formatos habituales, como una imagen BMP o

Vamos a ver cmo leer de un fichero "general", y lo aplicaremos a descifrar la

Introduccin a la programacin con C#, por Nacho Cabanes

Llega el momento de concretar algunos conceptos que hemos pasado por encima,

8.8. Conceptos bsicos sobre ficheros

que el fichero no se haya podido crear.

posibles errores, como que los datos no sean numricos, la divisin entre cero, o

Introduccin a la programacin con C#, por Nacho Cabanes

using (FileStream fichero = new FileStream(


nombre, FileMode.Open))
{
byte unDato = (byte) fichero.ReadByte();
Console.WriteLine("El byte leido es un {0}",
unDato);
}

}
catch (Exception e)

try
{

Revisin 0.99zz Pgina 255

public class Ejemplo_08_09c


{
public static void Main()
{
Console.WriteLine("Introduzca el nombre del fichero");
string nombre = Console.ReadLine();

using System;
using System.IO;

// Ejemplo_08_09c.cs
// Ficheros binarios: lectura de un byte con FileStream, using
// Introduccin a C#, por Nacho Cabanes

sea necesario cerrar el fichero de forma explcita:

Y tambin podemos emplear la sintaxis alternativa, con "using", de modo que no

FileStream fichero = new FileStream(nombre, FileMode.Open);


byte unDato = (byte) fichero.ReadByte();
Console.WriteLine("El byte leido es un {0}",
unDato);
fichero.Close();

}
catch (Exception e)
{
Console.WriteLine("Error: "+e.Message);
return;
}

try
{

public class Ejemplo_08_09b


{
public static void Main()
{
Console.WriteLine("Introduzca el nombre del fichero");
string nombre = Console.ReadLine();

using System;
using System.IO;

// Ejemplo_08_09b.cs
// Ficheros binarios: lectura de un byte con FileStream, constructor
// Introduccin a C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

Console.WriteLine("Error: "+e.Message);
return;

Revisin 0.99zz Pgina 256

public class Ejemplo_08_10a


{
public static void Main()
{
Console.WriteLine("Introduzca el nombre del fichero");

using System;
using System.IO;

// Ejemplo_08_10a.cs
// Ficheros binarios: lectura completa de un FileStream
// Introduccin a C#, por Nacho Cabanes

A partir de entonces, podramos usar un "for" para recorrer todo el fichero, as:

primera es descubrir el tamao del fichero, que podemos obtener con ".Length".

Tenemos dos formas de leer byte a byte todos datos que forma un FileStream. La

8.10. Leer hasta el final de un fichero binario

G, I, F.

(8.9.3) Abre una imagen GIF y comprueba si sus tres primeros bytes son las letras

bytes del fichero corresponden a una letra "B" y una letra "M", respectivamente.

realmente se trata de un fichero en ese formato, mirando si los dos primeros

(8.9.2) Abre una imagen BMP (cuyo nombre introducir el usuario) y comprueba si

que marca el cdigo ASCII) y un 90 (una letra "Z"), respectivamente.

bytes del fichero son un 77 (que corresponde a una letra "M", segn el estndar

comprueba si realmente se trata de un ejecutable, mirando si los dos primeros

(8.9.1) Abre un fichero con extensin EXE (cuyo nombre introducir el usuario) y

Ejercicios propuestos:

tras cada lectura, avanza la posicin actual dentro del fichero.

Si quisiramos leer un segundo dato, volveramos a llamar a ReadByte, porque

crea si no existe), Truncate (abre un fichero que debe existir y lo vaca).

existe), Open (abre si existe o falla si no existe), OpenOrCreate (abre si existe o lo

fichero o lo sobreescribe si ya exista), CreateNew (crea si no exista, o falla si

autoexplicativos) son: Append (aade al final o crea si no existe), Create (crea el

Los otros modos de apertura posibles (cuyos nombre en ingls son casi

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 257

public class Ejemplo_08_10b


{
public static void Main()
{
Console.WriteLine("Introduzca el nombre del fichero");
string nombre = Console.ReadLine();
FileStream fichero = File.OpenRead(nombre);
int count = 0;
int dato;
do
{
dato = fichero.ReadByte();
if (dato != -1)
{
char letra = Convert.ToChar( (byte) dato );
if (letra == 'A')
count++;
}
}
while (dato != -1);
Console.WriteLine("Tiene {0} letras A", count);
fichero.Close();
}
}

using System;
using System.IO;

// Ejemplo_08_10b.cs
// Ficheros binarios: lectura completa de un FileStream
// Introduccin a C#, por Nacho Cabanes

El fuente correspondiente podra ser:

un -1. Cuando esto ocurra, ser que seal de que se ha llegado al final del fichero.

La segunda forma de leer hasta el final del fichero es comprobar si el dato ledo es

error durante la lectura).

programa real s debera comprobar si el fichero existe y si se ha producido algn

Lo mismo ocurrir en la mayora de fuentes de ejemplo de este tema, pero un

(Por simplicidad, este fuente no realiza ningn tipo de comprobacin de errores.

string nombre = Console.ReadLine();


FileStream fichero = File.OpenRead(nombre);
int count = 0;
for ( int pos = 0; pos < fichero.Length; pos++)
{
byte unDato = (byte) fichero.ReadByte();
char letra = Convert.ToChar( unDato );
if (letra == 'A')
count++;
}
Console.WriteLine("Tiene {0} letras A", count);
fichero.Close();

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 258

FileStream fichero = File.OpenRead(nombre);


byte[] datos = new byte[10];
int posicion = 0;
int cantidadALeer = 10;
int cantidadLeida = fichero.Read(datos, posicion, cantidadALeer);

public class Ejemplo_08_11a


{
public static void Main()
{
Console.WriteLine("Introduzca el nombre del fichero");
string nombre = Console.ReadLine();

using System;
using System.IO;

// Ejemplo_08_11a.cs
// Ficheros binarios: lectura por bloques de un FileStream
// Introduccin a C#, por Nacho Cabanes

si hemos llegado al final del fichero).

(porque puede ser menos de lo que le hemos pedido, si hay un error de lectura o

devuelve un valor, que es la cantidad de datos que se han podido leer realmente

0, es decir, al principio del array), y qu cantidad de datos se deben leer. Nos

datos (no la posicin en el fichero, sino en el array, de modo que casi siempre ser

array guardar esos datos, a partir de qu posicin del array debe introducir los

permite leer una cierta cantidad de datos desde el fichero. Le indicaremos en qu

Para eso, dentro de la clase "FileStream" tenemos mtodo "Read", que nos

guardarn como un array de bytes.

es ms habitual leer grandes bloques de datos. Tpicamente, esos datos se

Leer byte a byte puede ser cmodo, pero tambin es lento. Por eso, en la prctica

8.11. Leer bloques de datos de un fichero binario

binario.

alfabticos (cdigos 32 a 127, adems del 10 y el 13) que contenga un fichero

(8.10.4) Crea un programa que extraiga a un fichero de texto todos los caracteres

palabra que introduzca el usuario.

(8.10.3) Crea un programa que diga si un fichero (binario) contiene una cierta

fichero binario.

(8.10.2) Crea un programa que cuente la cantidad de vocales que contiene un

el usuario) contiene una cierta letra (tambin escogida por el usuario).

(8.10.1) Crea un programa que compruebe si un fichero (cuyo nombre introducir

Ejercicios propuestos:

Introduccin a la programacin con C#, por Nacho Cabanes

retroceder).

Revisin 0.99zz Pgina 259

nmero negativo (si miramos desde el final del fichero, porque desde l habr que

La posicin es un Int64, porque puede ser un nmero muy grande e incluso un

posicin actual SeekOrigin.Current- o desde el final del fichero SeekOrigin.End-).

cuente esa posicin (desde el comienzo del fichero SeekOrigin.Begin-, desde la

la posicin a la que queremos saltar, y el punto desde el que queremos que se

Para ello, tenemos el mtodo "Seek". A este mtodo se le indican dos parmetros:

directamente a la posicin que buscamos (acceso aleatorio).

conseguirlo sin necesidad de leer todos los bytes anteriores, accediendo

encuentra el dato que nos interesa leer. En un fichero binario, esto podemos

habitualmente nos interesar situarnos antes en la posicin exacta en la que se

Cuando leemos byte a byte (y tambin a veces en el caso de leer todo un bloque),

8.12. La posicin en el fichero

Debers leer toda la cabecera (los primeros 54 bytes) con una sola orden.

valor es un 0 (que es lo habitual), indicar que el fichero no est comprimido.

mirando el valor del byte en la posicin 30 (empezando a contar desde 0). Si ese

(8.11.4) Abre una imagen en formato BMP y comprueba si est comprimida,

G, I, F. Guarda los 3 datos en un array.

(8.11.3) Abre una imagen GIF y comprueba si sus tres primeros bytes son las letras

Usa "Read" y un array.

bytes del fichero corresponden a una letra "B" y una letra "M", respectivamente.

si realmente se trata de un fichero en ese formato, mirando si los dos primeros

(8.11.2) Abre una imagen BMP (cuyo nombre introducir el usuario) y comprueba

un array.

letra "M" y una letra "Z", respectivamente. Debes leer ambos bytes a la vez, usando

un ejecutable, mirando si los dos primeros bytes del fichero corresponden a una

(8.11.1) Abre un fichero con extensin EXE y comprobar si realmente se trata de

Ejercicios propuestos:

if (cantidadLeida < 10)


Console.WriteLine("No se han podido leer todos los datos!");
else
{
Console.WriteLine("El primer byte leido es {0}", datos[0]);
Console.WriteLine("El tercero es {0}", datos[2]);
}
fichero.Close();

Introduccin a la programacin con C#, por Nacho Cabanes

fichero.Close();

Revisin 0.99zz Pgina 260

mirando el valor del byte en la posicin 30 (empezando a contar desde 0). Si ese

(8.12.2) Abre una imagen en formato BMP y comprueba si est comprimida,

corresponde a una letra "Z", sin leer su primer byte.

(8.12.1) Abre un fichero con extensin EXE y comprueba si su segundo byte

Ejercicios propuestos:

hemos abierto permite realmente que nos movamos a unas posiciones u otras).

(Nota: existe una propiedad "CanSeek" que nos permite saber si el fichero que

Console.WriteLine("La posicin actual es {0}",


fichero.Position);
Console.WriteLine("Y el tamao del fichero es {0}",
fichero.Length);

if (fichero.Length > 30)


{
fichero.Seek(19, SeekOrigin.Begin);
int nuevoDato = fichero.ReadByte();
Console.WriteLine("El byte 20 es un {0}", nuevoDato);

if (cantidadLeida < 10)


Console.WriteLine("No se han podido leer todos los datos!");
else
{
Console.WriteLine("El primer byte leido es {0}", datos[0]);
Console.WriteLine("El tercero es {0}", datos[2]);
}

public class Ejemplo_08_12a


{
public static void Main()
{
Console.WriteLine("Introduzca el nombre del fichero");
string nombre = Console.ReadLine();
FileStream fichero = File.OpenRead(nombre);
byte[] datos = new byte[10];
int posicion = 0;
int cantidadALeer = 10;
int cantidadLeida = fichero.Read(datos, posicion, cantidadALeer);

using System;
using System.IO;

// Ejemplo_08_12a.cs
// Ficheros binarios: posicin
// Introduccin a C#, por Nacho Cabanes

longitud del fichero, mirando su propiedad "Length").

consultando la propiedad "Position" (y tambin sabemos que podemos obtener la

De igual modo, podemos saber en qu posicin del fichero nos encontramos,

Introduccin a la programacin con C#, por Nacho Cabanes

(8.13.2) Abre una imagen en formato BMP y comprueba si comienza con el entero

byte1 + byte2*256, as:

Revisin 0.99zz Pgina 261

public class Ejemplo_08_13b


{
public static void Main()
{
Console.WriteLine("Introduzca el nombre del fichero");
string nombre = Console.ReadLine();

using System;
using System.IO;

debajo, a su "BaseStream",
SeekOrigin.Begin);

as:

1,

Revisin 0.99zz Pgina 262

ficheroEntrada.BaseStream.Seek(

directamente a nuestro fichero, sino al "Stream" (flujo de datos) que hay por

usamos un "BinaryReader", pero est un poco ms escondido: no se lo pedimos

Tambin podemos usar "Seek" para movernos a un punto u otro de un fichero si

corto 19778.

corto 23117.

menos significativo y luego el byte ms significativo, de modo que el dato sera

// Ejemplo_08_13b.cs
// Ficheros binarios: lectura de un short, byte a byte
// Introduccin a C#, por Nacho Cabanes

(8.13.1) Abre un fichero con extensin EXE y comprueba si comienza con el entero

cuenta que, en la mayora de sistemas actuales, en primer lugar aparece el byte

Ejercicios propuestos:

using (BinaryReader fichero = new BinaryReader(


File.Open(nombre, FileMode.Open)))
{
short dato = fichero.ReadInt16();
Console.WriteLine("El dato leido es {0}", dato);
}

public class Ejemplo_08_13c


{
public static void Main()
{
Console.WriteLine("Introduzca el nombre del fichero");
string nombre = Console.ReadLine();

using System;
using System.IO;

// Ejemplo_08_13c.cs
// Ficheros binarios: lectura de un short, con BinaryReader, using
// Introduccin a C#, por Nacho Cabanes

automticamente, as:

Tambin podemos emplear la clusula "using", para que el fichero se cierre

BinaryReader fichero = new BinaryReader(


File.Open(nombre, FileMode.Open));
short dato1 = fichero.ReadByte();
short dato2 = fichero.ReadByte();
Console.WriteLine("El dato leido es {0}", dato1 + dato2*256);
fichero.Close();

Introduccin a la programacin con C#, por Nacho Cabanes

como un BinaryReader, pero deberemos recomponer ese "short", teniendo en

Si preferimos hacer esta lectura byte a byte, podremos usar tanto un FileStream

BinaryReader fichero = new BinaryReader(


File.Open(nombre, FileMode.Open));
short dato = fichero.ReadInt16();
Console.WriteLine("El dato leido es {0}", dato);
fichero.Close();

public class Ejemplo_08_13a


{
public static void Main()
{
Console.WriteLine("Introduzca el nombre del fichero");
string nombre = Console.ReadLine();

using System;
using System.IO;

// Ejemplo_08_13a.cs
// Ficheros binarios: lectura de un short, con BinaryReader
// Introduccin a C#, por Nacho Cabanes

forman los dos bytes iniciales de un fichero con:

usaremos la clase "BinaryReader". Por ejemplo, podramos leer el entero corto que

leer otros tipos de datos bsicos existentes en C# (short, int, float, etc.). Para eso

Un FileStream es cmodo para leer byte a byte, pero no tanto cuando queremos

8.13. Leer datos nativos

esa posicin directamente, sin leer toda la cabecera.

valor es 0 (que es lo habitual), indicar que el fichero no est comprimido. Salta a

Introduccin a la programacin con C#, por Nacho Cabanes

TIPO DE INFORMACIN
Tipo de fichero (letras BM)
Tamao del archivo

Revisin 0.99zz Pgina 263

POSICIN EN EL ARCHIVO
0-1
2-5

En concreto, los datos que forman la cabecera de fichero y la cabecera de


bitmap son los siguientes:

Un fichero BMP est compuesto por las siguientes partes: una cabecera de
fichero, una cabecera del bitmap, una tabla de colores y los bytes que
definirn la imagen.

cabecera. El formato de dicha cabecera es el siguiente:

un poco ms all y a tratar de obtener muchos de los detalles que hay en su

Hemos estado extrayendo algo de informacin de ficheros BMP. Ahora vamos a ir

8.14. Ejemplo completo: leer informacin de un fichero


BMP

fichero BMP.

posicin 22. Ampla el ejemplo 08_13d, para que muestre tambin el alto de ese

(8.13.3) El alto de un fichero BMP es un entero de 32 bits que se encuentra en la

Ejercicios propuestos:

BinaryReader fichero = new BinaryReader(


File.Open(nombre, FileMode.Open));
fichero.BaseStream.Seek(18, SeekOrigin.Begin);
int ancho = fichero.ReadInt32();
Console.WriteLine("El ancho es {0}", ancho);
fichero.Close();

public class Ejemplo_08_13d


{
public static void Main()
{
Console.WriteLine("Introduzca el nombre del fichero BMP");
string nombre = Console.ReadLine();

using System;
using System.IO;

// Ejemplo_08_13d.cs
// Ficheros binarios: Seek, con BinaryReader
// Introduccin a C#, por Nacho Cabanes

que se encuentra en la posicin 18, de modo que podramos hacer:

Por ejemplo, la anchura de una imagen en formato BMP es un entero de 32 bits

Introduccin a la programacin con C#, por Nacho Cabanes

6-7
8-9
10-13
14-17
18-21
22-25
26-27
28-29
30-33
34-37
38-41
42-45
46-49
50-53

Revisin 0.99zz Pgina 264

if ((marca1 !='B') || (marca2 !='M'))


Console.WriteLine("No parece un fichero BMP");
else
{
Console.WriteLine("Marca del fichero: {0}{1}",
marca1, marca2);

// Leo los dos primeros bytes


char marca1 = Convert.ToChar( fichero.ReadByte() );
char marca2 = Convert.ToChar( fichero.ReadByte() );

if (! File.Exists( nombre) )
{
Console.WriteLine("No encontrado!");
}
else
{
BinaryReader fichero = new BinaryReader(
File.Open(nombre, FileMode.Open));

public class Ejemplo_08_14a


{
public static void Main()
{
Console.WriteLine("Informacin de imgenes BMP");
Console.WriteLine("Dime el nombre del fichero: ");
string nombre = Console.ReadLine();

using System;
using System.IO;

// Ejemplo_08_14a.cs
// Informacin de un fichero BMP, con BinaryReader
// Introduccin a C#, por Nacho Cabanes

su alto, la resolucin y si la imagen est comprimida o no:

Por tanto, ser fcil hacer que se nos muestren algunos detales, como su ancho,

Reservado
Reservado
Inicio de los datos de la imagen
Tamao de la cabecera de bitmap
Anchura (pxeles)
Altura (pxeles)
Nmero de planos
Tamao de cada punto
Compresin (0=no comprimido)
Tamao de la imagen
Resolucin horizontal
Resolucin vertical
Tamao de la tabla de color
Contador de colores importantes

Introduccin a la programacin con C#, por Nacho Cabanes

public class Ejemplo_08_14b


{
public static void Main()
{
Console.WriteLine("Informacin de imgenes BMP");
Console.WriteLine("Dime el nombre del fichero: ");
string nombre = Console.ReadLine();

using System;
using System.IO;

// Ejemplo_08_14b.cs
// Informacin de un fichero BMP, con FileStream
// Introduccin a C#, por Nacho Cabanes

componer a partir de los 4 bytes que los forman:

Revisin 0.99zz Pgina 265

otras operaciones, como el clculo de los valores enteros, que habr que

como la lectura, que se puede hacer toda en un bloque, pero a cambio complicar

Podemos hacerlo tambin con un FileStream, que simplificar ciertas operaciones,

fichero.Close();

// A continuacin: resolucin vertical


int resolV = fichero.ReadInt32();
Console.WriteLine("Resolucin Vertical: {0}", resolV);

// 4 bytes despus: resolucin horizontal


fichero.BaseStream.Seek(4, SeekOrigin.Current);
int resolH = fichero.ReadInt32();
Console.WriteLine("Resolucin Horiz.: {0}", resolH);

// Posicin 30: compresin


fichero.BaseStream.Seek(30, SeekOrigin.Begin);
int compresion = fichero.ReadInt32();
switch (compresion)
{
case 0: Console.WriteLine("Sin compresin");
break;
case 1: Console.WriteLine("Compresin RLE 8 bits");
break;
case 2: Console.WriteLine("Compresin RLE 4 bits");
break;
}

// A continuacin: alto
int alto = fichero.ReadInt32();
Console.WriteLine("Alto: {0}", alto);

// Posicin 18: ancho


fichero.
.BaseStream.Seek(18, SeekOrigin.Begin);
int ancho = fichero.ReadInt32();
Console.WriteLine("Ancho: {0}", ancho);

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 266

int resolV = cabecera[42] +


cabecera[43] * 256 + cabecera[44] * 256 * 256 +
cabecera[45] * 256 * 256 * 256;

int resolH = cabecera[38] +


cabecera[39] * 256 + cabecera[40] * 256 * 256 +
cabecera[41] * 256 * 256 * 256;
Console.WriteLine("Resolucin Horiz.: {0}", resolH);

int compresion = cabecera[30];


switch (compresion)
{
case 0: Console.WriteLine("Sin compresin");
break;
case 1: Console.WriteLine("Compresin RLE 8 bits");
break;
case 2: Console.WriteLine("Compresin RLE 4 bits");
break;
}

int alto = cabecera[22] +


cabecera[23] * 256 + cabecera[24] * 256 * 256 +
cabecera[25] * 256 * 256 * 256;
Console.WriteLine("Alto: {0}", alto);

int ancho = cabecera[18] + // Convierto 4 bytes a Int32


cabecera[19] * 256 + cabecera[20] * 256 * 256 +
cabecera[21] * 256 * 256 * 256;
Console.WriteLine("Ancho: {0}", ancho);

if ((marca1 !='B') || (marca2 !='M'))


Console.WriteLine("No parece un fichero BMP");
else
{
Console.WriteLine("Marca del fichero: {0}{1}",
marca1, marca2);

if (cantidadLeida != tamanyoCabecera)
{
Console.WriteLine("No se ha podido leer la cabecera");
}
else
{
// Analizo los dos primeros bytes
char marca1 = Convert.ToChar( cabecera[0] );
char marca2 = Convert.ToChar( cabecera[1] );

int cantidadLeida = fichero.Read(cabecera, 0, tamanyoCabecera);


fichero.Close();

if (! File.Exists( nombre) )
{
Console.WriteLine("No encontrado!");
}
else
{
FileStream fichero = File.OpenRead(nombre);
int tamanyoCabecera = 54;
byte[] cabecera = new byte[tamanyoCabecera];

Introduccin a la programacin con C#, por Nacho Cabanes

Un mtodo Write, para escribir un bloque de informacin (desde cierta

Crear un nuevo fichero con "Create".

public static void Main()


{
FileStream fichero;
string nombre;

public class Ejemplo_08_15a


{
const int TAMANYO_BUFFER = 10;

using System;
using System.IO;

// Ejemplo_08_15a.cs
// Ficheros binarios: escritura en FileStream
// Introduccin a C#, por Nacho Cabanes

volveremos a leer:

Revisin 0.99zz Pgina 267

datos, lo leeremos para comprobar que todo es correcto, aadiremos al final, y

Vamos a ver un ejemplo que junte todo ello: crearemos un fichero, guardaremos

Abrir un fichero existente con "OpenWrite".

Adems, a la hora de abrir el fichero, tenemos dos alternativas:

posicin de un array -normalmente 0-, y con cierto tamao).

Un mtodo WriteByte, para escribir slo un byte, o bien...

emplebamos para leer de l:

Para escribir en un FileStream, usaremos rdenes similares a las que

8.15. Escribir en un fichero binario

imagen GIF.

un programa que diga el subformato, ancho, alto y nmero de colores de una

(8.14.2) Localiza en Internet informacin sobre el formato de imgenes GIF. Crea

un programa que diga el ancho, alto y nmero de colores de una imagen PCX.

(8.14.1) Localiza en Internet informacin sobre el formato de imgenes PCX. Crea

en el fichero).

Revisin 0.99zz Pgina 268

(Nota: existe una propiedad "CanWrite" que nos permite saber si se puede escribir

}
catch (Exception e)
{
Console.WriteLine("Problemas: "+e.Message);
return;
}

// Volvemos a leer algun dato


fichero = File.OpenRead(nombre);
Console.WriteLine("El tamao es {0}", fichero.Length);
fichero.Seek(2, SeekOrigin.Begin);
nuevoDato = fichero.ReadByte();
Console.WriteLine("El tercer byte es un {0}", nuevoDato);
fichero.Close();

// Ahora aadimos 10 datos ms, al final


fichero = File.OpenWrite(nombre);
fichero.Seek(0, SeekOrigin.End);
fichero.Write(datos, 0, TAMANYO_BUFFER);
// y modificamos el tercer byte
fichero.Seek(2, SeekOrigin.Begin);
fichero.WriteByte( 99 );
fichero.Close();

// Ahora leemos dos datos


fichero = File.OpenRead(nombre);
Console.WriteLine("El tamao es {0}", fichero.Length);
fichero.Seek(2, SeekOrigin.Begin);
int nuevoDato = fichero.ReadByte();
Console.WriteLine("El tercer byte es un {0}", nuevoDato);
fichero.Seek(-2, SeekOrigin.End);
nuevoDato = fichero.ReadByte();
Console.WriteLine("El penultimo byte es un {0}", nuevoDato);
fichero.Close();

// Primero creamos el fichero, con algun dato


fichero = File.Create( nombre );
fichero.Write(datos, 0, TAMANYO_BUFFER);
fichero.Close();

try
{

Ejercicios propuestos:

nombre = "datos.dat";
datos = new byte[TAMANYO_BUFFER];

byte[
[] datos;

// Damos valores iniciales al array


for (byte i=0; i<TAMANYO_BUFFER; i++)
datos[i] = (byte) (i + 10);

Console.
.WriteLine("Resolucin Vertical: {0}", resolV);

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

// Ahora vamos a leerlos


Console.WriteLine("Leyendo fichero...");
Revisin 0.99zz Pgina 269

Console.WriteLine("Creando fichero...");
// Primero vamos a grabar datos
try
{
ficheroSalida = new BinaryWriter(
File.Open(nombre, FileMode.Create));
unDatoByte = 1;
unDatoInt = 2;
unDatoFloat = 3.0f;
unDatoDouble = 4.0;
unDatoString = "Hola";
ficheroSalida.Write(unDatoByte);
ficheroSalida.Write(unDatoInt);
ficheroSalida.Write(unDatoFloat);
ficheroSalida.Write(unDatoDouble);
ficheroSalida.Write(unDatoString);
ficheroSalida.Close();
}
catch (Exception e)
{
Console.WriteLine("Problemas al crear: "+e.Message);
return;
}

Console.Write("Introduzca el nombre del fichero a crear: ");


nombre = Console.ReadLine();

// Los datos que vamos a guardar/leer


byte unDatoByte;
int unDatoInt;
float unDatoFloat;
double unDatoDouble;
string unDatoString;

public class Ejemplo_08_15b


{
public static void Main()
{
BinaryWriter ficheroSalida;
BinaryReader ficheroEntrada;
string nombre;

Revisin 0.99zz Pgina 270

podemos emplear en un BinaryReader o en un BinaryWriter son los siguientes:

fichero, en vez de abrir un fichero ya existente. Los modos de fichero que

En este caso hemos usado "FileMode.Create" para indicar que queremos crear el

Introduzca el nombre del fichero a crear: 1234


Creando fichero...
Leyendo fichero...
El byte leido es un 1
El int leido es un 2
El float leido es un 3
El double leido es un 4
El string leido es "Hola"
Volvamos a leer el int...
El int leido es un 2

El resultado de este programa es:

}
catch (Exception e)
{
Console.WriteLine("Problemas al leer: "+e.Message);
return;
}

ficheroEntrada.BaseStream.Seek(1, SeekOrigin.Begin);
unDatoInt = ficheroEntrada.ReadInt32();
Console.WriteLine("El int leido es un {0}",
unDatoInt);
ficheroEntrada.Close();

unDatoString = ficheroEntrada.ReadString();
Console.WriteLine("El string leido es \"{0}\"",
unDatoString);
Console.WriteLine("Volvamos a leer el int...");

unDatoDouble = ficheroEntrada.ReadDouble();
Console.WriteLine("El double leido es un {0}",
unDatoDouble);

unDatoFloat = ficheroEntrada.ReadSingle();
Console.WriteLine("El float leido es un {0}",
unDatoFloat);

using System;
using System.IO;

unDatoByte = ficheroEntrada.ReadByte();
Console.WriteLine("El byte leido es un {0}",
unDatoByte);

ficheroEntrada = new BinaryReader(


File.Open(nombre, FileMode.Open));

unDatoInt = ficheroEntrada.ReadInt32();
Console.WriteLine("El int leido es un {0}",
unDatoInt);

try
{

Introduccin a la programacin con C#, por Nacho Cabanes

// Ejemplo_08_15b.cs
// Ficheros binarios: escritura en BinaryWriter
// Introduccin a C#, por Nacho Cabanes

dato que le indiquemos, sea del tipo que sea:

WriteString y similares, sino un nico mtodo "Write", que se encarga de escribir el

"BinaryReader", con la diferencia de que no tenemos mtodos WriteByte,

bytes, podemos usar un "BinaryWriter", que se maneja de forma similar a un

Si queremos que escribir datos bsicos de C# (float, int, etc.) en vez de un array de

Introduccin a la programacin con C#, por Nacho Cabanes

debe crearse uno nuevo.

crea un archivo nuevo si no existe.

Append: Abre el archivo si existe y se desplaza hasta el final del mismo, o

cero bytes.

Truncate: Abrir un archivo existente y truncarlo para que su tamao sea de

// Ejemplo_08_16a.cs
// Lectura y escritura en fichero binario
// Introduccin a C#, por Nacho Cabanes

datos con "Write" o "WriteByte":

Revisin 0.99zz Pgina 271

movernos dentro de l con "Seek", leer datos con "Read" o "ReadByte", y grabar

Una vez que hayamos indicado que queremos leer y escribir del fichero, podremos

queremos escribir, o FileAccess.ReadWrite si queremos leer y escribir).

8.12) y el modo de acceso (FileAccess.Read si queremos leer, FileAccess.Write si

se le puede indicar el modo de apertura (FileMode, como se vio en el apartado

"FileStream", que tambin tiene un mtodo llamado simplemente "Open", al que

o cerrando el fichero cada vez, pero tambin tenemos la alternativa de usar un

hexadecimal). Podemos conseguirlo abriendo (en modo de lectura o de escritura)

necesidad de crear una copia, o para poder crear herramientas como un editor

ejemplo, para poder modificar algn dato errneo, o para encriptar un fichero sin

Tambin es posible que nos interese leer y escribir en un mismo fichero (por

8.16. Leer y escribir en un mismo fichero binario

bytes, volcando a un tercer fichero.

primeros bytes. Para desencriptar, bastar con volver a intercambiar esos dos

volcando su contenido a un nuevo fichero, en el que intercambiar los dos

(8.15.2) Crea un programa que "encripte" el contenido de un fichero BMP,

extensin BAK.

(8.15.1) Crea una copia de un fichero EXE. La copia debe tener el mismo nombre y

Ejercicios propuestos:

OpenOrCreate: Se debe abrir un archivo si ya existe; en caso contrario,

excepcin System.IO.FileNotFoundException.

Open: Abrir un archivo existente. Si el archivo no existe, se produce una

Create: Crear un archivo nuevo. Si ya existe, se sobrescribir.

IOException.

CreateNew: Crear un archivo nuevo. Si existe, se produce una excepcin

Introduccin a la programacin con C#, por Nacho Cabanes

desencriptar, bastar con volver a intercambiar esos dos bytes.


Revisin 0.99zz Pgina 272

intercambiando los dos primeros bytes (y modificando el mismo fichero). Para

(8.16.1) Crea un programa que "encripte" el contenido de un fichero BMP,

Ejercicios propuestos:

fichero.Close();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return;
}

fichero.Seek(2, SeekOrigin.Begin);
nuevoDato = fichero.ReadByte();
Console.WriteLine("Ahora el tercer byte es un {0}", nuevoDato);

fichero.Seek(2, SeekOrigin.Begin);
fichero.WriteByte( 4 );

fichero.Seek(2, SeekOrigin.Begin);
int nuevoDato = fichero.ReadByte();
Console.WriteLine("El tercer byte es un {0}", nuevoDato);

// Ahora leemos dos datos


fichero = File.Open(nombre, FileMode.Open, FileAccess.ReadWrite);

// Primero creamos el fichero, con algun dato


fichero = File.Create( nombre );
fichero.Write(datos, posicion, TAMANYO_BUFFER);
fichero.Close();

try
{
int posicion = 0;

// Damos valores iniciales al array


for (byte i=0; i<TAMANYO_BUFFER; i++)
datos[i] = (byte) (i + 10);

nombre = "datos.dat";
datos = new byte[TAMANYO_BUFFER];

public static void Main()


{
FileStream fichero;
string nombre;
byte[] datos;

public class Ejemplo_08_16a


{
const int TAMANYO_BUFFER = 10;

using System;
using System.IO;

Introduccin a la programacin con C#, por Nacho Cabanes

ltimos 128 bytes del fichero).

Revisin 0.99zz Pgina 273

formato y sobre la cabecera ID3 V1, que se encuentra -si est presente- en los

en formato MP3 (tendrs que localizar en Internet la informacin sobre dicho

(8.16.11) Un programa que muestre el nombre del autor de un fichero de msica

todo su contenido en sendos arrays, que comparars.

(8.16.10) Crea un programa que compare si dos ficheros son iguales, volcando

uno de ellos.

comprobando primero su tamao y leyendo despus cada vez un byte de cada

(8.16.9) Crea un programa que compare si dos ficheros son iguales byte a byte,

no existir parmetros.

ambos ficheros se debe leer de la lnea de comandos, o pedir al usuario en caso de

un nuevo fichero, volcando para ello todo el contenido en un array. El nombre de

(8.16.8) Crea un programa que duplique un fichero, copiando todo su contenido a

nombre del fichero de entrada, al que se aadir ".out".

un nuevo fichero, byte a byte. El nombre del fichero de salida se tomar del

public static void Main()

public void Cargar(string nombre)


{
BinaryReader ficheroEntrada = new BinaryReader(
File.Open(nombre, FileMode.Open));
numero = ficheroEntrada.ReadInt32();
ficheroEntrada.Close();
}

public void Guardar(string nombre)


{
BinaryWriter ficheroSalida = new BinaryWriter(
File.Open(nombre, FileMode.Create));
ficheroSalida.Write(numero);
ficheroSalida.Close();
}

public int GetNumero()


{
return numero;
}

public void SetNumero(int n)


{
numero = n;
}

int numero;

public class Persist01


{

(8.16.7) Haz un programa que duplique un fichero, copiando todo su contenido a

secuencia de 4 bytes, y diga si el fichero contiene esa secuencia de bytes.

using System;
using System.IO;

// Ejemplo_09_01a.cs
// Primer acercamiento a la persistencia
// Introduccin a C#, por Nacho Cabanes

esos atributos desde el mismo fichero:

(8.16.6) Prepara un programa que pida al usuario el nombre de un fichero y una

eliminando "static" y "public" y las lneas que comiencen con "Using".

"Main" con "main", "string" con "char[80]", "Console.ReadLine" con "scanf", y

fichero de texto a otro, pero reemplazando "Console.WriteLine" con "printf",

(8.16.5) Crea un "traductor bsico de C# a C", que volcar todo el contenido de un

se vuelvan a cargar al principio de la siguiente.

almacenados se guarden automticamente en fichero al terminar una ejecucin, y

Revisin 0.99zz Pgina 274

cada uno de los atributos en un fichero y otro mtodo que recupere cada uno de

Podramos conseguirlo "de forma artesanal" si creamos un mtodo que guarde

(8.16.4) Mejora la base de datos de ficheros (ejemplo 04_06a) para que los datos

parmetros, se le preguntarn al usuario.

forman el programa.

convencional", sino pedir al sistema que se conserve el estado de los objetos que

est disponible para una ejecucin posterior es no guardarla en un "fichero

Una forma alternativa de conseguir que la informacin que manipula un programa

9.1. Por qu la persistencia?

9. Persistencia de objetos

Introduccin a la programacin con C#, por Nacho Cabanes

ficheros se deben indican como parmetros en la lnea de comandos. Si no hay

convirtiendo cada letra entre la A y la Z a maysculas. Los nombres de ambos

(8.16.3) Un programa que vuelque todo el contenido de un fichero binario a otro,

deben indican como parmetros en la lnea de comandos.

otro, convirtiendo cada frase a maysculas. Los nombres de ambos ficheros se

(8.16.2) Crea un programa que vuelque todo el contenido de un fichero de texto a

Ejercicios de repaso sobre ficheros:

Introduccin a la programacin con C#, por Nacho Cabanes

ejemplo2.Cargar( "ejemplo.dat" );
Console.WriteLine("Y ahora: {0}", ejemplo2.GetNumero());

Persist01 ejemplo2 = new Persist01();


Console.WriteLine("Valor 2: {0}", ejemplo2.GetNumero());

Persist01 ejemplo = new Persist01();


ejemplo.SetNumero(5);
Console.WriteLine("Valor: {0}", ejemplo.GetNumero());
ejemplo.Guardar( "ejemplo.dat" );

El programa completo podra ser algo como

public static void Guardar(string nombre, Persist02 objeto)

"static" para que sea Main el que se encargue de esas tareas:

Revisin 0.99zz Pgina 275

datos y recuperarlos. En este primer ejemplo, nos limitaremos a declararlos

misma clase: debern estar en una clase auxiliar, que se encargue de salvar los

atributos, ahora los mtodos "Cargar" y "Guardar" ya no pueden pertenecer a esa

En segundo lugar, como vamos a sobrescribir todo el objeto, en vez de slo los

[Serializable]
public class Persist02

fichero. En primer lugar, tendremos que indicar "[Serializable]" antes de la clase:

Vamos a guardar todo un objeto (incluyendo los valores de sus atributos) en un

9.2. Creando un objeto "serializable"

estado y recuperarlo posteriormente.

(9.1.1) Ampla la clase Persona (ejercicio 6.2.1), para que permita guardar su

Ejercicios propuestos:

automatizadas y que permiten escribir menos cdigo.

"array") que a su vez contienen otros objetos. Por eso, existen maneras ms

muchos atributos, y ms an si se trata de bloques de objetos (por ejemplo, un

Pero esta forma de trabajar se complica mucho cuando nuestro objeto tiene

Valor: 5
Valor 2: 0
Y ahora: 5

Que dara como resultado:

Introduccin a la programacin con C#, por Nacho Cabanes

System;
System.IO;
System.Runtime.Serialization;
System.Runtime.Serialization.Formatters.Binary;

Revisin 0.99zz Pgina 276

Persist02 ejemplo2 = new Persist02();


Console.WriteLine("Valor 2: {0}", ejemplo2.GetNumero());
ejemplo2 = Cargar("ejemplo.dat");
Console.WriteLine("Y ahora: {0}", ejemplo2.GetNumero());

public static void Main()


{
Persist02 ejemplo = new Persist02();
ejemplo.SetNumero(5);
Console.WriteLine("Valor: {0}", ejemplo.GetNumero());
Guardar("ejemplo.dat", ejemplo);

public static Persist02 Cargar(string nombre)


{
Persist02 objeto;
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream(nombre,
FileMode.Open, FileAccess.Read, FileShare.Read);
objeto = (Persist02)formatter.Deserialize(stream);
stream.Close();
return objeto;
}

public static void Guardar(string nombre, Persist02 objeto)


{
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream(nombre,
FileMode.Create, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, objeto);
stream.Close();
}

// Mtodos para guardar en fichero y leer desde l

public int GetNumero()


{
return numero;
}

public void SetNumero(int n)


{
numero = n;
}

int numero;

[Serializable]
public class Persist02
{

using
using
using
using

// Ejemplo_09_02a.cs
// Ejemplo bsico de persistencia
// Introduccin a C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 277

public void Guardar(ClaseAGuardar objeto)


{
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream(nombre,
FileMode.Create, FileAccess.Write, FileShare.None);

public Serializador(string nombreFich)


{
nombre = nombreFich;
}

public class Serializador


{
string nombre;

Y crear una segunda clase, que sea la encargada de guardar y recuperar los datos:

public Ejemplo GetDatos()


{
return e;
}

public void SetDatos(Ejemplo e1)


{
e = e1;
}

[Serializable]
public class ClaseAGuardar
{
Ejemplo e;

podamos reutilizar esa estructura:

vamos a guardar, incluyndola(s) dentro de otra clase auxiliar, de modo que

Una solucin un poco ms elegante podra ser encapsular la clase (o clases) que

9.3. Empleando clases auxiliares

recuperar los datos.

(9.2.1) Crea una variante del ejercicio 9.1.1, que use serializacin para guardar y

Ejercicios propuestos:

Valor: 5
Valor 2: 0
Y ahora: 5

Y su resultado sera el mismo que antes:

Introduccin a la programacin con C#, por Nacho Cabanes

System;
System.IO;
System.Runtime.Serialization;
System.Runtime.Serialization.Formatters.Binary;

public void SetDatos(Ejemplo e1)


{
e = e1;

// --------------------------------------------// La clase "que realmente se va a guardar"


[Serializable]
public class ClaseAGuardar
{
Ejemplo e;

public int GetNumero()


{
return numero;
}

public void SetNumero(int n)


{
numero = n;
}

int numero;

[Serializable]
public class Ejemplo
{

// --------------------------------------------// La clase "de prueba"

using
using
using
using

// Ejemplo_09_03a.cs
// Ejemplo de persistencia
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 278

De modo que un nico fuente que contuviera estas tres clases podra ser:

public ClaseAGuardar Cargar()


{
ClaseAGuardar objeto;
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream(nombre,
FileMode.Open, FileAccess.Read, FileShare.Read);
objeto = (ClaseAGuardar)formatter.Deserialize(stream);
stream.Close();
return objeto;
}

formatter..Serialize(stream, objeto);
stream.Close();

Introduccin a la programacin con C#, por Nacho Cabanes

Serializador s = new Serializador("ejemplo.dat");

ClaseAGuardar guardador = new ClaseAGuardar();


guardador.SetDatos(ejemplo);

Revisin 0.99zz Pgina 279

public static void Main()


{
Ejemplo ejemplo = new Ejemplo();
ejemplo.SetNumero(5);
Console.WriteLine("Valor: {0}", ejemplo.GetNumero());

public class Prueba


{

// --------------------------------------------// Y el programa de prueba

public ClaseAGuardar Cargar()


{
ClaseAGuardar objeto;
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream(nombre,
FileMode.Open, FileAccess.Read, FileShare.Read);
objeto = (ClaseAGuardar)formatter.Deserialize(stream);
stream.Close();
return objeto;
}

public void Guardar(ClaseAGuardar objeto)


{
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream(nombre,
FileMode.Create, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, objeto);
stream.Close();
}

public Serializador(string nombreFich)


{
nombre = nombreFich;
}

public class Serializador


{
string nombre;

System;
System.IO;
System.Runtime.Serialization;
System.Runtime.Serialization.Formatters.Binary;

public Ejemplo()
{
mini = new MiniEjemplo[100];
for (int i=0; i<100; i++)
{

int numero;
float numero2;
MiniEjemplo[] mini;

// ----[Serializable]
public class Ejemplo
{

public int GetDato()


{
return dato;
}

public void SetDato(int n)


{
dato = n;
}

[Serializable]
public class MiniEjemplo
{
int dato;

// --------------------------------------------// Las dos clases "de prueba": una contiene a otra

using
using
using
using

// Ejemplo_09_03b.cs
// Ejemplo de persistencia
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 280

cambiara la clase "ClaseAGuardar" (que aqu tampoco va a modificarse):

objetos de otra clase. La clase "Serializador" no cambiar, y en un caso real apenas

haciendo que nuestra clase contenga varios atributos, entre ellos un array de

Vamos a comprobar que se comporta correctamente en un caso ms complicado,

Ejemplo ejemplo2 = new Ejemplo();


Console.WriteLine("Valor 2: {0}", ejemplo2.GetNumero());
ejemplo2 = s.Cargar().GetDatos();
Console.WriteLine("Y ahora: {0}", ejemplo2.GetNumero());

public Ejemplo GetDatos()


{
return e;
}

// --------------------------------------------// La clase "encargada de guardar"

s.
.Guardar(guardador);

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

public void Guardar(ClaseAGuardar objeto)

Valor: 5
Valor 2: 0
Y ahora: 5
dato 50: 500

Esto dara como resultado:

public Serializador(string nombreFich)


{
nombre = nombreFich;
}

public class Serializador


{
string nombre;

}
}

Revisin 0.99zz Pgina 282

Ejemplo ejemplo2 = new Ejemplo();


Console.WriteLine("Valor 2: {0}", ejemplo2.GetNumero());
ejemplo2 = s.Cargar().GetDatos();
Console.WriteLine("Y ahora: {0}", ejemplo2.GetNumero());
Console.WriteLine("dato 50: {0}", ejemplo2.GetMini(50));

Serializador s = new Serializador("ejemplo.dat");


s.Guardar(guardador);

ClaseAGuardar guardador = new ClaseAGuardar();


guardador.SetDatos(ejemplo);

public static void Main()


{
Ejemplo ejemplo = new Ejemplo();
ejemplo.SetNumero(5);
ejemplo.SetMini(50, 500);
Console.WriteLine("Valor: {0}", ejemplo.GetNumero());

// --------------------------------------------// La clase "encargada de guardar"

public Ejemplo GetDatos()


{
return e;
}

public void SetDatos(Ejemplo e1)


{
e = e1;
}

[Serializable]
public class ClaseAGuardar
{
Ejemplo e;

Revisin 0.99zz Pgina 281

// --------------------------------------------// Y el programa de prueba

public int GetMini(int n)


{
return mini[n].GetDato();
}
public class Prueba
{

// --------------------------------------------// La clase "que realmente se va a guardar"

IFormatter formatter = new BinaryFormatter();


Stream stream = new FileStream(nombre,
FileMode.Create, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, objeto);
stream.Close();

public ClaseAGuardar Cargar()


{
ClaseAGuardar objeto;
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream(nombre,
FileMode.Open, FileAccess.Read, FileShare.Read);
objeto = (ClaseAGuardar)formatter.Deserialize(stream);
stream.Close();
return objeto;
}

Introduccin a la programacin con C#, por Nacho Cabanes

public void SetMini(int n, int valor)


{
mini[n].SetDato(valor);
}

public int GetNumero()


{
return numero;
}

public void SetNumero(int n)


{
numero = n;
}

mini[
[i] = new MiniEjemplo();
mini[i].SetDato( i*2 );

Introduccin a la programacin con C#, por Nacho Cabanes

public Ejemplo()

int numero;
float numero2;
MiniEjemplo[] mini;

[Serializable]
public class Ejemplo
{

public int GetDato()


{
return dato;
}

public void SetDato(int n)


{
dato = n;
}

[Serializable]
public class MiniEjemplo
{
int dato;

// --------------------------------------------// Las clases "de prueba"

Revisin 0.99zz Pgina 283

using System;
using System.IO;
using System.Runtime.Serialization;
// Para la siguiente lnea, puede ser necesario aadir a las referencias
// del proyecto "System.Runtime.Serialization.Formatters.Soap.dll"
using System.Runtime.Serialization.Formatters.Soap;

// Ejemplo_09_04a.cs
// Ejemplo de persistencia (XML)
// Introduccin a C#, por Nacho Cabanes

diente "using" y quiz aadir una DLL adicional al proyecto:

mnimos: cambiar "BinaryFormatter" por "SoapFormatter", as como el correspon-

sistema en el que quiz el orden de los bytes sea distinto), los cambios son

portabilidad, garantizando que se va a leer correctamente desde algn otro

binario. Si queremos guardarlos en un fichero XML (por ejemplo para maximizar la

La forma de trabajar que estamos empleando guarda los datos en un fichero

9.4. Volcando a un fichero de texto

serializacin.

(9.3.1) Crea una variante del ejercicio 9.2.1, que use una clase auxiliar para la

Ejercicios propuestos:

Introduccin a la programacin con C#, por Nacho Cabanes

public int GetMini(int n)


{
return mini[n].GetDato();
}

public void SetMini(int n, int valor)


{
mini[n].SetDato(valor);
}

public int GetNumero()


{
return numero;
}

public Serializador(string nombreFich)


{

public class Serializador


{
string nombre;

// --------------------------------------------// La clase "encargada de guardar"

public Ejemplo GetDatos()


{
return e;
}

public void SetDatos(Ejemplo e1)


{
e = e1;
}

[Serializable]
public class ClaseAGuardar
{
Ejemplo e;

// --------------------------------------------// La clase "que realmente se va a guardar"

mini = new MiniEjemplo[100];


for (int i=0; i<100; i++)
{
mini[i] = new MiniEjemplo();
mini[i].SetDato( i*2 );
}

public void SetNumero(int n)


{
numero = n;
}

Revisin 0.99zz Pgina 284

Introduccin a la programacin con C#, por Nacho Cabanes

public ClaseAGuardar Cargar()


{
ClaseAGuardar objeto;
IFormatter formatter = new SoapFormatter();
Stream stream = new FileStream(nombre,
FileMode.Open, FileAccess.Read, FileShare.Read);
objeto = (ClaseAGuardar)formatter.Deserialize(stream);
stream.Close();
return objeto;
}

Revisin 0.99zz Pgina 285

Revisin 0.99zz Pgina 286

anterior:

deberemos aadir una "referencia" adicional al proyecto.

Por ejemplo, este es un fragmento del fichero de datos generado por el programa

cambio se podr analizar con mayor cantidad de herramientas, al ser texto puro.

Si usamos XML, el fichero de datos resultante ser de mayor tamao, pero a

puede no compilar tal cual en versiones ms recientes, como la 4. Si es el caso,

"System.Runtime.Serialization.Formatters.Soap" y despus aceptar los cambios:

previstas para nuestra versin de .Net (por ejemplo, la 4.5) el nombre

Dentro de esta opcin, deberemos buscar dentro de las referencias que ya estn

referencia":

hacer clic con el botn derecho en "References" e indicar que deseamos "Agregar

Si usamos Visual Studio, deberemos ir al panel derecho (Explorador de soluciones),

Introduccin a la programacin con C#, por Nacho Cabanes

Este programa, que compilar correctamente en versiones de .Net como la 2.0,

Ejemplo ejemplo2 = new Ejemplo();


Console.WriteLine("Valor 2: {0}", ejemplo2.GetNumero());
ejemplo2 = s.Cargar().GetDatos();
Console.WriteLine("Y ahora: {0}", ejemplo2.GetNumero());
Console.WriteLine("dato 50: {0}", ejemplo2.GetMini(50));

Serializador s = new Serializador("ejemplo2.dat");


s.Guardar(guardador);

ClaseAGuardar guardador = new ClaseAGuardar();


guardador.SetDatos(ejemplo);

public static void Main()


{
Ejemplo ejemplo = new Ejemplo();
ejemplo.SetNumero(5);
ejemplo.SetMini(50, 500);
Console.WriteLine("Valor: {0}", ejemplo.GetNumero());

public class Prueba


{

// --------------------------------------------// Y el programa de prueba

nombre = nombreFich;

public void Guardar(ClaseAGuardar objeto)


{
IFormatter formatter = new SoapFormatter();
Stream stream = new FileStream(nombre,
FileMode.Create, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, objeto);
stream.Close();
}

Introduccin a la programacin con C#, por Nacho Cabanes

(Se ha omitido la mayor parte de los datos repetitivos)


Revisin 0.99zz Pgina 287

<a1:MiniEjemplo
id="ref-104"
xmlns:a1="http://schemas.microsoft.com/clr/assem/persist05%2C%20Version%3D0.0
.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<dato>198</dato>
</a1:MiniEjemplo>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

<item href="#ref-102"/>
<item href="#ref-103"/>
<item href="#ref-104"/>
</SOAP-ENC:Array>
<a1:MiniEjemplo
id="ref-5"
xmlns:a1="http://schemas.microsoft.com/clr/assem/persist05%2C%20Version%3D0.0
.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<dato>0</dato>
</a1:MiniEjemplo>
<a1:MiniEjemplo
id="ref-6"
xmlns:a1="http://schemas.microsoft.com/clr/assem/persist05%2C%20Version%3D0.0
.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<dato>2</dato>
</a1:MiniEjemplo>
...

<SOAP-ENV:Envelope
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:SOAPENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAPENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0"
SOAPENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<a1:ClaseAGuardar
id="ref-1"
xmlns:a1="http://schemas.microsoft.com/clr/assem/persist05%2C%20Version%3D0.0
.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<e href="#ref-3"/>
</a1:ClaseAGuardar>
<a1:Ejemplo
id="ref-3"
xmlns:a1="http://schemas.microsoft.com/clr/assem/persist05%2C%20Version%3D0.0
.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<numero>5</numero>
<numero2>0</numero2>
<mini href="#ref-4"/>
</a1:Ejemplo>
<SOAP-ENC:Array
id="ref-4"
SOAP-ENC:arrayType="a1:MiniEjemplo[100]"
xmlns:a1="http://schemas.microsoft.com/clr/assem/persist05%2C%20Version%3D0.0
.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<item href="#ref-5"/>
<item href="#ref-6"/>
<item href="#ref-7"/>
...

Introduccin a la programacin con C#, por Nacho Cabanes

datos en formato XML.

Revisin 0.99zz Pgina 288

(9.4.3) Aade al ejercicio de los trabajadores (6.8.1) la posibilidad de guardar sus

binario) usando persistencia.

04_06a) para que use objetos en vez de struct, y que guarde los datos (en formato

(9.4.2) Crea una versin ampliada de la "base de datos de ficheros" (ejemplo

(9.4.1) Crea una variante del ejercicio 9.3.1, que guarde los datos en formato XML.

Ejercicios propuestos:

(como objetos y sus componentes) en aplicaciones Web.

diseado para poder intercambiar de forma sencilla informacin estructurada

Como curiosidad, SOAP (que da su nombre al SoapFormatter) es un protocolo

Introduccin a la programacin con C#, por Nacho Cabanes

Por ejemplo, es habitual tener un tipo de datos llamado "VARCHAR" para

tabla "cliente", y el nombre de esta relacin es "ser para".

Revisin 0.99zz Pgina 289

el orden en que se disearon. Si no queremos introducir todos los datos, o

Revisin 0.99zz Pgina 290

queremos hacerlo en otro orden, o no recordamos con seguridad el orden, hay

Este formato nos obliga a indicar valores para todos los campos, y exactamente en

contendr algunos datos de cada uno de nuestros amigos. Como es nuestra

insert into personas values ('juan', 'su casa', 25);

"ejemplo1". Esta base de datos contendr una nica tabla, llamada "agenda", que

Como primer ejemplo, crearemos una base de datos sencilla, que llamaremos

10.2.1. Creando la estructura

"values" los valores para los campos de texto entre comillas, y los valores para
campos numricos sin comillas, as:

Para introducir datos usaremos la orden "insert", e indicaremos tras la palabra

modificarla.

10.2.2. Introduciendo datos

veremos alguna orden ms avanzada para extraer la informacin o para

de datos relacional. Cuando ya seamos capaces de guardar datos y recuperarlos,

posteriormente las aplicaremos desde un programa en C# que conecte a una base

algunas de las rdenes que podemos usar para almacenar y obtener datos, y

permite hacer consultas a una base de datos relacional. Por eso, vamos a ver

El lenguaje SQL (Structured Query Language) es un lenguaje muy extendido, que

10.2. Nociones mnimas de lenguaje SQL

grande, la orden necesaria para crear esta tabla sera:


create table personas (
nombre varchar(20),
direccion varchar(40),
edad int
);

distinto tamao. Si usamos "INT" para indicar que nos basta con un entero no muy

lenguaje de consulta ms habitual.

referirnos a texto hasta una cierta longitud, y varios tipos de datos numricos de

Cada gestor de bases de datos tendr una forma de llamar a esos tipos de datos.

nombre - texto, hasta 20 letras


direccin - texto, hasta 40 letras
edad - nmeros, de hasta 3 cifras

podramos decidir lo siguiente:

gestor de bases de datos habr que drselo bastante cuadriculado. Por ejemplo,

tambin qu tamao necesitaremos para cada uno de esos datos, porque al

qu datos concretos ("campos") guardaremos de cada amigo. Deberemos pensar

contendr los datos de nuestros amigos. Por tanto, el siguiente paso ser decidir

para un cierto cliente, de modo que la tabla "factura" se relaciona con la

Adems, existen relaciones entre las tablas: por ejemplo una factura es

electrnico, etc).

almacenar su nombre, su direccin postal, su telfono, su correo

Cada registro est formado por varios "campos" (de cada cliente podemos

cliente "Juan Lpez", el cliente "Pedro lvarez").

Cada tabla est formada por una serie de "registros" (por ejemplo, el

tabla de "productos").

"tablas" (por ejemplo, la tabla de "clientes", la tabla de "proveedores", la

En una base de datos relacional hay varios bloques de datos, llamados

En nuestro caso, nuestra base de datos almacenar una nica tabla, que

create database ejemplo1;

seguido del nombre que tendr la base de datos:

Para crear la base de datos que contiene todo usaremos "create database",

apenas guardaremos tres datos de cada amigo: el nombre, la direccin y la edad.

primera base de datos, no pretendemos que sea perfecta, sino sencilla, as que

Introduccin a la programacin con C#, por Nacho Cabanes

Vamos a aplicar estos conceptos bsicos a la vez que vamos conociendo el

conceptos que debemos conocer antes de empezar a trabajar con ellas:

tambin ms verstil) que un simple fichero de texto o binario. Hay ciertos

Una base de datos relacional es una estructura mucho ms compleja (pero

10.1. Nociones mnimas de bases de datos relacionales

10. Acceso a bases de datos relacionales

Introduccin a la programacin con C#, por Nacho Cabanes

apartado WHERE a la orden "select", as:

Revisin 0.99zz Pgina 291

aquellos que cumplan cierta condicin. Esta condicin se indica aadiendo un

Normalmente no querremos ver todos los datos que hemos introducido, sino slo

+--------+-----------+
| nombre | direccion |
+--------+-----------+
| juan | su casa |
| pedro | su calle |
+--------+-----------+

y obtendramos

select nombre, direccion from personas;

comas:

Si queremos ver slo ciertos campos, detallamos sus nombres, separados por

+--------+-----------+------+
| nombre | direccion | edad |
+--------+-----------+------+
| juan | su casa | 25 |
| pedro | su calle | 23 |
+--------+-----------+------+

algunos gestores de bases de datos, como MySQL):

que, con nuestros datos, dara como resultado (en el intrprete de comandos de

select * from personas;

un asterisco:

campos FROM tabla". Si queremos ver todos los campos, lo indicaremos usando

Para ver los datos almacenados en una tabla usaremos el formato "SELECT

10.2.3. Mostrando datos

insert into personas


(nombre, direccion, edad)
values (
'pedro', 'su calle', 23
);

campos, as:

otra opcin: detallar tambin en la orden "insert" los nombres de cada uno de los

Introduccin a la programacin con C#, por Nacho Cabanes

listo

para

usar
http://nachocabanes.com/csharp

ejemplo

desde

Visual

en

para

Revisin 0.99zz Pgina 292

Studio

puede descargar de http://system.data.sqlite.org/ y tienes un pequeo proyecto de

adaptacin de la biblioteca original. Una de ellas es System.Data.SQLite, que se

En nuestro caso, para acceder a SQLite desde C#, tenemos disponible alguna

programa en caso de que usemos lenguaje C en nuestro proyecto.

o bien como un fichero en C que se podra integrar con los fuentes de nuestro

como un fichero DLL que distribuiramos junto al ejecutable de nuestro programa,

lenguaje SQL para las consultas, y del que existe una versin que se distribuye

SQLite es un gestor de bases de datos de pequeo tamao, que emplea el

10.3. Acceso a bases de datos con SQLite

+--------+-----------+
| nombre | direccion |
+--------+-----------+
| pedro | su calle |
+--------+-----------+

cualquier texto (%) a continuacin:

calles que contengan la palabra "calle", precedida por cualquier texto (%) y con

que nos dira el nombre y la direccin de nuestros amigos llamados que viven en

select nombre, direccion from personas where direccion like '%calle%';

comodn "%", como en este ejemplo:

que usaramos la palabra "like", y para las partes que no conozcamos usaremos el

nombre de la calle). En ese caso, no compararamos con el smbolo "igual" (=), sino

contenido del campo (por ejemplo, porque slo sepamos un apellido o parte del

A veces no querremos comparar con un texto exacto, sino slo con parte del

+--------+-----------+
| nombre | direccion |
+--------+-----------+
| juan | su casa |
+--------+-----------+

que nos dira el nombre y la direccin de nuestros amigos llamados "juan":

select nombre, direccion from personas where nombre = 'juan';

Introduccin a la programacin con C#, por Nacho Cabanes

25);";

cmd = new SQLiteCommand(insercion, conexion);


int cantidad = cmd.ExecuteNonQuery();
if (cantidad < 1)
Console.WriteLine("No se ha podido insertar");
Revisin 0.99zz Pgina 293

// E insertamos dos datos


string insercion = "insert into personas values ('juan', 'su casa',

// Creamos la tabla
string creacion = "create table personas ("
+" nombre varchar(20),direccion varchar(40),edad int);";
SQLiteCommand cmd = new SQLiteCommand(creacion, conexion);
cmd.ExecuteNonQuery();

// Creamos la conexion a la BD.


// El Data Source contiene la ruta del archivo de la BD
SQLiteConnection conexion =
new SQLiteConnection
("Data
Source=ejemplo01.sqlite;Version=3;New=True;Compress=True;");
conexion.Open();

public class EjemploSQLite1


{
public static void Main()
{
Console.WriteLine("Creando la base de datos...");

using System;
// Es necesario aadir la siguiente DLL a la "referencias" del proyecto
using System.Data.SQLite;

// EjemploSQLite1.cs
// Ejemplo de acceso a bases de datos con SQLite (1)
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 294

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\csc ejemploSQLite.cs
/r:System.Data.SqLite.dll /platform:x86

"/platform:x86", as:

comandos, es indicar que es para "plataforma x86", aadiendo la opcin

bits puede no funcionar correctamente. La solucin, si compilamos desde lnea de

Este fichero DLL es de 32 bits, de modo que si usamos una versin de Windows 64

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\csc ejemploSQLite.cs
/r:System.Data.SqLite.dll

tener varias). Por ejemplo, para la versin 2 haramos

en la carpeta de la versin de la plataforma que tengamos instalada (es frecuente

que incorpora la "plataforma punto Net", que es un fichero llamado "csc.exe"

Como alternativa, tambin podemos crear el ejecutable usando el compilador

misma carpeta que nuestro ejecutable, para que ste funcione correctamente.

Tanto el fichero "System.Data.SQLite.dll" como el "sqlite3.dll" debern estar en la

mono ejemploSQLite.exe

de la plataforma .Net, o bien lanzarlo a travs de Mono:

Y para lanzar el ejecutable necesitaremos tener tambin la versin 2 (o superior)

gmcs ejemploSQLite.cs /r:System.Data.SQLite.dll

Por ejemplo, con Mono haramos

aadir el fichero "System.Data.SQLite.dll" a las "referencias" del proyecto.

Finalmente cerraremos la conexin con Close:

Deberemos compilar con la versin 2 (o superior) de la "plataforma punto Net" y

Console.WriteLine("Creada.");

uno, nos indica que no se ha podido guardar correctamente.

// Finalmente, cerramos la conexion


conexion.Close();

insercion = "insert into personas (nombre, direccion, edad)"


+" values ('pedro', 'su calle', 23);";
cmd = new SQLiteCommand(insercion, conexion);
cantidad = cmd.ExecuteNonQuery();
if (cantidad < 1)
Console.WriteLine("No se ha podido insertar");

Introduccin a la programacin con C#, por Nacho Cabanes

introduccin de un dato, debera ser 1; si nos devuelve un dato menor que

Nos devolver la cantidad de filas afectadas, que en nuestro caso, para una

orden SQL a ejecutar, y la lanzaremos con ExecuteNonQuery.

Empleando un objeto de la clase SQLiteCommand, detallaremos cul es la

ya existe.

del fichero, la versin de SQLite, y si el fichero se debe crear (new=True) o

SQLiteConnection, en cuyo constructor indicaremos detalles como la ruta

Crear una conexin a la base de datos, mediante un objeto de la clase

Un fuente que d estos pasos podra ser:

informacin en una base de datos de SQLite seran:

Con esta biblioteca, los pasos a seguir para crear una base de datos y guardar

Introduccin a la programacin con C#, por Nacho Cabanes

Finalmente cerraremos la conexin con Close:

segundo y as sucesivamente.

using System;
Revisin 0.99zz Pgina 295

como parte de un array: dato[0] ser el primer campo, dato[1] ser el

conseguido leer correctamente), y accederemos a los campos de cada dato

Con "Read", leeremos cada dato (devuelve un bool que indica si se ha

SQL a ejecutar, y la lanzaremos con ExecuteReader.

Con un objeto de la clase SQLiteCommand detallaremos cul es la orden

fichero ya existe (new=false).

Crear una conexin a la base de datos, indicando en este caso que el

// EjemploSQLite2.cs
// Ejemplo de acceso a bases de datos con SQLite (2)
// Introduccin a C#, por Nacho Cabanes

intermedios:

Para mostrar los datos, el primer y ltimo paso seran casi iguales, pero no los

Database Browser.

la extensin de Firefox llamada SQLite Manager o como la utilidad SQLite

previamente desde el propio entorno de SQLite, o con algn gestor auxiliar, como

Como curiosidad, esta base de datos de prueba se podra haber creado

que nuestro ejecutable (tpicamente "bin\debug").

"System.Data.SQLite.dll" como el "sqlite3.dll" debern estar en la misma carpeta

Al igual que si compilamos desde la lnea de comandos, tanto el fichero

pestaa "Examinar":

"Agregar referencia" y escogiendo el fichero System.Data.SQLite.DLL desde la

comienzo de la siguiente.

Revisin 0.99zz Pgina 296

guardar todos antes de terminar cada sesin de uso, y volverlos a cargar al

realmente guarde en una base de datos (de SQLite) los datos que maneja. Deber

(10.3.1) Crea una versin de la base de datos de ficheros (ejemplo 04_06a) que

Ejercicios propuestos:

y dato [2] (el tercer dato, la edad) pero no el dato intermedio, dato[1] (la direccin).

Nota: en este segundo ejemplo, mostrbamos dato[0] (el primer dato, el nombre)

Nombre: juan, edad: 25


Nombre: pedro, edad: 23

Que mostrara:

// Finalmente, cerramos la conexion


conexion.Close();

// Leemos los datos de forma repetitiva


while (datos.Read())
{
string nombre = Convert.ToString(datos[0]);
int edad = Convert.ToInt32(datos[2]);
// Y los mostramos
System.Console.WriteLine("Nombre: {0}, edad: {1}",
nombre, edad);
}

// Lanzamos la consulta y preparamos la estructura para leer datos


string consulta = "select * from personas";
SQLiteCommand cmd = new SQLiteCommand(consulta, conexion);
SQLiteDataReader datos = cmd.ExecuteReader();

public static void Main()


{
// Creamos la conexion a la BD
// El Data Source contiene la ruta del archivo de la BD
SQLiteConnection conexion =
new SQLiteConnection
("Data
Source=ejemplo01.sqlite;Version=3;New=False;Compress=True;");
conexion.Open();

public class EjemploSQLite2


{

"Explorador de soluciones", pulsando el botn derecho sobre "References",

las "referencias" de nuestro proyecto. Lo podemos hacer desde la ventana del

// Es necesario aadir la siguiente DLL a la "referencias" del proyecto


using System.Data.SQLite;

Introduccin a la programacin con C#, por Nacho Cabanes

Si usamos Visual Studio o SharpDevelop, tendramos que aadir ese fichero DLL a

Introduccin a la programacin con C#, por Nacho Cabanes

Posibilidad de errores al introducir los datos, lo que dara lugar a

tambin ms difcil cometer este tipo de errores.

Revisin 0.99zz Pgina 297

personas de Alicante, la ltima de ellas no aparecera. Al teclear menos, es

indicado "alicante", sino "alicantw", de modo que si hacemos consultas sobre

Por otra parte, hemos tecleado mal uno de los datos: en la tercera ficha no hemos

ejemplo, 7 bytes menos en cada ficha).

un cdigo de ciudad, por ejemplo "a", gastaramos menos espacio (en este

Si en vez de repetir "alicante" en cada una de esas fichas (registros), utilizsemos

+---------+-----------+-----------+
| nombre | direccion | ciudad
|
+---------+-----------+-----------+
| juan
| su casa | alicante |
| alberto | calle uno | alicante |
| pedro | su calle | alicantw |
+---------+-----------+-----------+

Veamos un ejemplo:

inconsistencias:

Espacio desperdiciado.

dos problemas:

redundantes: existira gran cantidad de datos repetitivos, y esto puede dar lugar a

podran clasificar dentro de un mismo "bloque de informacin" (tabla), seran

Por otra parte, habr ocasiones en que veamos que los datos, a pesar de que se

misma tabla.

compran, y estos dos bloques de informacin no deberan guardarse en una

tendremos datos como los artculos que distribuimos y los clientes que nos los

ejemplo, en una base de datos que guarde la informacin de una empresa

Por una parte, podemos tener bloques de informacin claramente distintos. Por

tabla.

Puede haber varios motivos por los que nos interese trabajar con ms de una

10.4.1. La necesidad de varias tablas

10.4. Un poco ms de SQL: varias tablas

Introduccin a la programacin con C#, por Nacho Cabanes

create table personas (


nombre varchar(20),

aadiendo un nuevo dato: el cdigo de la ciudad

Revisin 0.99zz Pgina 298

Mientras que la tabla de personas sera casi igual al ejemplo anterior, pero

create table ciudades (


codigo varchar(3),
nombre varchar(30),
primary key (codigo)
);

La forma de crear la tabla con esos dos campos y con esa clave primaria sera:

sucesivamente.

como "te" para Toledo de Espaa, "ta" para Toledo de Argentina y as

Unidos)... el nombre claramente no es nico, as que podramos usar cdigos

otra en Argentina, otra en Uruguay, dos en Colombia, una en Ohio (Estados

ciudad. Por ejemplo, hay una ciudad llamado "Toledo" en Espaa, pero tambin

su cdigo. Este cdigo ser el que acte como "clave primaria", para distinguir otra

Vamos a crear la tabla de ciudades, que guardar el nombre de cada una de ellas y

10.4.3. Enlazar varias tablas usando SQL

"fichas" (registros) de otras.

Llamaremos "claves primarias" a estos datos que distinguen claramente unas

inventado por nosotros, o algo similar.

ningn dato claro que nos sirva, en ocasiones aadiremos un "cdigo de cliente",

como puede ser el Documento Nacional de Identidad, o el Pasaporte. Si no hay

solucionar guardando algn dato adicional que s sea nico para cada cliente,

no cobrar a uno de ellos un dinero que corresponde a otro. Eso se suele

llamados "Juan Lpez". Si son nuestros clientes, debemos saber cul es cul, para

persona no es nico: pueden aparecer en nuestra base de datos varios usuarios

forma clara los datos que tenemos almacenados. Por ejemplo, el nombre de una

Generalmente, ser necesario tener algn dato que nos permita distinguir de

10.4.2. Las claves primarias

"a", la ciudad es "alicante").

las ciudades, y el nombre al que corresponden (por ejemplo: si cdigoDeCiudad =

A cambio, necesitaremos una segunda tabla, en la que guardemos los cdigos de

Introduccin a la programacin con C#, por Nacho Cabanes

ver qu personas viven en la ciudad llamada "madrid", haramos:

distintas tablas (por ejemplo, el nombre de una persona y el nombre de

una ciudad), y en ese caso deberemos escribir el nombre de la tabla antes

del nombre del campo.

cada una de las tablas que necesitemos).

+---------+-----------+-----------+
| nombre | direccion | nombre
|
+---------+-----------+-----------+
| juan
| su casa | alicante |
| pedro | su calle | alicante |
| alberto | calle uno | alicante |
| juan
| su casa | barcelona |
| pedro | su calle | barcelona |
| alberto | calle uno | barcelona |
| juan
| su casa | madrid
|
| pedro | su calle | madrid
|

obtenemos 3x3 = 9 resultados:

Revisin 0.99zz Pgina 299

tabla de personas con TODOS los datos de la tabla de ciudades, de modo que

Pero esto todava tiene problemas: estamos combinando TODOS los datos de la

select personas.nombre, direccion, ciudades.nombre from personas, ciudades;

+---------+-----------+-----------+
| nombre | direccion | nombre
|
+---------+-----------+-----------+
| alberto | calle uno | barcelona |
+---------+-----------+-----------+
Revisin 0.99zz Pgina 300

select personas.nombre, direccion, ciudades.nombre from personas, ciudades


where ciudades.nombre like 'b%' and personas.codciudad = ciudades.codigo;

"like":

Y para saber las personas de ciudades que comiencen con la letra "b", usaramos

+--------+-----------+------+
| nombre | direccion | edad |
+--------+-----------+------+
| pedro | su calle | 23 |
+--------+-----------+------+

where

deber terminar comprobando que los dos cdigos coinciden. Por ejemplo, para

Adems, puede ocurrir que tengamos campos con el mismo nombre en

Por eso, una consulta bsica sera algo parecido (slo parecido) a:

select personas.nombre, direccion, edad from personas, ciudades


ciudades.nombre='madrid' and personas.codciudad = ciudades.codigo;

Ese s es el resultado correcto. Cualquier otra consulta que implique las dos tablas

En primer lugar, indicaremos varios nombres despus de "FROM" (los de

pequeos cambios en las rdenes "select" que hemos visto:

Cuando queremos mostrar datos de varias tablas a la vez, deberemos hacer unos

consulta sera:

Esta ser la forma en que trabajaremos normalmente. El resultado de esta

select personas.nombre, direccion, ciudades.nombre from personas, ciudades


where personas.codciudad = ciudades.codigo;

aparece en la ciudad", as:

cdigo de ciudad que aparece en la persona debe ser el mismo que el cdigo que

debera mostrarse junto al nombre "alicante". Nos falta indicar esa condicin: "el

Pero esos datos no son reales: si "juan" vive en la ciudad de cdigo "a", slo

| alberto | calle uno | madrid


|
+---------+-----------+-----------+

Introduccin a la programacin con C#, por Nacho Cabanes

+---------+-----------+-----------+
| nombre | direccion | nombre
|
+---------+-----------+-----------+
| juan
| su casa | alicante |
| alberto | calle uno | barcelona |
| pedro | su calle | madrid
|
+---------+-----------+-----------+

insert into personas values ('juan', 'su casa', 25, 'a');


insert into personas values ('pedro', 'su calle', 23, 'm');
insert into personas values ('alberto', 'calle uno', 22, 'b');

insert into ciudades values ('a', 'alicante');


insert into ciudades values ('b', 'barcelona');
insert into ciudades values ('m', 'madrid');

con el mismo cdigo:

cambio, salvo por el hecho de que no se nos permitira introducir dos ciudades

Para introducir datos, el hecho de que exista una clave primaria no supone ningn

);

direccion varchar(40),
edad decimal(3),
codciudad varchar(3)

Introduccin a la programacin con C#, por Nacho Cabanes

// E insertamos datos
Console.WriteLine(" Introduciendo ciudades");
string insercion = "insert into ciudades values "
+"('a', 'alicante');";
cmd = new SQLiteCommand(insercion, conexion);
int cantidad = cmd.ExecuteNonQuery();
if (cantidad < 1)
Console.WriteLine("No se ha podido insertar");

Console.WriteLine(" Creando la tabla de personas");


creacion = "create table personas ( "
+ " nombre varchar(20), direccion varchar(40),"
+ " edad decimal(3), codciudad varchar(3));";
cmd = new SQLiteCommand(creacion, conexion);
cmd.ExecuteNonQuery();

Revisin 0.99zz Pgina 301

// Creamos las tablas


Console.WriteLine(" Creando la tabla de ciudades");
string creacion = "create table ciudades ( "
+ " codigo varchar(3), nombre varchar(30),"
+ " primary key (codigo));";
SQLiteCommand cmd = new SQLiteCommand(creacion, conexion);
cmd.ExecuteNonQuery();

// Creamos la conexion a la BD.


// El Data Source contiene la ruta del archivo de la BD
SQLiteConnection conexion =
new SQLiteConnection
("Data
Source=ejemplo02.sqlite;Version=3;New=True;Compress=True;");
conexion.Open();

public static void Crear()


{
Console.WriteLine("Creando la base de datos...");

public class EjemploSQLite3


{

using System;
// Es necesario aadir la siguiente DLL a la "referencias" del proyecto
using System.Data.SQLite;

// EjemploSQLite3.cs
// Ejemplo de acceso a bases de datos con SQLite (3)
// Introduccin a C#, por Nacho Cabanes

Vamos a crear un fuente de C# que ponga a prueba los ejemplos anteriores:

10.4.4. Varias tablas con SQLite desde C#

select distinct direccion from personas;

podemos pedir un listado sin duplicados, usando la palabra "distinct":

Si en nuestra tabla puede haber algn dato que se repita, como la direccin,

Introduccin a la programacin con C#, por Nacho Cabanes

Console.WriteLine("Base de datos creada.");

Revisin 0.99zz Pgina 302

+"from personas, ciudades where personas.codciudad =


ciudades.codigo;";
SQLiteCommand cmd = new SQLiteCommand(consulta, conexion);
SQLiteDataReader datos = cmd.ExecuteReader();

"

// Lanzamos la consulta y preparamos la estructura para leer datos


string consulta = "select personas.nombre, direccion, ciudades.nombre

public static void Mostrar()


{
// Creamos la conexion a la BD
// El Data Source contiene la ruta del archivo de la BD
SQLiteConnection conexion =
new SQLiteConnection
("Data
Source=ejemplo02.sqlite;Version=3;New=False;Compress=True;");
conexion.Open();

// Finalmente, cerramos la conexion


conexion.Close();

insercion = "insert into personas values "


+"('alberto', 'calle uno', 22, 'b');";
cmd = new SQLiteCommand(insercion, conexion);
cantidad = cmd.ExecuteNonQuery();
if (cantidad < 1)
Console.WriteLine("No se ha podido insertar");

insercion = "insert into personas values "


+"('pedro', 'su calle', 23, 'm');";
cmd = new SQLiteCommand(insercion, conexion);
cantidad = cmd.ExecuteNonQuery();
if (cantidad < 1)
Console.WriteLine("No se ha podido insertar");

Console.WriteLine(" Introduciendo personas");


insercion = "insert into personas values "
+"('juan', 'su casa', 25, 'a');";
cmd = new SQLiteCommand(insercion, conexion);
cantidad = cmd.ExecuteNonQuery();
if (cantidad < 1)
Console.WriteLine("No se ha podido insertar");

insercion = "insert into ciudades values "


+"('m', 'madrid');";
cmd = new SQLiteCommand(insercion, conexion);
cantidad = cmd.ExecuteNonQuery();
if (cantidad < 1)
Console.WriteLine("No se ha podido insertar");

insercion = "insert into ciudades values "


+"('b', 'barcelona');";
cmd = new SQLiteCommand(insercion, conexion);
cantidad = cmd.ExecuteNonQuery();
if (cantidad < 1)
Console.WriteLine("No se ha podido insertar");

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 303

operadores DIV (divisin entera) y MOD (resto de la divisin):


Revisin 0.99zz Pgina 304

decimales; si queremos trabajar con nmeros enteros, tambin tenemos los

negacin), * (multiplicacin), / (divisin) . La divisin calcula el resultado con

cualquier lenguaje de programacin, ligeramente ampliados: + (suma), - (resta y

delete from personas where nombre = 'juan';

Los operadores matemticos que podemos emplear son los habituales en

similar a como hacamos en la orden "select":

select edad-1 from personas;

from", y con "where" indicamos las condiciones que se deben cumplir, de forma

Podemos borrar los datos que cumplen una cierta condicin. La orden es "delete

10.5. Borrado y modificacin de datos

un ao, con

mostrarlos. Por ejemplo, podemos mostrar cul era la edad de una persona hace

Desde SQL podemos realizar operaciones a partir de los datos antes de

estarn almacenadas en una segunda tabla.

10.6. Operaciones matemticas con los datos

tamao, guarde una categora (por ejemplo, "utilidad" o "vdeo"). Estas categoras

modificar los datos de un registro (dem).

diatamente, permita borrar un registro (reflejando los cambios inmediatamente) y

sino que actualice con cada nueva modificacin: inserte los nuevos datos inme-

(10.5.1) Crea una versin del ejercicio 10.5.1 que no guarde todos los datos al salir,

Ejercicios propuestos:

del "where", los cambios se aplicarn a todos los registros de la tabla).

(al igual que habamos visto para "select" y para "delete", si no indicamos la parte

update personas set edad = edad+1;

Y si queremos corregir todas las edades para sumarles un ao se hara con

update personas set nombre = 'Alberto' where nombre = 'alberto';

corregir con:

Por ejemplo, si hemos escrito "Alberto" en minsculas ("alberto"), lo podramos

campo=nuevoValor where condicion".

Para modificar datos de una tabla, el formato habitual es "update tabla set

cumplen una condicin, sino TODOS los datos.

Cuidado: si no se indica la parte de "where", no se borraran los datos que

tabla "personas".

Esto borrara todas las personas llamadas "juan" que estn almacenadas en la

Introduccin a la programacin con C#, por Nacho Cabanes

(10.4.1) Mejora el ejercicio 10.3.1 para que, adems de el nombre del fichero y su

Ejercicios propuestos:

Creando la base de datos...


Creando la tabla de ciudades
Creando la tabla de personas
Introduciendo ciudades
Introduciendo personas
Base de datos creada.
Datos:
juan - su casa - alicante
pedro - su calle - madrid
alberto - calle uno - barcelona

Su resultado sera:

public static void Main()


{
Crear();
Mostrar();
}

// Finalmente, cerramos la conexion


conexion.Close();

Console..WriteLine("Datos:");
// Leemos los datos de forma repetitiva
while (datos.Read())
{
// Y los mostramos
Console.WriteLine(" {0} - {1} - {2}",
Convert.ToString(datos[0]), Convert.ToString(datos[1]),
Convert.ToString(datos[2]));
}

Introduccin a la programacin con C#, por Nacho Cabanes

+----------+------+
| count(*) | edad |
+----------+------+
|
1 | 22 |
|
1 | 23 |
|
1 | 25 |
+----------+------+

+--------+---------+---------+
| 5/2
| 5 div 2 | 5 mod 2 |
+--------+---------+---------+
| 2.5000 |
2 |
1 |
+--------+---------+---------+

max = mximo valor

sum = suma de los valores

avg = media de los valores

count = cantidad de valores

personas aparecen de cada edad, con:

Revisin 0.99zz Pgina 305

grupos. Por ejemplo, en nuestra tabla "personas", podramos saber cuntas

entonces pidiendo una valor agrupado (count, sum, avg, ...) para cada uno de esos

La forma de obtener subtotales es creando grupos con la orden "group by", y

base de datos, sino tambin la cantidad de clientes que viven en cada ciudad.

Por ejemplo: saber no slo la cantidad de clientes que hay registrados en nuestra

(el total, la media, la cantidad de datos), sino el resultado para un grupo de datos.

Puede ocurrir que no nos interese un nico valor agrupado para todos los datos

10.7 Grupos

select count(*) from personas where direccion like 's%';

saber cuntas personas tienen una direccin que comience por la letra "s", as:

muestren todos los datos que cumplen una condicin. Por ejemplo, podramos

La forma ms habitual de usar "count" es pidiendo con "count(*)" que se nos

min = mnimo valor

Las "funciones de agregacin" ms habituales son:

select min(edad) from personas;

las personas que tenemos en nuestra base de datos, haramos:

datos de una tabla. Por ejemplo, podemos saber cul es la edad ms baja de entre

// AgendaSQLite.cs
// Ejemplo de acceso a bases de datos con SQLite: agenda
// Introduccin a C#, por Nacho Cabanes
Revisin 0.99zz Pgina 306

datos, mostrar todos ellos o buscar los que cumplan una cierta condicin:

Vamos a crear un pequeo ejemplo que, para una nica tabla, permita aadir

10.8 Un ejemplo completo con C# y SQLite

hay pertenecientes a cada categora.

(10.7.1) Crea una versin del ejercicio 10.4.1 que permita saber cuntos ficheros

Ejercicios propuestos:

nuestro uso desde C# y SQLite debera ser suficiente.

En el lenguaje SQL existe mucho ms que lo que hemos visto aqu, pero para

+----------+------+
| count(*) | edad |
+----------+------+
|
1 | 25 |
+----------+------+

que mostrara

select count(*), edad from personas group by edad having edad > 24;

(que se podra traducir como "los que tengan..."). Un ejemplo:

La condicin que se aplica a los grupos no se indica con "where", sino con "having"

sino slo con los que cumplen alguna condicin.

Pero podemos llegar ms all: podemos no trabajar con todos los grupos posibles,

que dara como resultado

Dara como resultado

Tambin podemos aplicar ciertas funciones matemticas a todo un conjunto de

select count(*), edad from personas group by edad;

Introduccin a la programacin con C#, por Nacho Cabanes

select 5/2, 5 div 2, 5 mod 2;

Introduccin a la programacin con C#, por Nacho Cabanes

try
{

Revisin 0.99zz Pgina 307

insercion = "INSERT INTO persona " +


"VALUES ('"+nombre+"','"+direccion+"',"+edad+");";
cmd = new SQLiteCommand(insercion, conexion);
cantidad = cmd.ExecuteNonQuery();
if (cantidad < 1)
return false; // Si no se ha podido insertar

public bool InsertarDatos(string nombre, string direccion, int edad)


{
string insercion; // Orden de insercion, en SQL
SQLiteCommand cmd; // Comando de SQLite
int cantidad;
// Resultado: cantidad de datos

}
else
{
// Si ya existe, abrimos
conexion = new SQLiteConnection(
"Data
Source=agenda.sqlite;Version=3;New=False;Compress=True;");
conexion.Open();
}
}

// Y creamos la tabla
string creacion = "CREATE TABLE persona "
+ "(nombre VARCHAR(30), direccion VARCHAR(40), "
+ " edad INT );";
SQLiteCommand cmd = new SQLiteCommand(creacion, conexion);
cmd.ExecuteNonQuery();

// Abre la base de datos, o la crea si no existe


private void AbrirBD()
{
if (!File.Exists("agenda.sqlite"))
{
// Si no existe, creamos la base de datos
conexion =new SQLiteConnection (
"Data
Source=agenda.sqlite;Version=3;New=True;Compress=True;");
conexion.Open();

// Constructor
public AgendaSQLite()
{
AbrirBD();
}

public class AgendaSQLite


{
static SQLiteConnection conexion;

// Es necesario aadir la siguiente DLL a la "referencias" del proyecto


using System.Data.SQLite;

using System;
using System.IO; // Para File.Exists

Introduccin a la programacin con C#, por Nacho Cabanes

public class pruebaSQLite01


{
public static void Main()
{
AgendaSQLite agenda = new AgendaSQLite();
string opcion;
Revisin 0.99zz Pgina 308

// ------------------------------------------------------------------

~AgendaSQLite()
{
conexion.Close();
}

// Leer todos los datos y devolverlos en un string de varias lneas


public string LeerBusqueda(string texto)
{
// Lanzamos la consulta y preparamos la estructura para leer datos
string consulta = "select * from persona where nombre like '%"
+ texto + "%' or direccion like '%" + texto + "%';";
string resultado = "";
SQLiteCommand cmd = new SQLiteCommand(consulta, conexion);
SQLiteDataReader datos = cmd.ExecuteReader();
// Leemos los datos de forma repetitiva
while (datos.Read())
{
resultado += Convert.ToString(datos[0]) + " - "
+ Convert.ToString(datos[1]) + " - "
+ Convert.ToInt32(datos[2]) + "\n";
}
return resultado;
}

// Leer todos los datos y devolverlos en un string de varias lneas


public string LeerTodosDatos()
{
// Lanzamos la consulta y preparamos la estructura para leer datos
string consulta = "select * from persona";
string resultado = "";
SQLiteCommand cmd = new SQLiteCommand(consulta, conexion);
SQLiteDataReader datos = cmd.ExecuteReader();
// Leemos los datos de forma repetitiva
while (datos.Read())
{
resultado += Convert.ToString(datos[0]) + " - "
+ Convert.ToString(datos[1]) + " - "
+ Convert.ToInt32(datos[2]) + "\n";
}
return resultado;
}

catch (Exception e)
{
return false; // Si no se ha podido insertar (codigo repetido?)
}
return true; // Si todo ha ido bien, devolvemos true

Introduccin a la programacin con C#, por Nacho Cabanes

mostrar) de forma independiente al resto de la direccin.

Revisin 0.99zz Pgina 309

(10.8.4) Ampla el ejemplo 10.8.2 con una tabla de ciudades, que se deber pedir (y

texto (aadiendo al final de los existentes).

registro en lneas separados), o bien se pueda importar datos desde un fichero de

de texto (que contenga el nombre, la direccin y la edad correspondientes a cada

(10.8.3) Ampla el ejemplo 10.8.2, para que permita exportar los datos a un fichero

(10.8.2) Ampla el ejemplo 10.8.1, para que se pueda modificar un registro.

partir de su nombre (que debe coincidir exactamente).

(10.8.1) Ampla este ejemplo (AgendaSQLite), para que se pueda borrar un dato a

Ejercicios propuestos:

opcion = Console.ReadLine();

Console.WriteLine("Escoja una opcin...");


Console.WriteLine("1.- Aadir");
Console.WriteLine("2.- Ver todos");
Console.WriteLine("3.- Buscar");
Console.WriteLine("0.- Salir");

switch (opcion)
{
case "1":
Console.Write("Nombre? ");
string n = Console.ReadLine();
Console.Write("Direccin? ");
string d = Console.ReadLine();
Console.Write("Edad? ");
int e = Convert.ToInt32(Console.ReadLine());
agenda.InsertarDatos(n, d, e);
break;
case "2":
Console.WriteLine(agenda.LeerTodosDatos());
break;
case "3":
Console.Write("Texto a buscar? ");
string txt = Console.ReadLine();
Console.WriteLine(agenda.LeerBusqueda(txt));
break;
}
} while (opcion != "0");

do
{

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 310

contacto con el entorno grfico conocido como "Windows Forms".

Pero esto lo veremos (con poco detalle) ms adelante, cuando entremos en

vista de tabla, y poder hacer modificaciones sobre ellos:

Por ejemplo, existe un "DataGridView", que nos permite recorrer los datos en una

"navegar" por los datos de forma muy simple.

tendremos a nuestra disposicin ciertos componentes visuales que nos permitan

(en un apndice de este texto vers las nociones bsicas sobre cmo crearlos),

En la mayora de los casos, cuando trabajamos desde un entorno "de ventanas"

10.9. Nociones mnimas de acceso desde un entorno


grfico

Introduccin a la programacin con C#, por Nacho Cabanes

sucesores (se parte de un elemento "raz", y la estructura se va ramificando), o los


grafos, formados por una serie de nodos unidos por aristas.
Todas estas estructuras tienen en comn que, si se programan correctamente,
pueden ir creciendo o decreciendo segn haga falta, al contrario que un array, que
tiene su tamao (mximo) prefijado. Adems, ciertas operaciones, como las
ordenaciones o los borrados, pueden ser ms rpidas que en un array.

estructuras de datos que no cambien, pero resultan poco eficientes si tenemos

estructuras cuyo tamao no sea siempre el mismo.

Por ejemplo, si queremos crear una agenda, necesitaremos ir aadiendo nuevos

datos. Si reservamos espacio para un mximo de 10 fichas, no podremos llegar a

aadir la nmero 11. Una solucin "tpica" (pero mala) es sobredimensionar:

preparar una agenda contando con 1000 fichas, aunque supongamos que no

Revisin 0.99zz Pgina 311

la gente llega por un sitio (la cola) y sale por el opuesto (la cabeza). Al igual

Las colas. Una "cola de datos" se comportar como las del cine (en teora):

using System;

// Ejemplo_11_02a.cs
// Ejemplo de clase "Stack" (Pila)
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 312

volviera a mostrar sera:

un tamao mximo definido, sino que puede crecer arbitrariamente.

As, un ejemplo bsico que creara una pila, introdujera tres palabras y luego las

dejarlos en otro sitio distinto. De igual modo, se supone que la pila no tiene

necesitamos incluir en nuestro programa una referencia a "System.Collections".

Para utilizar la clase "Stack" y la mayora de las que veremos en este tema,

First Out: lo ltimo en entrar es lo primero en salir).

que no se puede tomar elementos de otro sitio que no sea la cima, ni

libros: podemos apilar cosas en la cima, o extraer de la cima. Se supone

Las pilas. Una "pila de datos" se comportar de forma similar a una pila de

Algunos ejemplos de estructuras de este tipo son:

facilidad.

Este tipo de estructuras se suele denotar tambin usando las siglas "LIFO" (Last In

hay en la cima ("desapilar", en ingls "pop").

ltimas versiones de C++, existen esqueletos ya creados que podemos utilizar con

un nuevo elemento en la cima ("apilar", en ingls "push") y quitar el elemento que

despus

bsicamente artesanal, mientras que en lenguajes modernos como C#, Java o las

Para crear una pila, emplearemos la clase Stack. Una pila nos permitir introducir

".Net"

como C y Pascal, este tipo de estructuras se tienen que crear de forma

plataforma

disminuyendo segn nos interese. En los lenguajes de programacin "clsicos",

la

11.2. Una pila en C#

incluye

La solucin real suele ser crear estructuras dinmicas, que puedan ir creciendo o

esta alternativa es muchsimo ms lenta.

que

comentaremos los pasos para crear una estructura dinmica de forma "artesanal".

usar acceso aleatorio para leer cada ficha desde disco cuando sea necesario, pero

posibilidades

usando

sobrepasado, etc. Otra (mala) solucin sera la de trabajar siempre en el disco y

las

Veremos ejemplos de cmo crear estructuras dinmicas de estos tipos en C#,

obliga a conocer bien los datos con los que vamos a trabajar, sigue pudiendo verse

vamos a pasar de 200. Esto tiene varios inconvenientes: se desperdicia memoria,

trataremos, como los rboles, en los que cada elemento puede tener varios

Este tipo de variables son sencillas de usar y rpidas... si slo vamos a manejar

Y existen otras estructuras dinmicas ms complejas y que nosotros no

cualquier posicin.

tienen un tamao asignado desde el momento en que se crea el programa.

puede aadir elementos en cualquier posicin y obtenerlos o borrarlos de

programa o de cada funcin. Estas variables, que reciben el nombre de estticas,

Las listas, mas verstiles pero ms complejas de programar, en las que se

11.1. Por qu usar estructuras dinmicas?

Hasta ahora tenamos una serie de variables que declarbamos al principio del

tamao indefinido.

de ella en posiciones intermedias y que la cola puede crecer hasta un

que antes, supondremos que un elemento no puede entrar a la cola ni salir

Introduccin a la programacin con C#, por Nacho Cabanes

11. Punteros y gestin dinmica de memoria

Introduccin a la programacin con C#, por Nacho Cabanes

(string)

"Clear", que borra todo el contenido de la pila.

"Contains", que indica si un cierto elemento est en la pila.

"GetType", para saber de qu tipo son los elementos almacenados en la

"GetEnumerator", que permite usar "enumeradores" para recorrer la pila,

elementos contiene.
Revisin 0.99zz Pgina 313

Tambin tenemos una propiedad "Count", que nos indica cuntos

una funcionalidad que veremos con algn detalle ms adelante.

"ToArray", que devuelve toda la pila convertida a un array.

"ToString", que devuelve el elemento actual convertido a un string.

pila.

"Peek", que mira el valor que hay en la cima, pero sin extraerlo.

esperar en una pila estndar: incorpora tambin mtodos como:

La implementacin de una pila en C# es algo ms avanzada que lo que podramos

"typecast" (conversin forzada de tipos), como en palabra


miPila.Pop();

"objetos", que deberemos convertir al tipo de datos que nos interese utilizando un

Queue miCola = new Queue();


miCola.Enqueue("Hola,");
miCola.Enqueue("soy");
miCola.Enqueue("yo");

public class Ejemplo_11_03a


{
public static void Main()
{
string palabra;

using System;
using System.Collections;

// Ejemplo_11_03a.cs
// Ejemplo de clase "Queue" (Cola)
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 314

que creara una cola, introdujera tres palabras y luego las volviera a mostrar sera:

primero en entrar es lo primero en salir). Un ejemplo bsico similar al anterior,

estructuras se nombran a veces tambin por las siglas FIFO (First In First Out, lo

extremo opuesto, el final de la cola ("Dequeue", desencolar). Este tipo de

introducir elementos por la cabeza ("Enqueue", encolar) y extraerlos por el

Podemos crear colas si nos apoyamos en la clase Queue. En una cola podremos

11.3. Una cola en C#

Como se puede ver en este ejemplo, no hemos indicado que sea una "pila de

strings", sino simplemente "una pila". Por eso, los datos que extraemos son

Implemntalo y comprueba si el resultado de "3 4 6 5 - + * 6 +" es 21.

convierte en: apilar 3, apilar 4, sacar dos datos y sumarlos, guardar 7, terminado.

proceso termina cuando slo hay un dato en la pila. Por ejemplo, "3 4 +" se

que hay en la cima de la pila, se realiza la operacin y se apila su resultado. El

ste se guarda en la pila; si se recibe un operador, se obtienen los dos operandos

parntesis y que se puede resolver usando una pila: si se recibe un dato numrico,

ejemplo, en vez de "3+4" se escribira "3 4 +". Es una notacin que no necesita

consiste en indicar los operandos antes del correspondiente operador. Por

(11.2.4) La "notacin polaca inversa" es una forma de expresar operaciones que

posterior veremos una forma de hacerlo).

internamente un array (si no lo consigues, no te preocupes; en un apartado

(11.2.3) Crea una clase que imite el comportamiento de una pila, pero usando

muestre en orden inverso las lneas que lo forma, empleando una pila.

(11.2.2) Crea un programa que pida al usuario el nombre de un fichero de texto y

muestre en orden contrario, utilizando una pila.

(11.2.1) Crea un programa que pida al usuario 5 nmeros enteros y luego los

Ejercicios propuestos:

Introduccin a la programacin con C#, por Nacho Cabanes

yo
soy
Hola,

cuyo resultado sera:

for (byte i=0; i<3; i++)


{
palabra = (string) miPila.Pop();
Console.WriteLine( palabra );
}

Stack miPila = new Stack();


miPila.Push("Hola,");
miPila.Push("soy");
miPila.Push("yo");

public class Ejemplo_11_02a


{
public static void Main()
{
string palabra;

using System.Collections;

Introduccin a la programacin con C#, por Nacho Cabanes

"Clear", que borra todo el contenido de la cola.

"Contains", que indica si un cierto elemento est en la cola.

"GetType", para saber de qu tipo son los elementos almacenados en la

"GetEnumerator", que permite usar "enumeradores" para recorrer la cola,

indica cuntos elementos contiene.

Al igual que en la pila, tambin tenemos una propiedad "Count", que nos

finalmente lo vuelque a otro fichero de texto.

Revisin 0.99zz Pgina 315

almacene lnea por lnea en una cola, luego muestre este contenido en pantalla y

(11.3.3) Crea un programa que lea el contenido de un fichero de texto, lo

frase vaca. En ese momento, mostrar todas las frases que se haban introducido.

(11.3.2) Crea un programa que pida frases al usuario, hasta que introduzca una

los guarde en una cola y luego los muestre en pantalla.

(11.3.1) Crea un programa que pida al usuario 5 nmeros reales de doble preisin,

Ejercicios propuestos:

"ToArray", que devuelve toda la pila convertida a un array.

una funcionalidad que veremos con algn detalle ms adelante.

"ToString", que devuelve el elemento actual convertido a un string.

cola.

"Peek", que mira el valor que hay en la cabeza de la cola, pero sin extraerlo.

ms avanzada que eso, con mtodos similares a los de antes:

Al igual que ocurra con la pila, la implementacin de una cola que incluye C# es

Hola,
soy
yo

que mostrara:

for (byte i=0; i<3; i++)


{
palabra = (string) miCola.Dequeue();
Console.WriteLine( palabra );
}

Introduccin a la programacin con C#, por Nacho Cabanes

// Mostramos de otra forma lo que contiene


Console.WriteLine( "Contenido tras insertar:");

// Insertamos en la segunda posicion


miLista.Insert(1, "Como estas?");

// Accedemos a una posicin


Console.WriteLine( "La segunda palabra es: {0}",
miLista[1] );

// Mostramos lo que contiene


Console.WriteLine( "Contenido actual:");
foreach (string frase in miLista)
Console.WriteLine( frase );

public class Ejemplo_11_04_01a


{
public static void Main()
{
ArrayList miLista = new ArrayList();
// Aadimos en orden
miLista.Add("Hola,");
miLista.Add("soy");
miLista.Add("yo");

using System;
using System.Collections;

// Ejemplo_11_04_01a.cs
// Ejemplo de ArrayList
// Introduccin a C#, por Nacho Cabanes

sus posibilidades:

Revisin 0.99zz Pgina 316

incluso ordenar toda la lista con "Sort". Vamos a ver un ejemplo de la mayora de

cualquier otra con "Insert", recuperar cualquier elemento usando corchetes, o

En un ArrayList, podemos aadir datos en la ltima posicin con "Add", insertar en

11.4.1. ArrayList

("SortedList").

puede acceder como a los de un array ("ArrayList") y una lista ordenada

genrica, pero s dos variantes especialmente tiles: una lista a cuyos elementos se

En el caso de C#, no tenemos ninguna clase "List" que represente una lista

posicin adecuada para que todos ellos queden en orden.

ordenada, de modo que cada nuevo dato se introduzca automticamente en la

extremos, as como entre dos elementos existentes, o bien incluso de forma

tantas restricciones. Es habitual que se puedan introducir nuevos datos en ambos

Una lista es una estructura dinmica en la que se puede aadir elementos sin

11.4. Las listas

Introduccin a la programacin con C#, por Nacho Cabanes

Contenido actual:
Hola,
soy
yo
La segunda palabra es: soy
Contenido tras insertar:
Hola,
Como estas?
soy
yo
La palabra "yo" est en la posicin 3

El resultado de este programa es:

Revisin 0.99zz Pgina 317

// Ordenamos y vemos dnde ira un nuevo dato


miLista.Sort();
Console.WriteLine( "La frase \"Hasta Luego\"...");
int posicion = miLista.BinarySearch("Hasta Luego");
if (posicion >= 0)
Console.WriteLine( "Est en la posicin {0}", posicion );
else
Console.WriteLine( "No est. El dato inmediatamente mayor "+
"es el {0}: {1}",
~posicion, miLista[~posicion] );

// Mostramos nuevamente lo que contiene


Console.WriteLine( "Contenido dar la vuelta y tras eliminar dos:");
foreach (string frase in miLista)
Console.WriteLine( frase );

// Borramos el segundo dato y la palabra "yo"


miLista.RemoveAt(1);
miLista.Remove("yo");

// Invertimos la lista
miLista.Reverse();

// Buscamos con bsqueda binaria


Console.WriteLine( "Ahora \"yo\" est en la posicin {0}",
miLista.BinarySearch("yo") );

// Mostramos lo que contiene


Console.WriteLine( "Contenido tras ordenar");
foreach (string frase in miLista)
Console.WriteLine( frase );

// Ordenamos
miLista.Sort();

// Buscamos un elemento
Console.WriteLine( "La palabra \"yo\" est en la posicin {0}",
miLista.IndexOf("yo") );

for (int i=0; i<miLista.Count; i++)


Console.WriteLine( miLista[i] );

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 318

almacene lnea por lnea en un ArrayList, luego muestre en pantalla las lneas

(11.4.1.4) Crea un programa que lea el contenido de un fichero de texto, lo

pantalla.

almacene lnea por lnea en un ArrayList, lo ordene y lo muestre ordenado en

(11.4.1.3) Crea un programa que lea el contenido de un fichero de texto, lo

Terminar cuando el usuario introduzca una cadena vaca.

usuario qu texto desea buscar y muestre las lneas que contienen ese texto.

almacene lnea por lnea en un ArrayList, y luego pregunte de forma repetitiva al

(11.4.1.2) Crea un programa que lea el contenido de un fichero de texto, lo

usuario qu lnea desea ver. Terminar cuando el usuario introduzca "-1".

almacene lnea por lnea en un ArrayList, y luego pregunte de forma repetitiva al

(11.4.1.1) Crea un programa que lea el contenido de un fichero de texto, lo

Ejercicios propuestos:

dedicado a otras caractersticas avanzadas de C#.

Veremos los operadores a nivel de bits, como ~, en el tema 13, que estar

ordenado sera la 1, que viene indicada por "~posicion".

"Hasta Luego", su posicin correcta para que todo el ArrayList permaneciera

A efectos prcticos, lo que nos interesa es que si quisiramos insertar la frase

entonces se ver con detalle en qu consiste el "complemento a 2".

representan internamente los nmeros enteros, tanto positivos como negativos, y

la expresin "~posicin"). En el apndice 3 de este texto hablaremos de cmo se

en la posicin 1 (que es el "complemento a 2" del nmero -2, que es lo que indica

que quiere decir que el dato no existe, y que el dato inmediatamente mayor est

cambiando los bits 0 por 1 y viceversa). En el ejemplo anterior, "posicin" vale -2, lo

complementario" de la posicin del dato inmediatamente mayor (es decir, el dato

no aparece, pero ese nmero negativo tiene un significado: es el "valor

a que BinarySearch devuelve un nmero negativo cuando el texto que buscamos

Casi todo debera resultar fcil de entender, salvo quiz el smbolo ~. Esto se debe

Contenido tras ordenar


Como estas?
Hola,
soy
yo
Ahora "yo" est en la posicin 3
Contenido dar la vuelta y tras eliminar dos:
Hola,
Como estas?
La frase "Hasta Luego"...
No est. El dato inmediatamente mayor es el 1: Hola,

Introduccin a la programacin con C#, por Nacho Cabanes

Cantidad de palabras en el diccionario: 3


Lista de palabras y su significado:
adis = good bye

Su resultado sera

Revisin 0.99zz Pgina 319

// Mostramos los datos


Console.WriteLine( "Cantidad de palabras en el diccionario: {0}",
miDiccio.Count );
Console.WriteLine( "Lista de palabras y su significado:" );
for (int i=0; i<miDiccio.Count; i++)
{
Console.WriteLine( "{0} = {1}",
miDiccio.GetKey(i), miDiccio.GetByIndex(i) );
}
Console.WriteLine( "Traduccin de \"hola\": {0}",
miDiccio.GetByIndex( miDiccio.IndexOfKey("hola") ));
Console.WriteLine( "Que tambin se puede obtener con corchetes: {0}",
miDiccio["hola"]);

public class Ejemplo_11_04_02a


{
public static void Main()
{
// Creamos e insertamos datos
SortedList miDiccio = new SortedList();
miDiccio.Add("hola", "hello");
miDiccio.Add("adis", "good bye");
miDiccio.Add("hasta luego", "see you later");

using System;
using System.Collections;

// Ejemplo_11_04_02a.cs
// Ejemplo de SortedList: Diccionario esp-ing
// Introduccin a C#, por Nacho Cabanes

"GetKey") o mediante su clave (con corchetes), como en este ejemplo:

elementos con "Add", o acceder a los elementos mediante su ndice numrico (con

valor (como en un diccionario: la palabra y su definicin). Se puede aadir

En un SortedList, los elementos estn formados por una pareja: una clave y un

11.4.2. SortedList

04_06a), pero usando ArrayList en vez de un array convencional.

(11.4.1.5) Crea una nueva versin de la "bases de datos de ficheros" (ejemplo

lneas pares (segunda, cuarta, etc.).

impares (primera, tercera, etc.) y finalmente vuelque a otro fichero de texto las

Introduccin a la programacin con C#, por Nacho Cabanes

"ContainsValue", para ver si la lista contiene un cierto valor.


"Remove", para eliminar un elemento a partir de su clave.
"RemoveAt", para eliminar un elemento a partir de su posicin.
"SetByIndex", para cambiar el valor que hay en una cierta posicin.

x
x
x
x

public class Ejemplo_11_05a


{

using System;
using System.Collections;

// Ejemplo_11_05a.cs
// Ejemplo de Tabla Hash: Diccionario de informtica
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 320

para un dato concreto, pero que no se puede recorrer en orden), podra ser:

Un ejemplo de diccionario, parecido al anterior (que es ms rpido de consultar

array) o binaria (como en un ArrayList ordenado).

clave es muy rpido, ms que si hacemos una bsqueda secuencial (como en un

secuencialmente y ocupan ms espacio, pero a cambio el acceso a partir de la

dispersin" para colocar los elementos, de forma que no se pueden recorrer

manejan internamente estos datos: la "tabla hash" usa una "funcin de

valor, como en un SortedList, pero la diferencia est en la forma en que se

En una "tabla hash", los elementos estn formados por una pareja: una clave y un

11.5. Las "tablas hash"

C# y mostrar su equivalente (que no ser perfecto) en Pascal.

cadena vaca. salo para convertir un abrir un fichero que contenga un fuente en

a "ReadLn", "void" se convertir a "procedure" y "Console." se convertir a una

convertir a "begin", "WriteLine" se convertir a "WriteLn", "ReadLine" se convertir

almacenadas en una SortedList (por ejemplo, "{" se convertir a "begin", "}" se

(11.4.2.2) Crea un traductor bsico de C# a Pascal, que tenga las traducciones

(por ejemplo, "dos").

nmero del 1 al 10 en ingls (por ejemplo, "two"), diga su traduccin en espaol

(11.4.2.1) Crea un programa que, cuando el usuario introduzca el nombre de un

Ejercicios propuestos:

"Contains", para ver si la lista contiene una cierta clave.

Otras posibilidades de la clase SortedList son:

hasta luego = see you later


hola = hello
Traduccin de "hola": hello

Introduccin a la programacin con C#, por Nacho Cabanes

Console.WriteLine( "No existe la palabra PC");

Revisin 0.99zz Pgina 321

// Mostramos algn dato


Console.WriteLine( "Cantidad de palabras en el diccionario: {0}",
miDiccio.Count );
if (miDiccio.Contains("pc"))

// Ejemplo_11_06a.cs
// Ejemplo de Enumeradores en una Tabla Hash
// Introduccin a C#, por Nacho Cabanes

public class Ejemplo_11_05b


{
public static void Main()
{
// Creamos e insertamos datos
Hashtable miDiccio = new Hashtable();
miDiccio.Add("byte", "8 bits");
miDiccio.Add("pc", "personal computer");
miDiccio.Add("kilobyte", "1024 bytes");

public class Ejemplo_11_06a


{
public static void Main()
{
// Creamos e insertamos datos
Hashtable miDiccio = new Hashtable();
miDiccio.Add("byte", "8 bits");

using System;
using System.Collections;

elementos. Por ejemplo, en una tabla hash podramos hacer:

Revisin 0.99zz Pgina 322

GetEnumerator, que permite obtener un enumerador para recorrer todos sus

dinmicas de forma secuencial. Casi todas ellas contienen un mtodo

Un enumerador es una estructura auxiliar que permite recorrer las estructuras

11.6. Los "enumeradores"

traducciones almacenadas en una tabla Hash.

(11.5.2) Crea una versin alternativa del ejercicio 11.4.2.2, pero que tenga las

traducciones almacenadas en una tabla Hash.

(11.5.1) Crea una versin alternativa del ejercicio 11.4.2.1, pero que tenga las

Ejercicios propuestos:

Hashtable miDiccio = new Hashtable(500);

una idea aproximada de cuntos datos vamos a guardar:

alternativo, en el que se le indica la capacidad inicial que queremos, si tenemos

bastante vaca que cuando est casi llena, podemos usar un constructor

cuando es necesario. Como la tabla hash es mucho ms rpida cuando est

Una tabla hash tiene una cierta capacidad inicial, que se ampla automticamente

buscar entre las claves con "Contains").

("Clear"), o ver si contiene un cierto valor ("ContainsValue", mucho ms lento que

Otras posibilidades son: borrar un elemento ("Remove"), vaciar toda la tabla

else

Console.
.WriteLine( "El significado de PC es: {0}",
miDiccio["pc"]);

Introduccin a la programacin con C#, por Nacho Cabanes

using System;
using System.Collections;

// Ejemplo_11_05b.cs
// Ejemplo de Tabla Hash: Diccionario de informtica
// Introduccin a C#, por Nacho Cabanes

en este ejemplo:

el dato ya existe, con el mtodo "Contains" (o su sinnimo "ContainsKey"), como

introducir un dato que ya existe. Una alternativa a usar try-catch es comprobar si

deberamos controlarlo con un bloque try-catch. Lo mismo ocurre si intentamos

Si un elemento que se busca no existe, se lanzara una excepcin, por lo que

Cantidad de palabras en el diccionario: 3


El significado de PC es: personal computer

que escribira en pantalla:

// Mostramos algn dato


Console.WriteLine( "Cantidad de palabras en el diccionario: {0}",
miDiccio.Count );
try
{
Console.WriteLine( "El significado de PC es: {0}",
miDiccio["pc"]);
}
catch (Exception)
{
Console.WriteLine( "No existe esa palabra!");
}

public static void Main()


{
// Creamos e insertamos datos
Hashtable miDiccio = new Hashtable();
miDiccio.Add("byte", "8 bits");
miDiccio.Add("pc", "personal computer");
miDiccio.Add("kilobyte", "1024 bytes");

Introduccin a la programacin con C#, por Nacho Cabanes

// Mostramos todos los datos


Console.WriteLine("Contenido:");
IEnumerator miEnumerador = miPila.GetEnumerator();

public class Ejemplo_11_06b


{
public static void Main()
{
Stack miPila = new Stack();
miPila.Push("Hola,");
miPila.Push("soy");
miPila.Push("yo");

using System;
using System.Collections;

// Ejemplo_11_06b.cs
// Ejemplo de Enumeradores en una pila (Stack)
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 323

usar ser un IEnumerator, con un campo Current para saber el valor actual:

Para las colecciones "normales", como las pilas y las colas, el tipo de Enumerador a

funcin de dispersin.

el mismo orden en el que los introdujimos, debido a que se colocan siguiendo la

Como se ve en el ejemplo, es habitual que no obtengamos la lista de elementos en

campos Key y Value.

ser un "enumerador de diccionario" (IDictionaryEnumerator), que contiene los

caso de las tablas hash, que tiene dos campos (clave y valor), el enumerador a usar

intenta moverse al siguiente elemento y devuelve "false" si no lo consigue. En el

Como se puede ver, los enumeradores tendrn un mtodo "MoveNext", que

Contenido:
pc = personal computer
byte = 8 bits
kilobyte = 1024 bytes

cuyo resultado es

// Mostramos todos los datos


Console.WriteLine("Contenido:");
IDictionaryEnumerator miEnumerador = miDiccio.GetEnumerator();
while ( miEnumerador.MoveNext() )
Console.WriteLine("{0} = {1}",
miEnumerador.Key, miEnumerador.Value);

miDiccio.
.Add("pc", "personal computer");
miDiccio.Add("kilobyte", "1024 bytes");

Introduccin a la programacin con C#, por Nacho Cabanes

anterioridad a ste.

using System;

// Ejemplo_11_07a.cs
// Ejemplo de clase "Pila" basada en un array
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 324

modo que el siguiente dato que se obtuviera sera el que se introdujo con

la ltima posicin, y que disminuye el contador que indica la posicin, de

Creamos tambin una funcin "Desapilar", que devuelve el dato que hay en

siguiente dato se introduzca a continuacin.

array (inicialmente la 0) y despus incrementa esa posicin, para que el

Creamos una funcin "Apilar", que aade en la primera posicin libre del

esperemos que vaya a almacenar la pila.

Utilizamos internamente un array ms grande que la cantidad de datos que

El fuente podra ser as:

Por ejemplo, podramos imitar una pila dando los siguientes pasos:

sobredimensionadas, y esto puede ser un ejercicio de programacin interesante.

Las estructuras dinmicas se pueden imitar usando estructuras estticas

11.7. Cmo "imitar" una pila usando "arrays"

http://msdn.microsoft.com/es-es/library/system.collections(en-us,VS.71).aspx#

sin traducir al espaol):

plataforma .Net consultando la referencia en lnea de MSDN (mucha de la cual est

Se puede saber ms sobre las estructuras dinmicas que hay disponibles en la

aunque all reciben el nombre de "iteradores".

Nota: los "enumeradores" existen tambin en otras plataformas, como Java,

Contenido:
yo
soy
Hola,

que escribira

while ( miEnumerador.MoveNext() )
Console.WriteLine("{0}", miEnumerador.Current);

Introduccin a la programacin con C#, por Nacho Cabanes

} // Fin de la clase

for (byte i=0; i<3; i++)


{
palabra = (string) miPila.Desapilar();
Console.WriteLine( palabra );
}
// Fin da Main de prueba

PilaString miPila = new PilaString();


miPila.Apilar("Hola,");
miPila.Apilar("soy");
miPila.Apilar("yo");

public static void Main()


{
string palabra;

// Extraer de la pila: Desapilar


public string Desapilar()
{
if (posicionPila < 0)
Console.WriteLine("Pila vacia!");
else
{
posicionPila --;
return datosPila[posicionPila];
}
return null;
}

// Aadir a la pila: Apilar


public void Apilar(string nuevoDato)
{
if (posicionPila == MAXPILA)
Console.WriteLine("Pila llena!");
else
{
datosPila[posicionPila] = nuevoDato;
posicionPila ++;
}
}

// Constructor
public PilaString()
{
posicionPila = 0;
datosPila = new string[MAXPILA];
}

public class PilaString


{
string[] datosPila;
int posicionPila;
const int MAXPILA = 200;

Revisin 0.99zz Pgina 325

Introduccin a la programacin con C#, por Nacho Cabanes

apartado 11.4.1 funcionara perfectamente:


Revisin 0.99zz Pgina 326

Con slo estos dos cambios, el ejemplo de uso de ArrayList que vimos en el

using System.Collections.Generic;

Y necesitaramos incluir un nuevo "using" al principio del programa:

List<<string> miLista = new List<string>();

cada uso. Por ejemplo, una lista de strings se definira con:

definen estructuras de datos genricas, que nosotros podemos particularizar en

Por ello, en la versin 2 de la "plataforma .Net" se introdujeron los "generics", que

extraigamos un dato.

adaptado a un tipo de datos, y no necesite una conversin de tipos cada vez que

de un ArrayList (crecimiento dinmico, mltiples mtodos disponibles) est

En ocasiones puede ser interesante algo un poco ms rgido, que con las ventajas

obtenemos (excepto con los "strings").

Esto obliga a que hagamos una "conversin de tipos" con cada dato que

string, luego un nmero entero, luego uno de coma flotante, despus un struct

de distinto tipo en una misma estructura: un ArrayList que contenga primero un

que hemos visto, es que permiten guardar datos de cualquier tipo, incluso datos

Una ventaja, pero tambin a la vez un inconveniente, de las estructuras dinmicas

11.8. Introduccin a los "generics"

(11.7.5) Crea una lista ordenada (de "strings") usando un ArrayList.

que t elijas) usando un ArrayList.

(11.7.4) Crea una cola que almacene un bloque de datos (struct, con los campos

un array.

(11.7.3) Crea una pila de "doubles", usando internamente un ArrayList en vez de

la lista (el nmero "n"). Deber almacenar "strings".

un nuevo dato en orden en el array, y un "Extraer(n)", que obtenga un elemento de

clave-valor como los SortedList). Debe contener un mtodo "Insertar", que aadir

(11.7.2) Crear una clase "ListaOrdenada", que almacene un nico dato (no un par

mtodo "Encolar" y otro "Desencolar".

dato que se introduzca debe ser el primero que se obtenga). Debe tener un

permita introducir datos (nmeros enteros) y obtenerlos en modo FIFO (el primer

(11.7.1) Usando esta misma estructura de programa, crea una clase "Cola", que

Ejercicios propuestos:

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 327

// Mostramos nuevamente lo que contiene


Console.WriteLine( "Contenido dar la vuelta y tras eliminar dos:");
foreach (string frase in miLista)

// Borramos el segundo dato y la palabra "yo"


miLista.RemoveAt(1);
miLista.Remove("yo");

// Invertimos la lista
miLista.Reverse();

// Buscamos con bsqueda binaria


Console.WriteLine( "Ahora \"yo\" est en la posicin {0}",
miLista.BinarySearch("yo") );

// Mostramos lo que contiene


Console.WriteLine( "Contenido tras ordenar");
foreach (string frase in miLista)
Console.WriteLine( frase );

// Ordenamos
miLista.Sort();

// Buscamos un elemento
Console.WriteLine( "La palabra \"yo\" est en la posicin {0}",
miLista.IndexOf("yo") );

Dictionary<string, int> dict = new Dictionary<string, int>();

// Mostramos de otra forma lo que contiene


Console.WriteLine( "Contenido tras insertar:");
for (int i=0; i<miLista.Count; i++)
Console.WriteLine( miLista[i] );

Revisin 0.99zz Pgina 328

// Mostramos algn dato


Console.WriteLine( "Cantidad de palabras en el diccionario: {0}",
miDiccio.Count );

public class Ejemplo_11_08b


{
public static void Main()
{
// Creamos e insertamos datos
Dictionary<string, string> miDiccio = new Dictionary<string,
string>();
miDiccio.Add("byte", "8 bits");
miDiccio.Add("pc", "personal computer");
miDiccio.Add("kilobyte", "1024 bytes");

using System;
using System.Collections.Generic;

// Ejemplo_11_08b.cs
// Ejemplo de Dictionary
// Introduccin a C#, por Nacho Cabanes

Contains por ContainsKey:

seran una declaracin parecida a la anterior, el "using" correcto, y cambiar

podramos crear una versin alternativa del ejemplo 11_05b. Los nicos cambios

As, con un diccionario que tenga tanto claves string como valores string,

usar una cadena como clave, pero un nmero entero como valor obtenido:

ser strings, sino el tipo de datos que nosotros decidamos. Por ejemplo, podemos

equivale a una tabla Hash, pero en la que las claves y los valores no tienen por qu

No slo tenemos listas. Por ejemplo, tambin existe un tipo "Dictionary", que

cualquier otro dato.

De esta misma forma, podramos crear una lista de structs, o de objetos, o de

// Ordenamos y vemos dnde ira un nuevo dato


miLista.Sort();
Console.WriteLine( "La frase \"Hasta Luego\"...");
int posicion = miLista.BinarySearch("Hasta Luego");
if (posicion >= 0)
Console.WriteLine( "Est en la posicin {0}", posicion );
else
Console.WriteLine( "No est. El dato inmediatamente mayor "+
"es el {0}: {1}",
~posicion, miLista[~posicion] );

Console.
.WriteLine( frase );

Introduccin a la programacin con C#, por Nacho Cabanes

// Insertamos en la segunda posicion


miLista.Insert(1, "Como estas?");

// Accedemos a una posicin


Console.WriteLine( "La segunda palabra es: {0}",
miLista[1] );

// Mostramos lo que contiene


Console.WriteLine( "Contenido actual:");
foreach (string frase in miLista)
Console.WriteLine( frase );

public class Ejemplo_11_08a


{
public static void Main()
{
List<string> miLista = new List<string>();
// Aadimos en orden
miLista.Add("Hola,");
miLista.Add("soy");
miLista.Add("yo");

using System;
using System.Collections.Generic;

// Ejemplo_11_08a.cs
// Ejemplo de List<string>
// Introduccin a C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

bien que le pidamos al compilador que nos reserve un espacio de memoria (ms
adelante veremos cmo).

(11.8.2) Crea un programa que lea todo el contenido de un fichero, lo guarde en

una lista de strings y luego lo muestre en orden inverso (de la ltima lnea a la

difciles de encontrar), el compilador nos obligamos a que le digamos que


sabemos que esa zona de programa no es segura, usando la palabra "unsafe":
unsafe static void pruebaPunteros() { ...

asociado: por ejemplo, un "puntero a entero" ser una direccin de memoria en la

que habr almacenado (o podremos almacenar) un nmero entero.

El hecho de poder acceder directamente al contenido de ciertas posiciones de

int numero;
int* posicion;

Revisin 0.99zz Pgina 329

/* "numero" es un nmero entero */


/* "posicion" es un "puntero a entero" (direccin de
memoria en la que podremos guardar un entero) */

En primer lugar, comentemos la sintaxis bsica que utilizaremos:

muestre qu es un puntero y cmo se utiliza.

que acompaan al lenguaje bsico. Aun as, veremos algn ejemplo que nos

varias estructuras dinmicas ya creadas como parte de las bibliotecas auxiliares

estructuras dinmicas, pero en C# podemos "esquivarlos", dado que tenemos

En lenguajes como C, es imprescindible utilizar punteros para poder crear

cualquier cosa, pero a cambio de un riesgo de errores mucho mayor.

mcs unsafe1.cs /unsafe

compilarlo":

Revisin 0.99zz Pgina 330

compilador "s, s que este programa tiene zonas no seguras, pero aun as quiero

Por tanto, deberemos compilar con la opcin /unsafe como forma de decir al

mcs unsafe1.cs
unsafe1.cs(15,31): error CS0227: Unsafe code requires the `unsafe' command
line
option to be specified
Compilation failed: 1 error(s), 0 warnings

que si nuestro cdigo no es seguro, deberemos compilarlo con la opcin "unsafe":

Es ms, si intentamos compilar obtendremos un mensaje de error, que nos dice

Como los punteros son "peligrosos" (es frecuente que den lugar a errores muy

tiene de especial es que normalmente un puntero tendr un tipo de datos

memoria da una mayor versatilidad a un programa, porque permite hacer casi

11.9.2. Zonas "inseguras": unsafe

posicion = &numero;

La palabra "puntero" se usa para referirse a una direccin de memoria. Lo que

11.9.1. Qu es un puntero?

11.9. Los punteros en C#

haba reservado para la variable "numero", lo haramos usando el smbolo "&", as:

Si queremos que "posicion" contenga la direccin de memoria que el compilador

habitual que tomemos una direccin de memoria que ya contiene otro dato, o

04_06a), pero usando List en vez de un array convencional.

primera).

podremos hacer cosas como posicion=5; porque nada nos garantiza que la
posicin 5 de la memoria est disponible para que nosotros la usemos. Ser ms

El valor que guarda "posicion" es una direccin de memoria. Generalmente no

int *posicion;

(11.8.1) Crea una nueva versin de la "bases de datos de ficheros" (ejemplo

es correcto escribir

variable. Ese asterisco puede ir junto a cualquiera de ambos, por lo que tambin

Es decir, escribiremos un asterisco entre el tipo de datos y el nombre de la

Introduccin a la programacin con C#, por Nacho Cabanes

Ejercicios propuestos:

if (miDiccio.ContainsKey("pc"))
Console.WriteLine( "El significado de PC es: {0}",
miDiccio["pc"]);
else
Console.WriteLine( "No existe la palabra PC");

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 331

// Ahora cambiamos el valor guardado en punteroAEntero


*punteroAEntero = 5;
// Y x se modifica tambin:
Console.WriteLine("x vale {0}", x);
Console.WriteLine("En punteroAEntero hay un {0}", *punteroAEntero);

// Damos un valor a x
x = 2;
// punteroAEntero ser la direccin de memoria de x
punteroAEntero = &x;
// Los dos estn en la misma direccin:
Console.WriteLine("x vale {0}", x);
Console.WriteLine("En punteroAEntero hay un {0}", *punteroAEntero);

public class Ejemplo_11_09_03a


{
private unsafe static void pruebaPunteros()
{
int* punteroAEntero;
int x;

using System;

// Ejemplo_11_09_03a.cs
// Primer ejemplo de punteros
// Introduccin a C#, por Nacho Cabanes

valor en l:

Veamos un ejemplo bsico de cmo dar valor a un puntero y de cmo guardar un

11.9.3. Uso bsico de punteros

decir que queremos "Permitir cdigo no seguro":

"propiedades del proyecto" (tpicamente estar al final del men "Proyecto") y

Si usamos Visual Studio como herramienta de desarrollo, tendremos que ir a las

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 332

// sta es la parte insegura de "Main"


unsafe
{
// La funcin espera un puntero, as que le pasamos
// la direccin de memoria del entero:

public static void Main()


{
int i = 1;

public class Ejemplo_11_09_04a


{
public unsafe static void Incrementar(int* p)
{
//Incrementamos el entero "apuntado" por p
*p = *p + 1;
}

using System;

// Ejemplo_11_09_04a.cs
// Segundo ejemplo de punteros
// Introduccin a C#, por Nacho Cabanes

indicando entre llaves una parte de una funcin:

Tambin podemos hacer que slo una parte de un programa sea insegura,

11.9.4. Zonas inseguras

comprobar que no son los mismos que al principio.

encuentran dos variables y que luego muestre sus contenidos en pantalla, para

(11.9.3.1) Crea un programa que intercambie la posicin de memoria en la que se

Ejercicios propuestos:

viceversa.

Es decir, cada cambio que hacemos en "x" se refleja en "punteroAEntero" y

x vale 2
En punteroAEntero hay un 2
x vale 5
En punteroAEntero hay un 5

La salida de este programa es:

public static void Main()


{
pruebaPunteros();
}

Introduccin a la programacin con C#, por Nacho Cabanes

Ejercicios propuestos:

vamos a profundizar.

Revisin 0.99zz Pgina 333

"habitual", conocida como "heap" o montn, pero es un detalle sobre el que no

memoria se reserva en la pila (stack), en vez de hacerlo en la zona de memoria

Existen ciertas diferencias entre esta forma de trabajar y la que ya conocamos: la

// Mostramos el array
for (int i = 0; i < tamanyoArray; i++)
{
Console.WriteLine(datos[i]);
}

// Rellenamos el array
for (int i = 0; i < tamanyoArray; i++)
{
datos[i] = i*10;
}

public class Ejemplo_11_09_05a


{
public unsafe static void Main()
{
const int tamanyoArray = 5;
int* datos = stackalloc int[tamanyoArray];

using System;

// Ejemplo_11_09_05a.cs
// Tercer ejemplo de punteros: stackalloc
// Introduccin a C#, por Nacho Cabanes

Un ejemplo completo podra ser:

int* datos = stackalloc int[5];

ejemplo, una forma alternativa de crear un array de enteros sera sta:

Podemos reservar espacio para una variable dinmica usando "stackalloc". Por

11.9.5. Reservar espacio: stackalloc

Incrementar(
(&i);

// Y mostramos el resultado
Console.WriteLine (i);

Introduccin a la programacin con C#, por Nacho Cabanes

Posicion actual: 1242196

obtengamos no tienen por qu ser las mismas) a:

Revisin 0.99zz Pgina 334

El resultado sera algo parecido (porque las direcciones de memoria que

// Finalmente mostramos el array


Console.WriteLine("Contenido:");
for (int i = 0; i < tamanyoArray; i++)
{
Console.WriteLine(datos[i]);
}

// Rellenamos los dems con 10,20,30...


for (int i = 1; i < tamanyoArray; i++)
{
posicion++;
Console.WriteLine("Posicion actual: {0}", (int) posicion);
*posicion = i * 10;
}

// Ponemos un 0 en el primer dato


*datos = 0;

Console.WriteLine("Posicion actual: {0}", (int) posicion);

public class Ejemplo_11_09_06a


{
public unsafe static void Main()
{
const int tamanyoArray = 5;
int* datos = stackalloc int[tamanyoArray];
int* posicion = datos;

using System;

// Ejemplo_11_09_06a.cs
// Cuarto ejemplo de punteros: aritmtica de punteros
// Introduccin a C#, por Nacho Cabanes

verlo con un ejemplo:

su direccin pasar a ser 40.004 (porque cada entero ocupa 4 bytes). Vamos a

ejemplo, si un puntero a entero tiene como valor 40.000 y hacemos "puntero++",

posicin capaz de almacenar un dato como el que corresponde a su tipo base. Por

representa... pero no cambiar de uno en uno, sino que saltar a la siguiente

Si aumentamos o disminuimos el valor de un puntero, cambiar la posicin que

11.9.6. Aritmtica de punteros

"stackalloc" y luego los muestre en orden inverso.

(11.9.5.1) Crea una programa que pida al usuario 5 strings, los almacene usando

Introduccin a la programacin con C#, por Nacho Cabanes

Console.WriteLine("Leyendo el segundo dato...");


fixed (int* posicionDato = &datos[1])
{
Console.WriteLine("En posicionDato hay {0}",

public class Ejemplo_11_09_07a


{
public unsafe static void Main()
{
int[] datos={10,20,30};

using System;

// Ejemplo_11_09_07a.cs
// Quinto ejemplo de punteros: fixed
// Introduccin a C#, por Nacho Cabanes

programa que queremos "bloquear" se indica entre llaves:

Revisin 0.99zz Pgina 335

Esta palabra se usa antes de la declaracin y asignacin de la variable, y la zona de

al compilador que esa zona "no debe limpiarse automticamente".

asignaciones son peligrosas y obligar a que usemos la palabra "fixed" para indicar

Por eso, en ciertas ocasiones el compilador puede avisarnos de que algunas

y haya borrado.

de memoria que el entorno de ejecucin haya previsto que ya no necesitaramos

cuando usamos variables dinmicas, porque estemos accediendo a una posicin

ocupado por variables que ya no se usan. Esto puede suponer algn problema

C# cuenta con un "recolector de basura", que se encarga de liberar el espacio

11.9.7. La palabra "fixed"


Leyendo el segundo dato...
En posicionDato hay 20
Leyendo el primer dato...
Ahora en posicionDato hay 10

Revisin 0.99zz Pgina 336

tendremos que empezar otra nueva zona "fixed".


El resultado del ejemplo anterior sera:

avisa de que esa variable es de "slo lectura" (read-only). Por eso, para cambiarla,

usando "stackalloc" y luego los recorra incrementando el puntero a partir de la

posicin del primer elemento.

valor de esa variables; si lo intentamos recibiremos un mensaje de error que nos

Como se ve en el programa anterior, en una zona "fixed" no se puede modificar el

*posicionDato);

Console.WriteLine("Leyendo el primer dato...");


fixed (int* posicionDato = datos)
{
Console.WriteLine("Ahora en posicionDato hay {0}",
*posicionDato);
}

(11.9.6.1) Crea una programa que pida al usuario 4 nmeros reales, los almacene

1242200
1242204
1242208
1242212

Introduccin a la programacin con C#, por Nacho Cabanes

Ejercicios propuestos:

Posicion actual:
Posicion actual:
Posicion actual:
Posicion actual:
Contenido:
0
10
20
30
40

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 337

AddMilliseconds, AddMinutes, AddMonths, AddSeconds, AddHours, o bien un Add

DateTime, como: AddDays (que aparece en el ejemplo anterior), AddHours,

Para calcular nuevas fechas, podemos usar mtodos que generan un nuevo

tipo a entero, anteponindole "(int)"); DayOfYear (da del ao).

que se puede convertir en un nmero del 0-domingo- al 6-sbado- si se fuerza su

Millisecond (milisegundos); DayOfWeek (da de la semana: su nombre en ingls,

(nmero de mes), Year (ao); Hour (hora), Minute (minutos), Second (segundos),

hora actual de este equipo), Today (fecha actual); Day (da del mes), Month

Algunos de las propiedades ms tiles de este tipo de datos son: Now (fecha y

apartado de"using", o bien usar la llamada completa:


Revisin 0.99zz Pgina 338

Este mtodo pertenece a System.Threading, que deberamos incluir en nuestro

cierta cantidad de milsimas de segundo con: Thread.Sleep(5000);

(Sleep) el subproceso (o hilo, "Thread") que representa nuestro programa una

"while" que compruebe la hora continuamente, sino que podemos "bloquear"

programa se detenga una cierta cantidad de tiempo, no hace falta que usemos un

Tambin podemos hacer una pausa en la ejecucin: Si necesitamos que nuestro

Han pasado 8886 das


Si lo quieres con decimales: 8886,41919806277 das
Y si quieres ms detalles: 8886.10:03:38.7126236

El resultado de este programa sera algo como

Console.WriteLine("Y si quieres ms detalles: {0}",


diferencia);

Console.WriteLine("Si lo quieres con decimales: {0} das",


diferencia.TotalDays);

using System;

public class Ejemplo_12_01a


{
public static void Main()
{
DateTime fecha = DateTime.Now;
Console.WriteLine("Hoy es {0} del mes {1} de {2}",
fecha.Day, fecha.Month, fecha.Year);
DateTime manyana = fecha.AddDays(1);
Console.WriteLine("Maana ser {0}",
manyana.Day);
}
}

Console.WriteLine("Han pasado {0} das",


diferencia.Days);

TimeSpan diferencia =
fechaActual.Subtract(fechaNacimiento) ;

public class Ejemplo_12_01b


{
public static void Main()
{
DateTime fechaActual = DateTime.Now;
DateTime fechaNacimiento = new DateTime(1990, 9, 18);

using System;

// Ejemplo_12_01b.cs
// Diferencia entre dos fechas
// Introduccin a C#, por Nacho Cabanes

decimales, Days, o con decimales, TotalDays), como se ve en este ejemplo:

(TimeSpan), del que podemos saber detalles como la cantidad de das (sin

Cuando restamos dos fechas, obtenemos un dato de tipo "intervalo de tiempo"

restar una fecha de otra).

ms genrico (para sumar una fecha a otra) y un Subtract tambin genrico (para

Introduccin a la programacin con C#, por Nacho Cabanes

// Ejemplo_12_01a.cs
// Ejemplo bsico de manejo de fechas
// Introduccin a C#, por Nacho Cabanes

(AddSeconds), das (AddDays), etc. Un ejemplo bsico de su uso sera:

calcular otras fechas sumando a la actual una cierta cantidad de segundos

(Day), el mes (Month) o el ao (Year) de una fecha, entre otros. Tambin podemos

Dentro de ese tipo de datos DateTime, tenemos las herramientas para saber el da

DateTime fecha = DateTime.Now;

hora) actual con:

ello, tenemos el tipo de datos DateTime. Por ejemplo, podemos hallar la fecha (y

Desde C#, tenemos la posibilidad de manejar fechas y horas con facilidad. Para

12.1. Fecha y hora. Temporizacin

12. Algunas bibliotecas adicionales de uso


frecuente

Introduccin a la programacin con C#, por Nacho Cabanes

lu ma mi ju vi
1
4 5 6 7 8
11 12 13 14 15
18 19 20 21 22
25 26 27 28

Mayo 2015

algo como:

s
2
9
16
23

do
3
10
17
24

Revisin 0.99zz Pgina 339

"bool")

public class Ejemplo_12_02a


{
public static void Main()

using System;

Revisin 0.99zz Pgina 340

Title: el ttulo que se va a mostrar en la consola (es un "string")


// Ejemplo_12_02a.cs
// Ms posibilidades de "System.Console"
// Introduccin a C#, por Nacho Cabanes

pantalla.
KeyAvailable: indica si hay alguna tecla disponible para ser leda (es un
x

primero debers calcular qu da de la semana es el da 1 de este mes). Deber ser

parmetro

que se pueda ver). Si no se indica este parmetro, la tecla se muestra en

El

(12.1.4) Crea un programa que muestre el calendario del mes actual (pista:

teclado.

sin permitir que se vea en pantalla ("true" para que no se vea, "false" para

desde

qu da de la semana se trataba.

tecla

(12.1.3) Crea un programa que pida al usuario su fecha de nacimiento, y diga de

una

"interceptar" es un "bool", y es opcional. Indica si se debe capturar la tecla

cmo hacer que se mantenga fijo en unas ciertas coordenadas de la pantalla).

lee

pantalla).
Readkey(interceptar):

segunda, luego en la tercera y as sucesivamente (en el prximo apartado veremos

contar desde el margen izquierdo, e "y" desde la parte superior de la

"WriteLine", de modo que aparecer en la primera lnea de pantalla, luego en la

(12.1.2) Crea un reloj que se muestre en pantalla, y que se actualice cada segundo

(usando "Sleep"). En esta primera aproximacin, el reloj se escribir con

deber primero cambiar el color de fondo y despus usar "Clear").


SetCursorPosition(x, y): cambia la posicin del cursor ("x" se empieza a

mostrarse con un cero inicial, de modo que siempre aparezcan con dos cifras.
x

partir de entonces; si se quiere borrar la pantalla con un cierto color, se

las milsimas). Si los minutos o los segundos son inferiores a 10, debern

final de este apartado).


BackgroundColor: cambia el color de fondo (para el texto que se escriba a

correspondiente), la hora, los minutos, los segundos y las dcimas de segundo (no
x

hay definidas constantes como "ConsoleColor.Black", que se detallan al

ForegroundColor: cambia el color de primer plano (para indicar los colores,

Clear: borra la pantalla.

del mes (usa un array para almacenar los nombres y accede a la posicin

resultar ms tiles:

net". Vamos a ver algunas de las funcionalidades adicionales que nos pueden

posibilidades estn incluidas en las primeras versiones de la "plataforma punto

En "Console" hay mucho ms que ReadLine y WriteLine, aunque no todas las

12.2. Ms posibilidades de la "consola"

tendr abril, mayo y junio y as sucesivamente.

meses en anchura: el primer bloque contendr enero febrero y marzo, el segundo

que se indique como parmetro en lnea de comandos. Deben mostrarse tres

(12.1.6) Crea un programa que vuelque a un fichero de texto el calendario del ao

ao que se indiquen como parmetros en lnea de comandos.

(12.1.5) Crea un programa que muestre el calendario correspondiente al mes y el

Introduccin a la programacin con C#, por Nacho Cabanes

(12.1.1) Crea una versin mejorada del ejemplo 12_01a, que muestre el nombre

Ejercicios propuestos:

public class Ejemplo_12_01c


{
public static void Main()
{
DateTime fecha = DateTime.Now;
Console.WriteLine("Son las {0}:{1}:{2}",
fecha.Hour, fecha.Minute, fecha.Second);
Console.WriteLine("Vamos a esperar 3 segundos...");
Thread.Sleep(3000);
fecha = DateTime.Now;
Console.WriteLine("Ahora son las {0}:{1}:{2}",
fecha.Hour, fecha.Minute, fecha.Second);
}
}

using System;
using System.Threading;

// Ejemplo_12_01c.cs
// Pausas
// Introduccin a C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

int maxY = Console.WindowHeight;


int maxX = Console.WindowWidth;
Console.SetCursorPosition(maxX-50, maxY-1);
Console.ForegroundColor = ConsoleColor.Red;
Console.Write("Pulsa una tecla para terminar... ");
Console.ReadKey(true);

Console.ForegroundColor = ConsoleColor.Blue;
Console.SetCursorPosition(10, 15);
Console.Write("Pulsa 1 o 2: ");
ConsoleKeyInfo tecla;
do
{
tecla = Console.ReadKey(false);
}
while ((tecla.KeyChar != '1') && (tecla.KeyChar != '2'));

posY = 10; // En la fila 10


Random r = new Random(DateTime.Now.Millisecond);
posX = r.Next(20, 40); // Columna al azar entre 20 y 40
Console.SetCursorPosition(posX, posY);
Console.WriteLine("Bienvenido");

Console.Title = "Ejemplo de consola";


Console.BackgroundColor = ConsoleColor.Green;
Console.ForegroundColor = ConsoleColor.Black;
Console.Clear();

int posX, posY;

if (tecla.Key == ConsoleKey.Escape) ... .

Revisin 0.99zz Pgina 341

PANT), Insert (Tecla INS (INSERT)), Delete (Tecla SUPR (SUPRIMIR))

Spacebar (Tecla BARRA ESPACIADORA), PrintScreen (Tecla IMPR

ENTRAR), Pause (Tecla PAUSA), Escape (Tecla ESC (ESCAPE)),

RETROCESO), Tab (Tecla TAB), Clear (Tecla BORRAR), Enter (Tecla

o Teclas de edicin y control como, como: Backspace (Tecla

Algunos de los cdigos de tecla disponibles son:

la tecla ESC podramos hacer

visualizable, como F1 o las teclas de cursor). Por ejemplo, para comprobar

Key, que se refiere a la tecla (porque hay teclas que no tienen un carcter

ejemplo, podramos hacer if (tecla.KeyChar == '1') ...

KeyChar, que representa el carcter que se escribira al pulsar esa tecla. Por

Un ConsoleKeyInfo tiene campos como:

que usar una variable de tipo "ConsoleKeyInfo" (informacin de tecla de consola).

Para comprobar el valor de una tecla, como se ve en el ejemplo anterior, tenemos

en la plataforma .Net 1.x, sino a partir de la versin 2).

(Nota: no todas las posibilidades que se aplican en este ejemplo estn disponibles

Introduccin a la programacin con C#, por Nacho Cabanes

NumPad7,

NumPad8,

NumPad9,

Multiply

(Tecla

que

permite

comprobar

si

se

han

pulsado

// Ejemplo_12_02b.cs
// No bloquear el programa con Console.Readkey
// Introduccin a C#, por Nacho Cabanes

ninguna tecla:

Revisin 0.99zz Pgina 342

smbolo a izquierda y derecha, pero muestra una animacin simple si no pulsamos

alguna tecla que haya que analizar, como en este ejemplo, que permite mover un

podemos emplear Console.KeyAvailable para comprobar si ya se ha pulsado

tecla. Si queremos hacer algo mientras que el usuario no pulse ninguna tecla,

Console.Readkey hace que el programa se quede parado hasta que se pulse una

if ((tecla.Modifiers & ConsoleModifiers.Alt) != 0)


Console.Write("Has pulsado Alt");

ejemplo de su uso sera:

simultneamente teclas modificadoras: Alt, Shift o Control. Un

o Modifiers,

Siguiente pista de multimedia), etc.

volumen, dem), VolumeUp (Subir el volumen), MediaNext (Tecla

Keyboard, bajo Windows 2000 o posterior), VolumeDown (Bajar el

VolumeMute (Tecla Silenciar el volumen, enMicrosoft Natural

o Incluso teclas multimedia, si el teclado las incorpora, como:

de Windows)

logotipo de Windows), RightWindows (Tecla derecha con el logotipo

o Teclas especiales de Windows: LeftWindows (Tecla izquierda con el

o Teclas de funcin: F1, F2 y sucesivas (hasta F24)

o Sleep (Tecla Espera del equipo)

Divisin)

Subtract (Tecla Resta), Decimal (Tecla Decimal), Divide (Tecla

Multiplicacin), Add (Tecla Suma), Separator (Tecla Separador),

NumPad6,

numrico), NumPad1, NumPad2, NumPad3, NumPad4, NumPad5,

o Teclado numrico adicional: NumPad0 (Tecla 0 del teclado

D9

o Teclas numricas, como: D0 (Tecla 0), D1, D2, D3, D4, D5, D6, D7, D8,

O, P, Q, R, S, T, U, V, W, X, Y, Z

o Teclas alfabticas, como: A (Tecla A), B, C, D, E, F, G, H, I, J, K, L, M, N,

FLECHA ABAJO)

ARRIBA), RightArrow (Tecla FLECHA DERECHA), DownArrow (Tecla

LeftArrow (Tecla FLECHA IZQUIERDA), UpArrow (Tecla FLECHA

PageDown (Tecla AV PG), End (Tecla FIN), Home (Tecla INICIO),

o Teclas de movimiento del cursor, como: PageUp (Tecla RE PG),

Introduccin a la programacin con C#, por Nacho Cabanes

DarkGreen (verde

u ocre), Gray (gris),

de 50 milisegundos entre un "fotograma" y otro.


Revisin 0.99zz Pgina 343

los bordes de la pantalla. Para que no se mueva demasiado rpido, haz una pausa

(12.2.1) Crea un programa que muestre una "pelota" (la letra "O") rebotando en

Ejercicios propuestos:

azulado claro), Red (rojo), Magenta (fucsia), Yellow (amarillo), White (blanco).

DarkGray (gris oscuro), Blue (azul), Green (verde), Cyan (aguamarina o verde

(fucsia oscuro o prpura), DarkYellow (amarillo oscuro

oscuro) DarkCyan (verde azulado oscuro), DarkRed (rojo oscuro), DarkMagenta

"ConsoleColor") son: Black (negro), DarkBlue (azul marino),

Los colores que tenemos disponibles (y que se deben escribir precedidos con

procesador para tareas poco importantes.

animacin no sea demasiado rpida como para no hacer un consumo muy alto de

una comprobacin de teclas y la siguiente, con Thread.Sleep, tanto para que la

Al igual que en este ejemplo, ser recomendable hacer una pequea pausa entre

Console.Clear();
Console.SetCursorPosition(posX, posY);
Console.Write( simbolos[ simboloActual ]);
Thread.Sleep(500);
if (Console.KeyAvailable)
{
ConsoleKeyInfo tecla = Console.ReadKey(true);
if (tecla.Key == ConsoleKey.RightArrow) posX++;
if (tecla.Key == ConsoleKey.LeftArrow) posX--;
if (tecla.Key == ConsoleKey.Escape) terminado = true;
}
simboloActual++;
if (simboloActual > 3) simboloActual = 0;

}
while ( ! terminado );

do
{

public class Ejemplo_12_02b


{
public static void Main()
{
int posX=40, posY=10;
string simbolos = "^>v<";
byte simboloActual = 0;
bool terminado = false;

using System;
using System.Threading;

Introduccin a la programacin con C#, por Nacho Cabanes

deberemos aadirlo entre los "using" de nuestro programa).

Revisin 0.99zz Pgina 344

(la clase Directory est declarada en el espacio de nombres System.IO, por lo que

public class Ejemplo_12_03a


{
public static void Main()
{
string miDirectorio = @"d:\datos";
if (!Directory.Exists(miDirectorio))
Directory.CreateDirectory(miDirectorio);
}
}

using System.IO;

// Ejemplo_12_03a.cs
// Crear un directorio
// Introduccin a C#, por Nacho Cabanes

podramos crear un directorio con:

borrarlo (Delete), moverlo (Move), comprobar si existe (Exists), etc. Por ejemplo,

La clase Directory contiene mtodos para crear un directorio (CreateDirectory),

Directory y DirectoryInfo.

Si queremos analizar el contenido de un directorio, podemos emplear las clases

12.3. Lectura de directorios

pantalla).

actualizado en pantalla, que lo dibuje siempre en la esquina superior derecha de la

(12.2.5) Crea una versin mejorada del programa 12.1.2 (mostrar el reloj

recuperarlo (con F3).

(pulsando F1), guardar el contenido de la pantalla en un fichero de texto (con F2) o

permita escribir ms caracteres (por ejemplo, las letras), as como mostrar ayuda

(12.2.4) Crea una versin del programa de "dibujar" en consola (12.2.3), que

con las flechas del teclado y pulsando "espacio" para dibujar un punto o borrarlo.

(12.2.3) Crea un programa que permita "dibujar" en consola, moviendo el cursor

del usuario, y que no necesite pulsar Intro tras escoger cada opcin.

use colores para ayudar a distinguir los mensajes del programa de las respuestas

(12.2.2) Crea una versin de la "base de datos de ficheros" (ejemplo 04_06a) que

Introduccin a la programacin con C#, por Nacho Cabanes

}
}

contenido del directorio al que se ha accedido).

Revisin 0.99zz Pgina 345

fichero, sino otros detalles adicionales como el tamao y la fecha de creacin:


Revisin 0.99zz Pgina 346

(en ese momento, se actualizar la lista de ficheros y directorios, para mostrar el

permite conseguir informacin similar sobre un fichero. Podramos usar estas dos

clases para ampliar el ejemplo anterior, y que no slo muestre el nombre de cada

ficheros (a continuacin), y permita entrar a un directorio si se pulsa Intro sobre l

sobre fechas de creacin, modificacin y acceso, y, de forma anloga, FileInfo nos

(12.3.4) Mejora el ejercicio 12.3.3 para que muestre directorios (en primer lugar) y

distinto del resto.

lista usando las flechas del cursor. El elemento seleccionado se mostrar en color

carpeta actual, y permitir al usuario moverse hacia arriba o abajo dentro de la

antiguo "Comandante Norton": mostrar la lista de ficheros y subdirectorios de la

(12.3.3) Crea un programa que permita "pasear" por la carpeta actual, al estilo del

todos los ficheros de texto existentes en la carpeta actual.

(12.3.2) Crea un programa que cree un fichero de texto a partir del contenido de

para luego volver a preguntarle el nombre del fichero.

pulsar "Intro" y se le mostrar la lista de ficheros existentes en el directorio actual ,

texto, cuyo nombre escoja el usuario. Si el usuario no sabe el nombre, podr

(12.3.1) Crea un programa que muestre en pantalla el contenido de un fichero de

Ejercicios propuestos:

hiberfil.sys, de tamao 6775930880, creado 15/07/2013 17:48:07

que escribira cosas como

public class Ejemplo_12_03d


{
public static void Main()
{
string miDirectorio = @"c:\";
DirectoryInfo dir = new DirectoryInfo(miDirectorio);
FileInfo[] infoFicheros = dir.GetFiles();
foreach (FileInfo infoUnFich in infoFicheros)
{
Console.WriteLine("{0}, de tamao {1}, creado {2}",
infoUnFich.Name,
infoUnFich.Length,
infoUnFich.CreationTime);
}

using System;
using System.IO;

// Ejemplo_12_03d.cs
// Lista detallada de ficheros en un directorio
// Introduccin a C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

Si necesitamos ms detalles, la clase DirectoryInfo permite obtener informacin

public class Ejemplo_12_03c


{
public static void Main()
{
string[] listaFicheros = Directory.GetFiles(".", "*.cs");
foreach(string fichero in listaFicheros)
Console.WriteLine(fichero);
}
}

using System;
using System.IO;

// Ejemplo_12_03c.cs
// Lista de ficheros en un directorio
// Introduccin a C#, por Nacho Cabanes

con:

ejemplo, podramos saber todos los fuentes de C# ("*.cs") de la carpeta actual (".")

deben seguir los nombres de los ficheros que buscamos, como "*.txt". Por

Se puede aadir un segundo parmetro a "GetFiles", que sera el patrn que

listaFicheros = Directory.GetFiles(miDirectorio);
foreach(string fichero in listaFicheros)
Console.WriteLine(fichero);

public class Ejemplo_12_03b


{
public static void Main()
{
string miDirectorio = @"c:\";
string[] listaFicheros;

using System;
using System.IO;

// Ejemplo_12_03b.cs
// Lista de ficheros en un directorio
// Introduccin a C#, por Nacho Cabanes

directorio con:

ficheros que contiene un directorio. As, podramos listar todo el contenido de un

Tambin tenemos un mtodo "GetFiles" que nos permite obtener la lista de

Introduccin a la programacin con C#, por Nacho Cabanes

Comandante Norton") para que, si se pulsa Intro sobre un cierto fichero, lance el
correspondiente proceso.

de ficheros que ya se han copiado.

public class Ejemplo_12_04a


{
public static void Main()
{
Console.WriteLine("Lanzando el bloc de notas...");

using System;
using System.Diagnostics;

// Ejemplo_12_04a.cs
// Lanzar otro proceso y esperar
// Introduccin a C#, por Nacho Cabanes

cerrase podra ser:

Revisin 0.99zz Pgina 347

Revisin 0.99zz Pgina 348

public class Ejemplo_12_05a


{
public static void Main()
{
string avanceLinea = Environment.NewLine;
Console.WriteLine("Directorio actual: {0}",
Environment.CurrentDirectory);
Console.WriteLine("Nombre de la mquina: {0}",
Environment.MachineName);
Console.WriteLine("Nombre de usuario: {0}", Environment.UserName);
Console.WriteLine("Dominio: {0}", Environment.UserDomainName);
Console.WriteLine("Cdigo de salida del programa anterior: {0}",
Environment.ExitCode);
Console.WriteLine("Linea de comandos: {0}", Environment.CommandLine);
Console.WriteLine("Versin del S.O.: {0}",
System.Convert.ToString(Environment.OSVersion));
Console.WriteLine("Version de .Net: {0}",
Environment.Version.ToString());
String[] discos = Environment.GetLogicalDrives();

proc.WaitForExit();

Un programa completo que lanzara el bloc de notas y que esperase a que se

using System;
using System.Diagnostics;

// Ejemplo_12_05a.cs
// Informacin sobre el sistema
// Introduccin a C#, por Nacho Cabanes

conseguiramos con "WaitForExit", aadiendo esta segunda lnea:

proseguir. Si aun as, queremos esperar a que se complete la otra tarea, lo

necesario esperar a que termine otra la tarea, sino que nuestro programa puede

En los actuales sistemas operativos multitarea se da por sentado que no es

usan para avanzar de lnea, etc:

la plataforma .Net, nombre de usuario y mquina, carcter o caracteres que se

unidades de disco disponibles, directorio actual, versin del sistema operativo y de

Process proc = Process.Start("notepad.exe");

La clase "Environment" nos sirve para acceder a informacin sobre el sistema:

con:

12.5. Datos sobre "el entorno"

proceso. Este proceso se le indicar como parmetro en la lnea de comandos.

(12.4.3) Crea un programa que mida el tiempo que tarda en ejecutarse un cierto

programa "tipo Comandante Norton").

con "Process.Start". Por ejemplo, podramos lanzar el bloc de notas de Windows

(incluso programas externos de casi cualquier tipo) es creando un nuevo proceso

trabaje por nosotros. La forma de llamar a otras rdenes del sistema operativo

sistema operativo s es capaz de hacer por nosotros, podemos hacer que ella

Si hay algo que no sepamos o podamos hacer, pero que alguna utilidad del

12.4. El entorno. Llamadas al sistema

(12.4.1) Mejora el ejercicio 12.3.3 (la versin bsica del programa "tipo

debe mostrar una "barra de progreso" de color amarillo, que indicar el porcentaje

(12.4.2) Aplica esta misma mejora al ejercicio 12.3.5 (la versin con dos paneles del

Ejercicios propuestos:

copiarn a la carpeta del otro panel. Mientras se estn copiando, el programa

Process proc = Process.Start("notepad.exe");


Console.WriteLine("Esperando a que se cierre...");
proc.WaitForExit();
Console.WriteLine("Terminado!");

Introduccin a la programacin con C#, por Nacho Cabanes

pulsa F5, los ficheros seleccionados en la carpeta actual del panel actual se

distinto. Se podrn deseleccionar volviendo a pulsar "Espacio" o "Insert". Si se

pulsando "Espacio" o "Insert". Los ficheros seleccionados se mostrarn en un color

(12.3.6) Mejora el ejercicio 12.3.5, para que se pueda "seleccionar un fichero"

distinto. Si se pulsa el "tabulador", cambiar el panel activo.

otro, cada uno de los cuales podr estar mostrando el contenido de un directorio

(12.3.5) Mejora el ejercicio 12.3.4 para que contenga dos paneles, uno al lado del

Introduccin a la programacin con C#, por Nacho Cabanes

TcpListener para recibir, y en ambos casos trataremos los datos como un tipo

fichero o escribiramos en l.

Revisin 0.99zz Pgina 349

public static void Main()


{
WebClient cliente = new WebClient();
Stream conexion = cliente.OpenRead("http://www.nachocabanes.com");
StreamReader lector = new StreamReader(conexion);
string linea;

public class DescargarWeb


{

using System;
using System.IO; // Para Stream
using System.Net; // Para System.Net.WebClient

// Ejemplo_12_06a.cs
// Ejemplo de descarga y anlisis de una web:
// Muestra las lneas que contienen "Pascal"
// Introduccin a C#, por Nacho Cabanes

contengan un cierto texto (por ejemplo, la palabra "Pascal"):

tratara de un fichero de texto (StreamReader), y mostrar slo las lneas que

ejemplo, la pgina principal de "www.nachocabanes.com"), lnea a lnea como si se

Como primer ejemplo, vamos a ver cmo podramos recibir una pgina web (por

diferencias hay entre el protocolo TCP y el UDP).

bsicos de redes, como qu es una direccin IP, qu significa "localhost" o qu

System;
System.IO;
// Para
System.Text; // Para
System.Net;
// Para
System.Net.Sockets;

Stream
Encoding
Dns, IPAddress
// Para NetworkStream

Revisin 0.99zz Pgina 350

private static string esperar(string direccion, int puerto)


{

conexion.Close();
cliente.Close();

conexion.Write(secuenciaLetras, 0, secuenciaLetras.Length);

private static void enviar(string direccion,


int puerto, string frase)
{
TcpClient cliente = new TcpClient(direccion, puerto);
NetworkStream conexion = cliente.GetStream();
byte[] secuenciaLetras = Encoding.ASCII.GetBytes( frase );

public class ComunicacionRed


{
static string direccionPrueba = "localhost";
static int puertoPrueba = 2112;

using
using
using
using
using

// Ejemplo_12_06b.cs
// Ejemplo de envio y recepcin de frases a travs de la red
// Introduccin a C#, por Nacho Cabanes

especial de fichero binario, un NetworkStream:

directamente el protocolo TCP: emplearemos un TcpClient para enviar y un

accesibles de forma sencilla, tpicamente enmascarados como si leyramos de un

(Nota: en este apartado se asumir que el lector entiende algunos conceptos

es la de comunicar dos ordenadores, para enviar informacin desde uno y


recibirla desde el otro. Se puede hacer de varias formas. Una de ellas es usando

Muchos de los servicios que podemos obtener de Internet o de una red local son

Otra posibilidad que tampoco es complicada (aunque s algo ms que sta ltima)

28:
<li><a href="pascal/index.php">Pascal/Delphi</a></li>
54: | <a href="pascal/index.php">Pascal / Delphi</a>
204:
<li><a href="pascal/index.php">Pascal/Delphi</a></li>

El resultado de este programa sera algo como:

int contador = 0;
while ( (linea=lector.ReadLine()) != null )
{
contador ++;
if (linea.IndexOf("Pascal") >= 0)
Console.WriteLine("{0}: {1}", contador, linea);
}
conexion.Close();

Introduccin a la programacin con C#, por Nacho Cabanes

12.6. Algunos servicios de red.

panel derecho.

pulsa Alt+F2, se realizar el mismo proceso, pero cambiar la unidad activa en el

escoger una de ellas, y esa pasar a ser la unidad activa en el panel izquierdo. Si se

disco. Si se pulsa Alt+F1, se mostrar la lista de unidades lgicas, el usuario podr

Comandante Norton") para que se pueda pasar a "navegar" por otra unidad de

(12.5.1) Mejora el ejercicio 12.4.2 (la versin ms completa del programa "tipo

Ejercicios propuestos:

Console.
.WriteLine("Unidades lgicas: {0}",
String.Join(", ", discos));
Console.WriteLine("Carpeta de sistema: {0}",
Environment.GetFolderPath(Environment.SpecialFolder.System));

Introduccin a la programacin con C#, por Nacho Cabanes

if (respuesta == "2") // Enviar


{
Console.Write("Enviando... ");
enviar( direccionPrueba, puertoPrueba, "Prueba de texto");
Console.WriteLine("Enviado");
}
else // Recibir
{
Console.WriteLine("Esperando... ");
Console.WriteLine( esperar(direccionPrueba, puertoPrueba) );
Console.WriteLine("Recibido");
}

Pulse 1 para recibir o 2 para enviar


2
Enviando...

escogeramos la opcin de Enviar (2):

Revisin 0.99zz Pgina 351

(porque estamos conectando a la direccin "localhost"), y en esta nueva sesin

Entonces lanzaramos otra sesin del mismo programa en el mismo ordenador

1
Esperando...

Lo razonable es lanzar primero el proceso que espera para recibir, pulsando 1:

Pulse 1 para recibir o 2 para enviar

Cuando lanzramos el programa, se nos preguntara si queremos enviar o recibir:

return frase;

public static void Main()


{
Console.WriteLine("Pulse 1 para recibir o 2 para enviar");
string respuesta = Console.ReadLine();

cliente.Close();
listener.Stop();

string frase = lector.ReadToEnd();

// Tratamos de hallar la primera IP que corresponde


// a una direccin como "localhost"
IPAddress direccionIP = Dns.GetHostEntry(direccion).AddressList[0];
// Comienza la espera de informacin
TcpListener listener = new TcpListener(direccionIP,puerto);
listener.Start();
TcpClient cliente = listener.AcceptTcpClient();
NetworkStream conexion = cliente.GetStream();
StreamReader lector = new StreamReader(conexion);

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 352

longitud 2, 2 de longitud 3 y uno de longitud 4. Cada jugador ver el estado de su

horizontal o en vertical sobre un tablero de 8x8, y sern: 4 de longitud 1, 3 de

de si ha acertado ("impacto") o no ("agua"). Los barcos se podrn colocar en

"dispare" por turnos, escogiendo una casilla (por ejemplo, "B5"), y siendo avisado

jugador decida dnde quiere colocar sus barcos, y luego cada uno de ellos

(12.6.5) Crea un juego de "barquitos" en red, para dos jugadores, en el que cada

(alojadas en otros sitios web).

procesar los enlaces internos (en el mismo sitio web), no las pginas externas

de forma recursiva las pginas que corresponden a dichos enlaces. Slo deber

pgina que indique el usuario, analizando los enlaces que contiene y descargando

(12.6.4) Crea un programa que descargue todo un sitio web, partiendo de la

mostrar en pantalla un mensaje que avise al usuario de si hay cambios o no.

comparando el contenido actual con una copia guardada en fichero. Deber

(12.6.3) Crea un programa que monitorice cambios en una pgina web,

comunicarse, sin necesidad de seguir turnos estrictos.

(12.6.2) Crea un programa bsico de chat, en el que dos usuarios puedan

jugador escoja un movimiento, pero ambos vean un mismo estado del tablero.

(12.6.1) Crea un juego de "3 en raya" en red, para dos jugadores, en el que cada

Ejercicios propuestos:

de TCP, pero nosotros no veremos ms detalles de ninguno de ambos mtodos.

en vez de los TcpClient, o de un modo "no fiable", usando el protocolo UDP en vez

Esto se puede conseguir a un nivel algo ms alto, usando los llamados "Sockets"

uno de ellos.

en el que hubiera que avisar a otros jugadores de los cambios realizados por cada

sino la IP del otro equipo), como podra ser un chat o cualquier juego multijugador

comunicaran diferentes equipos (en este caso, la direccin no sera "localhost",

Esta misma idea se podra usar como base para programas ms elaborados, que

Enviando... Enviado

Y la segunda sesin confirmara que el envo ha sido correcto:

Prueba de texto
Recibido

desde la segunda, y se mostrara en pantalla:

Instantneamente, en la primera sesin recibiramos el texto que hemos enviado

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 353

ficheo, y en la siguiente sesin se reanude el juego en el punto en el que qued.

pueda decidir aplazar la partida, y entonces el resultado quede guardado en

(12.6.7) Mejora el juego de "barquitos" completo (12.6.6) para que un jugador

ms detallado ("tocado" o "hundido", segn el caso).

(12.6.6) Mejora el juego de "barquitos" (12.6.5) para que el aviso de impacto sea

juego terminar cuando uno de los jugadores hunda toda la flota del otro.

propio tablero y los impactos que ha conseguido en el tablero del otro jugador. El

Introduccin a la programacin con C#, por Nacho Cabanes

System;
System.Collections.Generic;
System.Linq;
System.Text;

Y esta es apariencia del fuente si usamos SharpDevelop 3:

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
}
}
}

using
using
using
using

usamos VisualStudio 2008:

Revisin 0.99zz Pgina 354

de nombres que se llamar igual que el proyecto. Esta es apariencia del fuente si

nuevo proyecto, el fuente "casi vaco" que se nos propone contendr un espacio

De hecho, con entornos como SharpDevelop o Visual Studio, cuando creamos un

.Net.

de esas clase pueda simultanear su uso con el de las incluidas en la plataforma

razonable es crear un nuevo espacio de nombres, de forma que cualquier usuario

a la consola, o mi propia clase "Random" para manejo de nmeros aleatorios, lo

de otros. Por ejemplo, si yo quisiera crear mi propia clase "Console" para el acceso

Por eso, se recomienda usar "espacios de nombres", que permitan distinguir unos

esperada.

correctamente, o, peor an, que compilaran pero no funcionaran de la forma

distintas procedencias, esto podra dar lugar a programas que no compilaran

proyecto) creen funciones o clases que se llamen igual, y, si se mezclan fuentes de

en distintos puntos del mundo (o incluso en distintos grupos de un mismo gran

La idea detrs de ese "using" es que puede ocurrir que distintos programadores

plataforma .Net.

funciones que estamos usando pertenecen a la estructura bsica de C# y de la

"System.Console" o bien "using System". Esa palabra "System" indica que las

Desde nuestros primeros programas hemos estado usando cosas como

13.1. Espacios de nombres

13. Otras caractersticas avanzad as de C#

Introduccin a la programacin con C#, por Nacho Cabanes

Cambiar

Complemento (not)

&

y ~

WriteLine.

Una

es

la

original

de

C#,

que

invocaramos

con

Revisin 0.99zz Pgina 355

mediante "ConsolaAmpliada.Console". El resultado es que podemos tener dos

texto modifica y en color (ayudndose de System.Console), y que llamaramos

"System.Console". Otra es la que hemos creado para el ejemplo, que escribe un

mtodo

Como se puede ver, este ejemplo tiene dos clases Console, y ambas tienen un

public class PruebaDeNamespaces


{
public static void Main()
{
System.Console.WriteLine("Hola");
ConsolaAmpliada.Console.WriteLine("Hola otra vez");
}
}

namespace ConsolaAmpliada
{
public class Console
{
public static void WriteLine(string texto)
{
System.Console.ForegroundColor = ConsoleColor.Blue;
System.Console.WriteLine("Mensaje: "+texto);
}
}
}

ceros
ceros

1101 >> 2 = 0011

1101 << 2 = 110100

1101 ^ 1011 = 0110

1101 | 1011 = 1111

1101 & 1011 = 1001

~1100 = 0011

Ejemplo

Revisin 0.99zz Pgina 356

Console.WriteLine("La variable a vale {0}", a);


Console.WriteLine("y b vale {0}", b);
Console.WriteLine(" El complemento de a es: {0}", ~a);
Console.WriteLine(" El producto lgico de a y b es: {0}", a&b);
Console.WriteLine(" Su suma lgica es: {0}", a|b);
Console.WriteLine(" Su suma lgica exclusiva es: {0}", a^b);
Console.WriteLine(" Desplacemos a a la izquierda: {0}", a << 1);

public class Bits


{
public static void Main()
{
int a = 67;
int b = 33;

using System;

// Ejemplo_13_02a.cs
// Operaciones a nivel de bits
// Introduccin a C#, por Nacho Cabanes

Ahora vamos a aplicarlo a un ejemplo completo en C#:

derecha

Desplazamiento a la Desplaza y rellena con >>

izquierda

Desplazamiento a la Desplaza y rellena con <<

using System;

distintos

1 slo si los 2 bits son ^

Suma exclusiva (xor)

es 1

1 slo si uno de los bits |

1 slo si los 2 bits son 1

por

Suma lgica (or)

C#

En

Producto lgico (and)

viceversa

Resultado

Operacin

etc). Vamos primero a ver qu significa cada una de esas operaciones.

Podemos hacer desde C# operaciones entre bits de dos nmeros (AND, OR, XOR,

13.2. Operaciones con bits

Hola
Mensaje: Hola otra vez

entre ellas. El resultado del programa sera:

clases Console accesibles desde el mismo programa, sin que existan conflictos

Introduccin a la programacin con C#, por Nacho Cabanes

// Ejemplo_13_01a.cs
// Ejemplo de uso de "namespaces"
// Introduccin a C#, por Nacho Cabanes

nuestra y la original, de System):

espacio de nombres, que cree una nueva clase Console y que utilice las dos (la

Nosotros vamos a preparar un ejemplo algo ms avanzado, que contenga un

Console.Write("Press any key to continue . . . ");


Console.ReadKey(true);

// TODO: Implement Functionality Here

namespace PruebaDeNamespaces
{
class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Hello World!");

using System;

Introduccin a la programacin con C#, por Nacho Cabanes

Console..WriteLine(" Desplacemos a a la derecha: {0}", a >> 1);

Revisin 0.99zz Pgina 357

multiplicar por potencias de dos; desplazar a la derecha es dividir por potencias de

primera vista. Por ejemplo: desplazar a la izquierda es una forma muy rpida de

Qu utilidades puede tener todo esto? Posiblemente, ms de las que parece a

0010 0001 = 33

Desplazar los bits una posicin a la derecha es como dividir entre dos:

1000 0110 = 134

Desplazar los bits una posicin a la izquierda es como multiplicar por dos:

0110 0010 = 98

1^0 = 1, 0^0 = 0

La suma lgica exclusiva devuelve un 1 cuando los dos bits son distintos: 1^1 = 0,

1, 0+0 = 0
0110 0011 = 99

Despus hacemos su suma lgica, sumando cada bit, de modo que 1+1 = 1, 1+0 =

Revisin 0.99zz Pgina 358

LUNES = 0, MARTES = 1, MIERCOLES = 2, JUEVES = 3, VIERNES = 4,


SABADO = 5, DOMINGO = 6

modo que en nuestro caso valen:

La primera constante valdr 0, y las dems irn aumentando de una en una, de

para recordar "de un vistazo" que son constantes, no variables)

(Al igual que las constantes de cualquier otro tipo, se puede escribir en maysculas

enum diasSemana { LUNES, MARTES, MIERCOLES, JUEVES, VIERNES, SABADO,


DOMINGO };

consecutivos. Se trata de enumerarlos:

Hay una forma alternativa de hacerlo, especialmente til si son nmeros enteros

const int LUNES = 0, MARTES = 1,


MIERCOLES = 2, JUEVES = 3,
VIERNES = 4, SABADO = 5,
DOMINGO = 6;

ahora estamos dando los valores uno por uno, as:

Cuando tenemos varias constantes, cuyos valores son nmeros enteros, hasta

0000 0001 = 1

13.3. Enumeraciones

que 1*1 = 1, 1*0 = 0, 0*0 = 0

pequeo, como 3, por ejemplo) y vuelque el resultado a un nuevo fichero.

haciendo un XOR de los caracteres que la forman con un cierto dato prefijado (y

(13.2.1) Crea un programa que lea un fichero de texto, encripte cada lnea

Ejercicios propuestos

x <<= 2;
x &= 2;
x |= 2;
...

tambin podremos hacer cosas como

x += 2;

Un ltimo comentario: igual que hacamos operaciones abreviadas como

contrario, puede servir para obligar a que ciertos bits sean 1...

que se puede usar para comprobar mscaras de red); la suma lgica, por el

mensajes; el producto lgico nos permite obligar a que ciertos bits sean 0 (algo

dos; la suma lgica exclusiva (xor) es un mtodo rpido y sencillo de cifrar

Introduccin a la programacin con C#, por Nacho Cabanes

Despus hacemos el producto lgico de A y B, multiplicando cada bit, de modo

1011 1100 = -68

En primer lugar complementamos "a", cambiando los ceros por unos:

67 = 0100 0011
33 = 0010 0001

nmeros y seguir las operaciones paso a paso:

Para comprobar que es correcto, podemos convertir al sistema binario esos dos

La variable a vale 67
y b vale 33
El complemento de a es: -68
El producto lgico de a y b es: 1
Su suma lgica es: 99
Su suma lgica exclusiva es: 98
Desplacemos a a la izquierda: 134
Desplacemos a a la derecha: 33

El resultado es:

Introduccin a la programacin con C#, por Nacho Cabanes

sintaxis es ligeramente distinta: en C# es necesario indicar el nombre de la


enumeracin cada vez que se usen sus valores (como en diasSemana.MIERCOLES),

cualquiera de las contantes, y las siguientes irn aumentando de uno en uno. Por

ejemplo, si escribimos

MIERCOLES);

Revisin 0.99zz Pgina 359

ConsoleColor.Red) y las teclas de la consola (como ConsoleKey.Escape).

Tambin son enumeraciones los cdigos de color de la consola (como

fichero (FileMode) es una enumeracin, por lo que escribimos FileMode.Open.

realmente que lo estbamos haciendo. Por ejemplo, el modo de apertura de un

Nosotros hemos usado enumeraciones muchas veces hasta ahora, sin saber

En la enumeracion, el mircoles tiene el valor: MIERCOLES que equivale a: 2


En las constantes, el mircoles tiene el valor: 2

y su resultado ser:

{0}",

Console.WriteLine("En las constantes, el mircoles tiene el valor:

const int LUNES = 0, MARTES = 1, MIERCOLES = 2, JUEVES = 3,


VIERNES = 4, SABADO = 5, DOMINGO = 6;

public static void Main()


{
Console.Write("En la enumeracion, el mircoles tiene el valor: {0} ",
diasSemana.MIERCOLES);
Console.WriteLine("que equivale a: {0}",
(int) diasSemana.MIERCOLES);

enum diasSemana { LUNES, MARTES, MIERCOLES, JUEVES, VIERNES,


SABADO, DOMINGO };

public class Enumeraciones


{

using System;

// Ejemplo_13_03a.cs
// Ejemplo de enumeraciones
// Introduccin a C#, por Nacho Cabanes

Un ejemplo bsico podra ser

LUNES = 1, MARTES = 2, MIERCOLES = 3, JUEVES = 6, VIERNES = 7,


SABADO = 10, DOMINGO = 11

Ahora sus valores son:

// Oculto mediante una "propiedad"


public int Anchura

// Otro atributo convencional, privado


private int anchura = 0;

// -------------------------

// Y lo fijamos con un "set"


public void SetAltura(int nuevoValor)
{
altura = nuevoValor;
}

// Para ocultar detalles, leemos su valor con un "get"


public int GetAltura()
{
return altura;
}

// Un atributo convencional, privado


private int altura = 0;

public class EjemploPropiedades


{
// -------------------------

using System;

// Ejemplo_13_04a.cs
// Ejemplo de propiedades (1)
// Introduccin a C#, por Nacho Cabanes

abreviada de escribir sus mtodos "get" y "set":

Revisin 0.99zz Pgina 360

mismo efecto, empleando las llamadas "propiedades", que tienen una forma

(para cambiarlo). En el caso de C#, existe una forma alternativa de conseguir el

privados, y se acceda a ellos a travs de mtodos "get" (para leer su valor) y "set"

Hasta ahora estbamos siguiendo la poltica de que los atributos de una clase sean

13.4. Propiedades

12.2.2) en la que las opciones sean parte de una enumeracin.

(13.3.1) Crea una versin de la base de datos de ficheros con colores (ejercicio

Ejercicios propuestos

mientras que en C se usa slo el valor (MIERCOLES).

Nota: las enumeraciones existen tambin en otros lenguajes como C y C++, pero la

Si queremos que los valores no sean exactamente estos, podemos dar valor a

enum diasSemana { LUNES=1, MARTES, MIERCOLES, JUEVES=6, VIERNES,


SABADO=10, DOMINGO };

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

anchura = value;

return anchura;

ejemplo.Anchura = 6;
Console.WriteLine("La anchura es {0}",
ejemplo.Anchura );

ejemplo.SetAltura(5);
Console.WriteLine("La altura es {0}",
ejemplo.GetAltura() );

// El "Main" de prueba
public static void Main()
{
EjemploPropiedades ejemplo
= new EjemploPropiedades();

quiere decir "un carcter entre la a y la z".

que indique la expresin "[^0-9]".

Revisin 0.99zz Pgina 361

que si se usa un simple "Contains". Por ejemplo, podemos comprobar con una

Las "expresiones regulares" permiten hacer comparaciones mucho ms abstractas

13.5. Introduccin a las expresiones regulares.

el "nombre" sea una propiedad, con sus correspondientes "get" y "set".

public static bool EsNumeroEntero2(String cadena)


{
Regex patronNumerico = new Regex(@"\A[0-9]*\z");
return patronNumerico.IsMatch(cadena);
}

class PruebaExprRegulares
{
public static bool EsNumeroEntero(String cadena)
{
Regex patronNumerico = new Regex("[^0-9]");
return !patronNumerico.IsMatch(cadena);
}

Ejercicios propuestos

(13.4.1) Crea una nueva versin del ejercicio de la clase Persona (6.7.1), en la que

using System;
using System.Text.RegularExpressions;

// Ejemplo_13_05a.cs
// Ejemplo de expresiones regulares
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 362

no sea del 0 al 9", que se podra conseguir devolviendo lo contrario de lo

plantear la expresin regular al contrario: "no es vlido si contiene algo que

cadena", que se representara como "\A[0-9]+\z". Una alternativa es

debera ser "inicio de cadena, cualquier secuencia de cifras, final de

queremos que slo tenga cifras numricas, nuestra expresin regular

nmeros aunque tuviera otros smbolos al principio y al final. Por eso, si

como [0-9]+ aceptara cualquier cadena que contuviera una secuencia de

Aun as, esa expresin puede dar resultados inesperados: un secuencia

ms caracteres entre la a y la z".

ms veces", ? para "0 o una vez", como en [a-z]+, que quiere decir "uno o

Podemos aadir modificadores: * para indicar "0 o ms veces", + para "1 o

El ejemplo podra ser:

Uno de los patrones ms habituales es indicar un rango de datos: [a-z]

coincide con un cierto patrn.

Tenemos un mtodo IsMatch, que devuelve "true" si una cadena de texto

x
x

Usaremos el tipo de datos "RegEx" (expresin regular).

cadena es numrica, alfabtica o alfanumrica. Las ideas bsicas son:

Vamos a ver solamente un ejemplo con un caso habitual: comprobar si una

por mayscula y el resto son minsculas, etc.

orden breve si todos los caracteres de una cadena son numricos, o si empieza

Introduccin a la programacin con C#, por Nacho Cabanes

escritura, definiendo su "set" pero no su "get".

el programa no compilara. De igual modo, se podra crear una propiedad de slo

propiedad de slo lectura, no podremos hacer cosas como "Anchura = 4", porque

Una curiosidad: si una propiedad tiene un "get", pero no un "set", ser una

ventana en consola, etc.

("Length") y la posicin actual ("Position") en un fichero, el ttulo ("Title") de una

anteriormente, sin saberlo: la longitud ("Length") de una cadena, el tamao

Al igual que ocurra con las enumeraciones, ya hemos usado "propiedades"

set
{

get
{

// -------------------------

Introduccin a la programacin con C#, por Nacho Cabanes

if (EsAlfabetico("hola"))
Revisin 0.99zz Pgina 363

if (EsNumeroConDecimales("23,45,67"))
Console.WriteLine("23,45,67 es un nmero con decimales");
else
Console.WriteLine("23,45,67 NO es un nmero con decimales");

if (EsNumeroConDecimales("23,45"))
Console.WriteLine("23,45 es un nmero con decimales");
else
Console.WriteLine("23,45 NO es un nmero con decimales");

if (EsNumeroEntero2("23,45"))
Console.WriteLine("23,45 es entero (forma 2)");
else
Console.WriteLine("23,45 NO es entero (forma 2)");

if (EsNumeroEntero("23,45"))
Console.WriteLine("23,45 es un nmero entero");
else
Console.WriteLine("23,45 NO es un nmero entero");

if (EsNumeroEntero2("1942"))
Console.WriteLine("1942 es entero (forma 2)");
else
Console.WriteLine("1942 NO es entero (forma 2)");

if (EsNumeroEntero("1942"))
Console.WriteLine("1942 es un nmero entero");
else
Console.WriteLine("1942 NO es un nmero entero");

static void Main(string[] args)


{
if (EsNumeroEntero("hola"))
Console.WriteLine("hola es nmero entero");
else
Console.WriteLine("hola NO es nmero entero");

public static bool EsAlfanumerico(String cadena)


{
Regex patronAlfanumerico = new Regex("[^a-zA-Z0-9]");
return !patronAlfanumerico.IsMatch(cadena);
}

public static bool EsAlfabetico(String cadena)


{
Regex patronAlfabetico = new Regex("[^a-zA-Z]");
return !patronAlfabetico.IsMatch(cadena);
}

public static bool EsNumeroConDecimales(String cadena)


{
Regex patronNumericoConDecimales =
new Regex(@"\A[0-9]*,?[0-9]+\z");
return patronNumericoConDecimales.IsMatch(cadena);
}

Introduccin a la programacin con C#, por Nacho Cabanes

ejemplo:
Revisin 0.99zz Pgina 364

contador, pero esto no tiene por qu ser siempre as. Vamos a verlo con un

Cuando vimos la orden "for", siempre usbamos una nica variable como

13.6. El operador coma

parece un correo electrnico vlido.

(13.5.2) Crea una funcin que diga si una cadena que se le pase como parmetro

postal vlido.

numricas): devolver true si la cadena recibida como parmetro es un cdigo

(13.5.1) Crea una funcin que valide cdigos postales espaoles (5 cifras

Ejercicios propuestos

http://msdn.microsoft.com/eses/library/system.text.regularexpressions.regex(VS.80).aspx

MSDN (Microsoft Developer Network):

extenso, puede ser recomendable ampliar informacin usando la pgina web de

por otras. Como ver muchos ms detalles podra hacer el texto demasiado

sino que tambin permite otras operaciones, como reemplazar unas expresiones

llegar a ser difcil de seguir. Por otra parte, el manejo en C# no se limita a buscar,

Las expresiones regulares son algo complejo. Por una parte, su sintaxis puede

hola NO es nmero entero


1942 es un nmero entero
1942 es entero (forma 2)
23,45 NO es un nmero entero
23,45 NO es entero (forma 2)
23,45 es un nmero con decimales
23,45,67 NO es un nmero con decimales
hola es alfabetico
hola1 es alfanumerico

Su salida es:

Console.WriteLine("hola NO es alfabetico");

Console.
.WriteLine("hola es alfabetico");

if (EsAlfanumerico("hola1"))
Console.WriteLine("hola1 es alfanumerico");
else
Console.WriteLine("hola1 NO es alfanumerico");

else

Introduccin a la programacin con C#, por Nacho Cabanes

0
1
2
3
4
5

y
y
y
y
y
y

j
j
j
j
j
j

vale
vale
vale
vale
vale
vale

1
3
5
7
9
11

// Ejemplo_13_07a.cs
// Ejemplo de uso de "var"
// Introduccin a C#, por Nacho Cabanes
Revisin 0.99zz Pgina 365

contexto. Para ello, se utiliza la palabra "var", como en este ejemplo:

tipo de una variable, sino que sea el propio compilador el que lo deduzca del

A partir de Visual C# 3.0, existe la posibilidad de no declarar de forma explcita el

13.7. Variables con tipo implicito

for (i=0, j=1; i<=5, j<=30; i++, j+=2)

operaciones booleanas):

condicin debe ser un "boolean", y la coma no es un operador vlido para

hasta que se cumplen las dos condiciones (algo que no es vlido en C#, ya que la

terminacin tambin podra tener una coma, y entonces no se sale del bucle "for"

Nota: En el lenguaje C se puede "rizar el rizo" todava un poco ms: la condicin de

vale
vale
vale
vale
vale
vale

Revisin 0.99zz Pgina 366

primero el conjunto de datos, luego la condicin y luego la variable a devolver).

usando una sintaxis que recuerda a la de SQL (aunque se escribe "casi al revs":

Studio 2008, que nos permite hacer consultas a cualquier coleccin de datos

posibilidad aadida en la plataforma .Net versin 3.5, y accesible a partir de Visual

LINQ (Language-integrated Query, consulta integrada en el lenguaje) es una

13.8. Contacto con LINQ

Tanto el fichero como la lnea se deben declarar con "var".

(13.7.2) Crea un programa que muestre la primera lnea de un fichero de texto.

variable definida con "var".

muestre su equivalencia en millas. El valor de conversin debe estar en una

(13.7.1) Crea un programa que pida al usuario una cantidad de kilmetros y

Ejercicios propuestos

detalles), lo podramos conseguir con "GetType()".

que no es habitual, porque si se usa "var" es para despreocuparnos de esos

Como se ve en este ejemplo, si necesitramos saber de qu tipo es una variable (lo

var texto = "Hola";


Console.WriteLine("texto vale {0} y es de tipo {1}",
texto, texto.GetType());

i
i
i
i
i
i

Al final de cada paso, i aumenta en una unidad, y j en dos unidades.

x
}

Se repetir mientras que i <= 5 y j <= 30.

var pi = 3.1416;
Console.WriteLine("pi vale {0} y es de tipo {1}",
pi, pi.GetType());

var letra = 'a';


Console.WriteLine("letra vale {0} y es de tipo {1}",
letra, letra.GetType());

var condicion = 5 == 7;
Console.WriteLine("condicion vale {0} y es de tipo {1}",
condicion, condicion.GetType());

public class UsoVar


{
public static void Main()
{
var n = 5;
Console.WriteLine("n vale {0} y es de tipo {1}",
n, n.GetType());

using System;

Introduccin a la programacin con C#, por Nacho Cabanes

El resultado de este programa es:

Los valores iniciales son i=0, j=1.

Vamos a ver qu hace este "for":

for (i=0, j=1; i<=5 && j<=30; i++, j+=2)


Console.WriteLine("i vale {0} y j vale {1}", i, j);

public class OperadorComa


{
public static void Main()
{
int i, j;

using System;

// Ejemplo_13_06a.cs
// Operador coma
// Introduccin a C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

foreach (string n in resultado)


Console.Write("{0} ", n);
Console.WriteLine();

var resultado =
from nombre in nombres
orderby nombre
select nombre;

Revisin 0.99zz Pgina 367

public class EjemploLinq2


{
public static void Main()
{
List<string> nombres = new List<string>
{ "pan", "carne", "queso", "manzana", "natillas" };

using System;
using System.Linq;
using System.Collections.Generic;

// Ejemplo_13_08b.cs
// Segundo ejemplo de LINQ
// Introduccin a C#, por Nacho Cabanes

obtenerla ordenada, as:

Tambin podemos recorrer la informacin de una lista de cadenas de texto y

foreach(int i in result)
Console.Write("{0} ", i);
Console.WriteLine();

var result =
from n in datos
where n > 10
select n;

El preprocesador.
Entornos grficos (Windows Forms, WPF).
Uso en servidores Web (ASP.Net).

x
x
x

Funciones lambda.

Delegados (delegate).

Revisin 0.99zz Pgina 368

en MSDN o en cualquier otra fuente de informacin. Por ejemplo:

Mencionaremos algunos, por si alguien quiere ampliar informacin por su cuenta

En C# (y la plataforma "punto net") hay ms que lo que hemos visto aqu.

13.9. Lo que no vamos a ver...

array o no, utilizando LINQ.

debe introducir una palabra, y el programa responder si es palabra est en el

(13.8.2) Crea un programa que prepare un array de palabras. Luego, el usuario

LINQ.

en una lista y luego muestre todos los que sean positivos, ordenados, empleando

(13.8.1) Crea un programa que pida al usuario varios nmeros enteros, los guarde

Ejercicios propuestos

using System;
using System.Linq;

public class EjemploLinq1


{
public static void Main()
{
int[] datos = { 20, 5, 7, 4, 25, 18, 5, 8, 21, 2 };

https://msdn.microsoft.com/es-es/library/bb397926.aspx

quieres saber ms, puedes acudir a la propia referencia oficial en lnea, en MSDN:

Profundizar en LINQ es algo que queda fuera del propsito de este texto. Si

Introduccin a la programacin con C#, por Nacho Cabanes

// Ejemplo_13_08a.cs
// Ejemplo bsico de LINQ
// Introduccin a C#, por Nacho Cabanes

mayor que 10 con:

Por ejemplo, podemos obtener los nmeros enteros de un array cuyo valor es

Introduccin a la programacin con C#, por Nacho Cabanes

"Depurar". En l aparece la opcin "Paso a paso por instrucciones" (al que


corresponde la tecla F11):

La depuracin es el anlisis de un programa para descubrir fallos. El nombre en

ingls es "debug", porque esos fallos de programacin reciben el nombre de

a = 5;
b = a + 2;
b -= 3;
c = -3;
c *= 2;
++c;
a *= b;

namespace EjemploDeOperaciones
{
class Program
{
static void Main(string[] args)
{
int a, b, c;

using System;

Esto se convertira en un programa como

a==5; b=a+2; b-=3; c=-3; c*=2; ++c; a*=b;

ejercicio al final del apartado 2.1:

Revisin 0.99zz Pgina 369

Vamos a tomar como ejemplo la secuencia de operaciones que se propuso como

14.2. Depurando desde Visual Studio

con versiones posteriores de Visual Studio deberan ser mnimas.

Veremos como ejemplo el caso de Visual Studio 2008 Express, pero las diferencias

tambin nos dejan ver los valores de las variables.

avanzar paso a paso para ver cmo avanza realmente nuestro programa, y

debera, se usan unas herramientas llamadas "depuradores". Estos nos permiten

Para eliminar esos fallos que hacen que un programa no se comporte como

"bugs" (bichos).

Para avanzar paso a paso y ver los valores de las variables, entramos al men

14.1. Conceptos bsicos sobre depuracin

programa:

Revisin 0.99zz Pgina 370

con la lista de variables, y un nuevo cursor amarillo, que se queda al principio del

Si escogemos esa opcin del men o pulsamos F11, aparece una ventana inferior

pantalla, ser el propio entorno de desarrollo de Visual Studio el que nos muestre
los valores de las variables.

Ni siquiera necesitamos rdenes "WriteLine", porque no mostraremos nada en

Introduccin a la programacin con C#, por Nacho Cabanes

14. Depuracin, prueba y documentacin de


programas

Introduccin a la programacin con C#, por Nacho Cabanes

con fondo amarillo la siguiente lnea que se analizar:

Revisin 0.99zz Pgina 371

cambio ms reciente se ver en color rojo), y se vuelve a quedar parado, realzando

lnea de programa, muestra los valores de las variables correspondientes (el

correspondiente de la barra de herramientas), el depurador analiza una nueva

Cada vez que pulsemos nuevamente F11 (o vayamos al men, o al botn

Introduccin a la programacin con C#, por Nacho Cabanes

los esperados.

Revisin 0.99zz Pgina 372

de un programa, se lanza la batera de pruebas y se verifica que los resultados son

que todo se comporta como debera. As, antes de dar por definitiva una versin

creando una "batera de pruebas" que permita comprobar de forma automtica

nuevos. Por eso, una forma habitual de garantizar la calidad de los programas es

Es frecuente que la correccin de ciertos errores introduzca a su vez errores

14.3. Prueba de programas

depurando paso a paso como antes.

punto, y ser entonces cuando se interrumpa. A partir de ah, podemos seguir

Si ahora iniciamos la depuracin del programa, saltar sin detenerse hasta ese

programa, junto a esa lnea):

como alternativa, podemos hacer clic con el ratn en el margen izquierdo del

puntos de ruptura" (tecla F9). Aparecer una marca granate en la lnea actual

de conseguirlo es escoger otra de las opciones del men de depuracin: "Alternar

se encuentra el error, y slo queramos depurar una zona de programa. La forma

totalmente habitual. Es ms frecuente que supongamos en qu zona del programa

Aqu hemos avanzado desde el principio del programa, pero eso no es algo

Introduccin a la programacin con C#, por Nacho Cabanes

x2 = 0 x1 = 0, x2 = No existe (solucin nica)

x2 -1 = 0 x1 = 1, x2 = -1
Revisin 0.99zz Pgina 373

Y la batera de pruebas podra basarse en varios casos conocidos. Por ejemplo:

que se obtenga en un caso habitual, como -9999.

Es decir, si alguna solucin no existe, se devuelve un valor falso, que no sea fcil

if (discriminante < 0)
{
x1 = -9999;
x2 = -9999;
}
else if (discriminante == 0)
{
x1 = - b / (2*a);
x2 = -9999;
}
else
{
x1 = (float) ((- b + Math.Sqrt(discriminante))/ 2*a);
x2 = (float) ((- b - Math.Sqrt(discriminante))/ 2*a);
}

discriminante = b*b - 4*a*c;

float discriminante;

public static void Resolver(


float a, float b, float c,
out float x1, out float x2)
{

public class SegundoGrado {

Un programa (incorrecto) para resolverlo podra ser:

La frmula que emplearemos es:

Introduccin a la programacin con C#, por Nacho Cabanes

Console.Write("Probando x2 - 1 = 0 ...");
ecuacion.Resolver((float)1, (float) 0, (float) -1,
out soluc1, out soluc2);
if ((soluc1 == 1) && (soluc2 == -1))
Console.WriteLine("OK");

SegundoGrado ecuacion = new SegundoGrado();

Revisin 0.99zz Pgina 374

Console.WriteLine("Probando ecuaciones de segundo grado");

public class PruebaSegundoGrado


{
public static void Main()
{
float soluc1, soluc2;

if (discriminante < 0)
{
x1 = -9999;
x2 = -9999;
}
else if (discriminante == 0)
{
x1 = - b / (2*a);
x2 = -9999;
}
else
{
x1 = (float) ((- b + Math.Sqrt(discriminante))/ 2*a);
x2 = (float) ((- b - Math.Sqrt(discriminante))/ 2*a);
}

discriminante = b*b - 4*a*c;

float discriminante;

public void Resolver(


float a, float b, float c,
out float x1, out float x2)
{

public class SegundoGrado


{

using System;

// Ejemplo_14_03a.cs
// Ejemplo de realizacin de pruebas
// Introduccin a C#, por Nacho Cabanes

Estos casos de prueba se podran convertir en un programa como:

2x2 -2 = 0 x1 = 1, x2 = -1

resultados de operaciones conocidas. Vamos a ver un ejemplo, para un programa

que calcule las soluciones de una ecuacin de segundo grado.

x2 -3x = 0 x1 = 3, x2 = 0

Una forma sencilla de crear una batera de pruebas es comprobando los

Introduccin a la programacin con C#, por Nacho Cabanes

Console.Write("Probando 2x2 - 2 = 0 ...");


ecuacion.Resolver((float)2, (float)0, (float)-2,
out soluc1, out soluc2);
if ((soluc1 == 1) && (soluc2 == -1))
Console.WriteLine("OK");
else
Console.WriteLine("Falla");

Console.Write("Probando x2 -3x = 0 ...");


ecuacion.Resolver((float)1, (float)-3, (float)0,
out soluc1, out soluc2);
if ((soluc1 == 3) && (soluc2 == 0))
Console.WriteLine("OK");
else
Console.WriteLine("Falla");

ecuaciones de segundo grado


x2 - 1 = 0 ...OK
x2 = 0 ...OK
x2 -3x = 0 ...OK
2x2 - 2 = 0 ...Falla

// Ejemplo_14_03b.cs
// Segundo ejemplo de realizacin de pruebas, con Assert
// Introduccin a C#, por Nacho Cabanes

System.Diagnostics, de modo que el programa quedara as:

Revisin 0.99zz Pgina 375

llamada "Assert". En C#, se trata de Debug.Assert", que es parte de

ya incorporadas como parte del lenguaje, normalmente en forma de una funcin

La mayora de lenguajes modernos tienen funcionalidades de creacin de pruebas

entre (2*a), de modo que estamos diviendo entre 2 y luego multiplicando por a.

automatizadas. En este caso, el problema es que falta un parntesis, para dividir

que da nuestro programa, corregiramos el fallo y volveramos a lanzar las pruebas

Vemos que en uno de los casos, la solucin no es correcta. Revisaramos los pasos

Probando
Probando
Probando
Probando
Probando

El resultado de este programa es:

Console.WriteLine("Falla");

Console.Write("Probando x2 = 0 ...");
ecuacion.Resolver((float)1, (float)0, (float)0,
out soluc1, out soluc2);
if ((soluc1 == 0) && (soluc2 == -9999))
Console.WriteLine("OK");
else
Console.WriteLine("Falla");

else

Introduccin a la programacin con C#, por Nacho Cabanes

Console.Write("Probando 2x2 - 2 = 0 ...");

Console.Write("Probando x2 -3x = 0 ...");


ecuacion.Resolver((float)1, (float)-3, (float)0,
out soluc1, out soluc2);
Debug.Assert((soluc1 == 3) && (soluc2 == 0));

Console.Write("Probando x2 = 0 ...");
ecuacion.Resolver((float)1, (float)0, (float)0,
out soluc1, out soluc2);
Debug.Assert((soluc1 == 0) && (soluc2 == -9999));

Console.Write("Probando x2 - 1 = 0 ...");
ecuacion.Resolver((float)1, (float) 0, (float) -1,
out soluc1, out soluc2);
Debug.Assert((soluc1 == 1) && (soluc2 == -1));

SegundoGrado ecuacion = new SegundoGrado();

Revisin 0.99zz Pgina 376

Console.WriteLine("Probando ecuaciones de segundo grado");

public class PruebaSegundoGrado


{
public static void Main()
{
float soluc1, soluc2;

if (discriminante < 0)
{
x1 = -9999;
x2 = -9999;
}
else if (discriminante == 0)
{
x1 = - b / (2*a);
x2 = -9999;
}
else
{
x1 = (float) ((- b + Math.Sqrt(discriminante))/ 2*a);
x2 = (float) ((- b - Math.Sqrt(discriminante))/ 2*a);
}

discriminante = b*b - 4*a*c;

float discriminante;

public void Resolver(


float a, float b, float c,
out float x1, out float x2)
{

public class SegundoGrado


{

using System;
using System.Diagnostics;

Introduccin a la programacin con C#, por Nacho Cabanes

Diagramas de anlisis, como los diagramas de casos de uso UML, para

nuestro programa y cmo interactuarn.

Revisin 0.99zz Pgina 377

apartado 6.4, para mostrar qu tipos de objetos formarn realmente

Diagramas de diseo, como los diagramas de clases UML que vimos en el

plasmar de una forma grfica lo que un usuario podr hacer con el sistema.

Especificaciones de requisitos, que reflejen lo que el programa debe hacer.

antes de comenzar a teclear:

La mayor parte de la documentacin de un programa "serio" se debe realizar

14.4. Documentacin bsica de programas

principal, para evitar que se omitan cosas que se "den por supuestas".

pruebas las realice un equipo de desarrollo distinto al que ha realizado el proyecto

conocimiento del problema. Algunos expertos recomiendan que, si es posible, las

Para crear las bateras de pruebas, lo que ms ayuda es la experiencia y el

detectado.

encuentren problemas: puede que aun as exista un fallo que no hayamos

encontrar problemas, pero no permiten asegurar nada en caso de que no se

Por tanto, las pruebas slo permiten asegurar que el programa falla en caso de

descubierto el fallo del programa.

batera de pruebas anterior solo contuviera las tres primeras pruebas, no habra

programa sea correcto, sino slo que no falla en ciertos casos. Por ejemplo, si la

comprobar que todo es correcto. El inconveniente es que NO GARANTIZA que el

un programa, por lo que se puede aplicar tras cada pocos cambios para

La ventaja de crear bateras de pruebas es que es una forma muy rpida de probar

Depurar o Continuar ignorando el error.

con el texto "Error de asercin" al llegar a la lnea 67, con botones para Salir,

A lanzar este programa, se detendr la ejecucin y mostrar una ventana de aviso

ecuacion.
.Resolver((float)2, (float)0, (float)-2,
out soluc1, out soluc2);
Debug.Assert((soluc1 == 1) && (soluc2 == -1));

Introduccin a la programacin con C#, por Nacho Cabanes

{
...

foreach (Record record in records)

// son correctos

// Comprobamos si todos los datos

lnea en blanco para separar bloques:

Revisin 0.99zz Pgina 378

realicen una tarea simple, e introducir un comentario al principio adems de una

Adems, es recomendable dividir un bloque de cdigo extenso en "prrafos" que

2. Usa prrafos comentados

(Lo importante es ceirse a unas normas y aplicarlas siempre).

parmetros y resultados obtenidos

Por cada mtodo, una descripcin de su objeto y funcionalidades, as como de los

modificacin

En cada clase, incluir una breve descripcin, su autor y fecha de ltima

criterio uniforme y distinto para cada nivel, por ejemplo:

Comenta los distintos bloques de los que se compone tu cdigo, aplicando un

1. Comenta a varios niveles

cdigo.html

http://www.variablenotfound.com/2007/12/13-consejos-para-comentar-tu-

artculo original se puede encontrar en:

resumida) una de Jos M. Aguilar, recopilada en su blog "Variable not found". El

Existen buenas recopilaciones de consejos en Internet. Yo voy a incluir (algo

14.4.1. Consejos para comentar el cdigo

forma casi automtica.

como a partir de estos comentarios se puede generar documentacin adicional de

suelen recomendar para los comentarios en los programas, y tambin veremos

Por eso, este apartado se va a centrar en algunas de las pautas que los expertos

problema: los comentarios que aclaren todo aquello que no sea obvio.

Aun as, hay un tipo de documentacin que s debe estar presente en cualquier

los que no es necesaria una gran planificacin.

introduccin a la programacin se realizan programas de pequeo tamao, para

Casi todos esos diagramas caen fuera del alcance de este texto: en una

Introduccin a la programacin con C#, por Nacho Cabanes

// Mscara de bits TCP

// TODO: implementar los clculos

Ve introduciendo los comentarios conforme vas codificando. No lo dejes para el

// Generar factura

En palabras del genial Phil Haack, "tan pronto como una lnea de cdigo sale de la
pantalla y volvemos a ella, estamos en modo mantenimiento de la misma"

entendieran no programadores. Otros, en cambio, piensan que debe servir de

ayuda para desarrolladores exclusivamente. En cualquier caso, lo que importa es

8. Para los comentarios internos, usa marcas especiales

Revisin 0.99zz Pgina 379

Revisin 0.99zz Pgina 380

modificado no se actualizan tambin los comentarios. Ambos deben evolucionar

De nada sirve comentar correctamente una porcin de cdigo si en cuanto ste es

11. Actualiza los comentarios a la vez que el cdigo

desarrollador que en el futuro sea designado para corregir o mantener tu cdigo.

Hay quien opina que los comentarios deberan ser escritos para que los

que siempre sea de la misma forma, orientados al mismo destinatario.

es un regalo que dejas para la posteridad del que slo obtendr beneficios el

A la hora de comentar no pienses slo en mantenimiento posterior, ni creas que

10. Comenta como si fuera para t mismo. De hecho, lo es.

7. Utiliza un estilo consistente

florituras, ni chistes, ni poesas, ni chascarrillos.

transmitir la idea. Nada de diseos realizados a base de caracteres ASCII, ni

No comentes si no es necesario, no escribas nada ms que lo que necesites para

// Enviar la orden a almacn

Relacionado e igualmente importante: cuida la ortografa.

6. No pierdas el tiempo

// Comprobar que hay material


// Comprobar que el cliente es vlido

producido por la pattica implementacin del inepto desarrollador inicial".

public void ProcesaPedido()


{

introducido un nmero negativo", o "este parche corrige el efecto colateral

codificado stos queden como comentarios para la posteridad. Un ejemplo:

referencia para saber qu es lo que hay que hacer y, segundo, que una vez

escribirse antes de codificarlo, de forma que, en primer lugar, sirvan como

Hay incluso quien opina que los comentarios que describen un bloque deberan

Evita comentarios del tipo "ahora compruebo que el estpido usuario no haya

5. S correcto

...

contador = 0; // ... ponemos el contador a cero

// Si a vale cinco, ...

proyecto va muy retrasado"... son simplemente excusas.

Debemos evitar comentarios absurdos como:

if (a == 5)

hacerlo. Olvida las posturas "no tengo tiempo de comentar, voy muy apurado", "el

4. No insultes la inteligencia del lector

final, puesto que entonces te costar ms del doble de tiempo, si es que llegas a

9. Comenta mientras programas

return 0;

asegurarse de que esto es lo que hace el IDE correspondiente.

preferencias personales del desarrollador. Lo mejor es usar espacios simples o

lo sustituyen por un nmero determinado de espacios, que suelen variar segn las

Ojo a las tabulaciones. Hay editores de texto que usan el carcter ASCII (9) y otros,

const MASK = 0x1F;

const MAX_ITEMS = 10; // Nmero mximo de paquetes

int calcula(int x, int y)

implementar:

legible si estn alineados:

es el comentario TODO (to-do, por hacer), que describe funciones pendientes de

Si tenemos un bloque de lneas de cdigo, cada una con un comentario, ser ms

Y sobre todo cuando se trabaja en un equipo de programacin. El ejemplo tpico

Introduccin a la programacin con C#, por Nacho Cabanes

3. Tabula por igual los comentarios de lneas consecutivas

Introduccin a la programacin con C#, por Nacho Cabanes

de un fuente en C#:

Revisin 0.99zz Pgina 381

Por ejemplo, la herramienta (gratuita) Doxygen genera pginas como sta a partir

varios ficheros XML.

Esta documentacin tpicamente ser una serie pginas HTML enlazadas, o bien

de forma automtica cierta documentacin del programa.

adicional que puede resultar muy til: usar comentarios que nos ayuden a crear

Pero en algunos lenguajes modernos, como Java y C#, existe una posibilidad

de lnea (a partir de una doble barra // ).

Conocemos los comentarios de bloque (/* hasta */) y los comentarios hasta final

14.4.2. Generacin de documentacin a partir del cdigo


fuente.

trabajo en equipo.

y la creacin cdigo inteligible nos favorecer a todos, sobre todo en contextos de

nuestro cdigo comentado, la generalizacin y racionalizacin de los comentarios

Aunque nosotros mismos nos beneficiamos inmediatamente de las bondades de

13. Difunde estas prcticas entre tus colegas

Console.WriteLine("Resultado: " +
new Calculator()
.Set(0)
.Add(10)
.Multiply(2)
.Substract(4)
.Get()
);

explicativos adicionales:

que una codificacin limpia puede hacer innecesaria la introduccin de textos

programadores a los que no les gusta comentar su cdigo ;-), es totalmente cierto

hable por s mismo. Aunque se sospecha que este movimiento est liderado por

Es uno de los principios bsicos para muchos desarrolladores: deja que tu cdigo

12. La regla de oro del cdigo legible

tenga que mantener el software, al darle pistas incorrectas.

paralelamente, o estaremos haciendo ms difcil la vida del desarrollador que

Introduccin a la programacin con C#, por Nacho Cabanes

(...)
Revisin 0.99zz Pgina 382

public class Personaje : ElemGrafico


{
/// Mueve el personaje a la derecha, si es posible (sin obstculos)
public void MoverDerecha()
{
(...)
}

/**
* Personaje: uno de los tipos de elementos graficos del juego
*
*
@see ElemGrafico Juego
*
@author 1-DAI 2008/09
*/

y de cada mtodo, as:

Lo habitual es que estos tipos de comentarios se utilicen al principio de cada clase

de documentacin hasta final de lnea (a partir de una triple barra /// ).

comentarios de documentacin en bloque (desde /** hasta */) y los comentarios

La forma de conseguirlo es empleando otros dos tipos de comentarios:

Introduccin a la programacin con C#, por Nacho Cabanes

"@see" se emplea en el apartado "Ver tambin", que incluye enlaces a la

Revisin 0.99zz Pgina 383

/// <summary>Mueve el personaje a la derecha, si es posible</summary>


/// <seealso cref="MoverIzquierda"/>
public void MoverDerecha()
{
(...)
}

usar etiquetas XML, as:

La forma que propone Microsoft de crear comentarios de documentacin en C# es

menos legible, pero se pueden emplear alternativas gratuitas como Doxygen.

herramienta estndar genera documentacin en formato XML, que puede resultar

JavaDoc, que es parte de la distribucin "oficial" del lenguaje. En cambio, en C#, la

En el lenguaje Java, documentacin como esta se puede crear con la herramienta

documentacin de otros ficheros relacionados.

"@author" se usa para el apartado "Autor" de la documentacin.

que no se tiene en cuenta al generar la documentacin.

pero est con el formato de un comentario "normal" (doble barra), por lo

La funcin "MoverDerecha" tambin tiene un comentario que la precede,

descripcin de dicha funcin miembro.

El comentario de documentacin del mtodo "Morir" se toma como

clase, aparece en el apartado "Descripcin detallada".

El comentario de documentacin inicial, creado antes del comienzo de la

l, podemos ver que:

As, comparando el fuente anterior y la documentacin que se genera a partir de

qu otras clases de nuestro programa estn relacionadas con la actual.

informacin sobre el valor que devuelve una funcin, o como @see, para detallar

reservadas" para poder afinar la documentacin, como @returns, que da

Adems, es habitual que tengamos a nuestra disposicin ciertas "palabras

/// Animacin cuando el personaje muere: ambulancia, etc.


public void Morir()
{
(...)
}

Introduccin a la programacin con C#, por Nacho Cabanes

<example>

<paramref>

<summary>

<exception>

<permission>

https://msdn.microsoft.com/en-us/library/5ast78ax.aspx

Revisin 0.99zz Pgina 384

Puedes leer ms sobre el uso que se sugiere para cada una de ellas aqu:

<typeparam> <include>* <remarks> <typeparamref> <list> <returns> <value>.

<seealso>

Las etiquetas que sugiere Microsoft son <c> <para> <see> <code> <param>

Introduccin a la programacin con C#, por Nacho Cabanes

Terabytes).
Revisin 0.99zz Pgina 385

memoria RAM entre 4 y 8 Gb, as como un disco duro de entre 500 y 2.000 Mb (2

correspondencia 1 Gb = 1024 Mb. As, es habitual que un equipo actual tenga una

medir en megabytes, sino en el mltiplo siguiente: en gigabytes, con la

Para unidades de almacenamiento de gran capacidad, su tamao no se suele

(CD-ROM) se pueden almacenar hasta 700 Mb.

ejemplo, en un diskette caban 1.44 Mb, y en un Compact Disc para ordenador

o Mb, que es 1000 Kb (en realidad 1024 Kb) o algo ms de un milln de bytes. Por

Cuando se manejan datos ms extensos, necesitamos otro mltiplo, el megabyte

letras) y 4 Kb.

Por otra parte, una pgina mecanografiada suele ocupar entre 2 K (cerca de 2000

mucho tiempo la memoria habitual en los primeros IBM PC y equipos similares.

Los Kb eran unidades tpicas para medir la memoria de ordenadores: 640 Kb fue

es 1 Kb = 1024 bytes.

(pronto veremos por qu), por lo que se usa 210 =1024. As, la equivalencia exacta

bytes, pero en los ordenadores conviene buscar por comodidad una potencia de 2

En teora, el prefijo kilo querra decir "mil", luego un kilobyte debera ser 1000

que se recurre a un mltiplo suyo, el kilobyte, que se suele abreviar Kb o K.

Un byte se queda corto a la hora de manejar textos o datos algo ms largos, con lo

formato de pgina, etc.

sobre los tipos de letra que se han utilizado, cursivas, negritas, mrgenes y

ordenador ocupe ms de 2000 bytes, porque se suele incluir informacin adicional

Eso s, suele ocurrir que realmente un texto de 2000 letras que se guarde en el

nuestro disco.

por 2000 letras, podemos esperar que ocupe unos 2000 bytes de espacio en

pensar que un byte es el equivalente a una letra. Si un cierto texto est formado

En informtica, la unidad bsica de informacin es el byte. En la prctica, podemos

Ap1.1. bytes, kilobytes, megabytes...

Apnd ice 1. Unid ades de medida y sistemas de


numeracin

Introduccin a la programacin con C#, por Nacho Cabanes

Byte

1024 Mb
1024 Gb

Gigabyte (Gb)
Terabyte (Tb)

00000000
00000001
00000010
00000011

elementos tomados de 8 en 8: VR2,8):

Revisin 0.99zz Pgina 386

bits de 8 en 8, tenemos 256 posibilidades distintas (variaciones con repeticin de 2

byte. Las matemticas elementales (combinatoria) nos dicen que si agrupamos los

dos valores: 0 1), por lo que se usa un conjunto de ellos, 8 bits, que forman un

Un bit es demasiado pequeo para un uso normal (recordemos: slo puede tener

que se representa como un 1 o un 0. Esta unidad recibe el nombre de bit.

una posicin de memoria est usada o no (totalmente llena o totalmente vaca), lo

se basa en componentes electrnicos, la unidad bsica de informacin ser que

forma que a l le resulte "cmoda" de manejar. Como la memoria del ordenador

Dentro del ordenador, la informacin se debe almacenar realmente de alguna

Ap1.2. Unidades de medida empleadas en informtica (2):


los bits

un DVD de 4,7 Gb? Y la de uno de 8,5 Gb?

(Ap1.1.4) A cuantos CD de 700 Mb equivale la capacidad de almacenamiento de

compact disc de 700 Mb, cuntos necesitaramos?

seguridad de un ordenador que tiene un disco duro de 6,4 Gb? Y si usamos

(Ap1.1.3) Cuntos diskettes de 1,44 Mb haran falta para hacer una copia de

de capacidad?

3.500 Kb, cuntas se podran guardar en un reproductor MP3 que tenga 256 Mb

(Ap1.1.2) Si suponemos que una cancin tpica en formato MP3 ocupa cerca de

tenga 32 Kb de capacidad?

(Ap1.1.1) Cuntas letras se podran almacenar en una agenda electrnica que

Ejercicios propuestos:

1024 Kb

Megabyte (Mb)
-

Aprox. media pgina mecanografiada

Kilobyte (K o Kb) 1024 bytes

0 a 255 (para guardar 1 letra)

Equivalencia Valores posibles

Unidad

Todo esto se puede resumir as:

Introduccin a la programacin con C#, por Nacho Cabanes

(binario)
(binario)
(binario)
(binario)

=
=
=
=

0
1
2
3

(decimal)
(decimal)
(decimal)
(decimal)

1110 (binario) = 254 (decimal)


1111 (binario) = 255 (decimal)

0000
0001
0010
0011

Revisin 0.99zz Pgina 387

modernos, como UTF-8, que comentaremos en el siguiente apartado.

son estndar para todos los ordenadores. Por eso, existen estndares ms

puede que no aparezcan correctamente, porque se les asignan nmeros que no

cambiarn, pero las letras internacionales (como la o las vocales con acentos)

llevamos a otro, las letras bsicas (A a la Z, 0 al 9 y algunos smbolos) no

son estndar. Eso quiere decir que si escribimos un texto en un ordenador y lo

Aun as, hay un inconveniente con el cdigo ASCII: slo los primeros 127 nmeros

apndice tendrs un extracto de este cdigo.

exactamente un byte (8 bits: 8 posiciones elementales de memoria). En el prximo

de almacenar la informacin en ordenadores, ya que cada letra ocupar

el 65, la "B", el 32, el "0" el 48, el "1" el 49, etc. As se tiene una forma muy cmoda

(realmente, con una secuencia de 8 bits): la "a" es el nmero 97, la "b" el 98, la "A"

informacin), que relaciona cada letra, nmero o smbolo con una cifra del 0 al 255

for Information Interchange, cdigo estndar americano para intercambio de

En la prctica, existe un cdigo estndar, el cdigo ASCII (American Standard Code

0000
0000
0000
0000
...
1111
1111

muy poco), en vez del sistema decimal, tenemos que:

al 255: si usamos el sistema binario de numeracin (que aprenderemos dentro de

Tambin existe una correspondencia entre cada grupo de bits y un nmero del 0

poco ms adelante).

y as sucesivamente (aunque existe un estndar distinto, que comentaremos un

la interpretaremos como una letra A, y la combinacin 00000011 como una letra B,

Por ejemplo, se podra decir que cada vez que encontremos la secuencia 00000010

numrica o algn otro smbolo.

que suficientes para almacenar una letra, o un signo de puntuacin, o una cifra

como un byte), nos encontramos con 256 posibilidades distintas, que ya son ms

ordenador, pero no para nosotros) los utilizamos en grupos de 8 (lo que se conoce

Por tanto, si en vez de tomar los bits de 1 en 1 (que resulta cmodo para el

00000100
...
11111110
11111111

Introduccin a la programacin con C#, por Nacho Cabanes

en enviar 630 Mbytes de datos?

Revisin 0.99zz Pgina 388

(Ap1.2.2) En una conexin de red de 100 Mbits/segundo, cunto tiempo tardara

(Ap1.2.1) Un nmero entero largo de 64 bits, cuntos bytes ocupa?

Ejercicios propuestos:

exacta es 1 K = 1024 bytes.

sino que se usa la potencia de 2 ms cercana: 210 =1024. Por eso, la equivalencia

no lo son, es lo que explica que el prefijo kilo no quiera decir "exactamente mil",

resulta ms fcil manejar los nmeros que son potencia de 2 que los nmeros que

Nota: Eso de que realmente el ordenador trabaja con ceros y unos, por lo que le

Introduccin a la programacin con C#, por Nacho Cabanes

000
010
020
030
040
050
060
070
080
090
100
110
120

0
NUL
LF
DC4
RS
(
2
<
F
P
Z
d
n
x

1
SOH
VT
NAK
US
)
3
=
G
Q
[
e
o
y

2
3
STX ETX
FF CR
SYN ETB
SP
!
*
+
4
5
>
?
H
I
R
S
\
]
f
g
p
q
z
{

4
EOT
SO
CAN
"
,
6
@
J
T
^
h
r
|

5
6
7
8
ENQ ACK BEL BS
SI DLE DC1 DC2
EM
SUB ESC FS
#
$
%
&
.
/
0
7
8
9
:
A
B
C
D
K
L
M
N
U
V
W
X
_
`
a
b
i
j
k
l
s
t
u
v
}
~

9
HT
DC3
GS
'
1
;
E
O
Y
c
m
w

|
|
|
|
|
|
|
|
|
|
|
|
|
|

Revisin 0.99zz Pgina 389

ejemplo, aunque estos smbolos que van del nmero 128 al 255 no son estndar,

tambin vocales acentuadas, ees, y otros smbolos para dibujar recuadros, por

bits, que permite 256 smbolos (del 0 al 255), lo que permite que se puedan usar

Hoy en da, casi todos los ordenadores incluyen un cdigo ASCII extendido de 8

|
|
|
|
|
|
|
|
|
|
|
|
|
|

Estos cdigos ASCII estndar son:

impresora (y borra la pantalla en algunos ordenadores), etc.

caracter 13 (CR) avanza de lnea, el carcter 12 (FF) expulsa una pgina en la

cdigos de control: por ejemplo, el caracter 7 (BEL) hace sonar un pitido, el

Los cdigos estndar "visibles" van del 32 al 127. Los cdigos del 0 al 31 son

1000001 (65 en decimal) corresponder a la letra "A" (a, en maysculas).

Por ejemplo, en cualquier ordenador que use cdigo ASCII, la secuencia de bits

letra.

0000000 hasta el 1111111 (0 a 127 en decimal) corresponda siempre a la misma

El cdigo ASCII estndar es de 7 bits, lo que hace que cada grupo de bits desde el

carcter a cada secuencia de varios bits.

ordenadores o sistemas informticos. Para ello, se hace corresponder una letra o

La idea de este cdigo es que se pueda compartir informacin entre distintos

Intercambio de Informacin.

Interchange", que se podra traducir como Cdigo Estndar Americano para

El nombre del cdigo ASCII viene de "American Standard Code for Information

Apnd ice 2. El cdigo ASCII

Introduccin a la programacin con C#, por Nacho Cabanes

carcter 32 hasta el 127, en filas de 16 caracteres cada una.

Revisin 0.99zz Pgina 390

(Ap2.1) Crea un programa en C# que muestre una tabla ASCII bsica, desde el

Ejercicios propuestos:

tenga problemas de distintas interpretaciones.

lo que permite que la transferencia de informacin entre distintos sistemas no

de ms de 8 bits (tpicamente 16 bits, que dara lugar a 65.536 smbolos distintos),

Una alternativa ms moderna es el estndar UTF-8, que permite usar caracteres

sistema operativo que utiliza es distinto.

de modo que puede que otro ordenador no los interprete correctamente si el

Introduccin a la programacin con C#, por Nacho Cabanes

byte- para mayor legibilidad, como yo he hecho en el ejemplo anterior; a un grupo


de 4 bits se le llama nibble).
Otra forma sencilla de convertir de decimal a binario es dividir consecutivamente
entre 2 y coger los restos que hemos obtenido, pero en orden inverso:

de memoria" que estn completamente vacas (0) o completamente llenas (1), slo

les es realmente cmodo contar con 2 cifras: 0 y 1.

Por eso, dentro del ordenador cualquier nmero se deber almacenar como ceros

y unos, y entonces los nmeros se debern desglosar en potencias de 2 (el

+ 1 2

+ 0 2

+ 1 2

Revisin 0.99zz Pgina 391

0110 1101 (binario) =


7
6
5
4
3
2
1
0 2 + 1 2 + 1 2 + 0 2 + 1 2 + 1 2 + 0 2 + 1 2
0 128 + 1 64 + 1 32 + 0 16 + 1 8 + 1 4 + 0 2 + 1 1 =
109 (decimal)

expresamos como suma de potencias de 2 y sumamos:

En general, convertir un nmero binario al sistema decimal es fcil: lo

de modo que el nmero decimal 13 se escribir en binario como 1101.

13 = 1 2

o, ms detallado:

13 = 1 8 + 1 4 + 0 2 + 1 1

(Nota: es frecuente separar los nmeros binarios en grupos de 4 cifras -medio

Para los ordenadores no es cmodo contar hasta 10. Como partimos de "casillas

00 = 0
0+0 = 0

decimal:
01 = 0
0+1 = 1

10 = 0
1+0 = 1

11 = 1
1+1 = 10

Revisin 0.99zz Pgina 392

(en decimal: 2)

Y se pueden hacer operaciones con nmeros binarios? S, casi igual que en

01101101).

cifras, si queremos completarlo a 8 cifras rellenamos con ceros por la izquierda:

Si leemos esos restos de abajo a arriba, obtenemos el nmero binario: 1101101 (7

109 / 2 = 54, resto 1


54 / 2 = 27, resto 0
27 / 2 = 13, resto 1
13 /2 = 6, resto 1
6 / 2 = 3, resto 0
3 / 2 = 1, resto 1
1 / 2 = 0, resto 1
(y ya hemos terminado)

109 decimal = 0110 1101 binario

254 = 3 103 + 2 102 + 5 101 + 4 100

llamado "sistema binario"):

buscbamos:

Si "juntamos" los cocientes que hemos obtenido, aparece el nmero binario que

109 / 128 = 0 (resto: 109)


109 / 64 = 1 (resto: 45)
45 / 32 = 1 (resto: 13)
13 / 16 = 0 (resto: 13)
13 / 8 = 1 (resto: 5)
5 / 4 = 1 (resto: 1)
1 / 2 = 0 (resto: 1)
1 / 1 = 1 (hemos terminado).

divisiones:

sencilla es ir dividiendo entre las potencias de 2, y coger todos los cocientes de las

Convertir un nmero de decimal a binario resulta algo menos intuitivo. Una forma

Introduccin a la programacin con C#, por Nacho Cabanes

o ms detallado todava:

3.254 = 3 1000 + 2 100 + 5 10 + 4 1

Por ejemplo, el nmero 3.254 se podra desglosar como:

sin pensar.

nmeros se expresan a partir de potencias de 10, pero normalmente lo hacemos

Nosotros normalmente utilizamos el sistema decimal de numeracin: todos los

Ap3.1. Sistema binario

Apnd ice 3. Sistemas de numeracin.

Introduccin a la programacin con C#, por Nacho Cabanes

11111111+00101101.

rapidsimo

(Ap3.1.5) Crea un programa en C# que convierta a binario los nmeros (en base

que

el sistema

binario

cuando

haya

que

expresar

cifras

254 = 3 8

de modo que

+ 7 8

+ 6 8

254 (decimal) ->


254 / 64 = 3 (resto: 62)
62 / 8 = 7 (resto: 6)
6 / 1 = 6 (se termin)

ejemplo:

Revisin 0.99zz Pgina 393

decimal a binario ser, como siempre dividir entre las potencias de la base. Por

El sistema octal de numeracin trabaja en base 8. La forma de convertir de

sistema octal y, sobre todo, el hexadecimal.

correspondencia algo ms sencilla que el sistema decimal. Los ms usados son el

medianamente grandes, pero que a la vez mantengan con ste una

"compactos"

Por eso, se han buscado otros sistemas de numeracin que resulten ms

nmero 254 se expresa en binario como 11111110 (8 cifras en vez de 3).

expresados en este sistema de numeracin "ocupan mucho". Por ejemplo, el

informacin dentro del ordenador es el sistema binario. Pero los nmeros

Hemos visto que el sistema de numeracin ms cercano a como se guarda la

Ap3.2. Sistema octal

que introduzca el usuario.

(Ap3.1.6) Crea un programa en C# que convierta a base 10 los nmeros binarios

que introduzca el usuario.


Revisin 0.99zz Pgina 394

(Ap3.1.6) Crea un programa en C# que convierta a base 10 los nmeros octales

que introduzca el usuario.

(Ap3.1.5) Crea un programa en C# que convierta a octal los nmeros (en base 10)

(Ap3.2.4) Expresar en el sistema decimal los nmeros octales 162, 76, 241, 102.

(Ap3.2.3) Expresar en el sistema binario los nmeros octales 171, 243, 105, 45.

10110010, 11111111, 00101101

(Ap3.2.2) Expresar en sistema octal los nmeros binarios de 8 bits: 01100110,

(Ap3.2.1) Expresar en sistema octal los nmeros decimales 17, 101, 83, 45.

Ejercicios propuestos:

el hexadecimal...

De cualquier modo, el sistema octal no es el que ms se utiliza en la prctica, sino

423 (octal) = 4 64 + 2 8 + 3 1 = 275 (decimal)

o bien

nmero 423 (octal) sera 423 (octal) = 100 010 011 (binario)

El paso desde el octal al binario y al decimal tambin es sencillo. Por ejemplo, el

254 (decimal) = 011 111 110 (binario) = 376 (octal)

de modo que

011 (binario ) = 3 (decimal y octal)


111 (binario ) = 7 (decimal y octal)
110 (binario ) = 6 (decimal y octal)

254 (decimal) = 011 111 110 (binario)

sistema binario: si agrupamos los bits de 3 en 3, el paso de binario a octal es

Comprueba el resultado convirtindolos a decimal.

10) que introduzca el usuario.

Pero adems existe una correspondencia muy sencilla entre el sistema octal y el

(Ap3.1.4) Multiplica los nmeros binarios de 4 bits 01001011, 10010011.

anterior.

necesitaba en sistema binario.

ocupa 3 cifras en decimal, y tambin 3 cifras en octal, frente a las 8 cifras que

01100110+10110010,

Comprueba el resultado sumando los nmeros decimales obtenidos en el ejercicio

nmeros

incmoda que usar el sistema decimal, al menos es ms compacta: el nmero 254

los

(Ap3.1.3)

Suma

Hemos conseguido otra correspondencia que, si bien nos resulta a nosotros ms

10110010, 11111111, 00101101

254 (decimal) = 376 (octal)

o bien

Introduccin a la programacin con C#, por Nacho Cabanes

(Ap3.1.2) Expresa en sistema decimal los nmeros binarios de 8 bits: 01100110,

(Ap3.1.1) Expresa en sistema binario los nmeros decimales 17, 101, 83, 45.

Ejercicios propuestos:

Introduccin a la programacin con C#, por Nacho Cabanes

(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)

=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=

0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F

(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)

o bien

254 = 15 16

de modo que

+ 14 16

254 (decimal) ->


254 / 16 = 15 (resto: 14)
14 / 1 = 14 (se termin)

difcil:

Revisin 0.99zz Pgina 395

Con estas consideraciones, expresar nmeros en el sistema hexadecimal ya no es

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

estas cifras usaremos las letras de la A a la F, as:

11, 12, 13, 14 y 15, que utilizaremos en el sistema hexadecimal. Para representar

del 0 al 9, de modo que no tenemos cifras de un solo dgito para los nmeros 10,

Pero hay una dificultad: estamos acostumbrados al sistema decimal, con nmeros

=16), y es lo que se conoce como sistema hexadecimal.

representara por 2 cifras. Este sistema de numeracin trabajar en base 16 (2

Sera ms cmodo poder agrupar de 4 en 4 bits, de modo que cada byte se

por 8 bits, que no es mltiplo de 3.

convertir de binario a octal y viceversa es muy sencillo, pero un byte est formado

+ 4 16

+ 3 16

+ 11 16

+ 2 16

+ 11 16

+ 5 16

= 41653

0
1
2
3
4
5
6
7
8
9
A
B
C
D
E

(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)
(hexadecimal)

=
=
=
=
=
=
=
=
=
=
=
=
=
=
=

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14

(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)
(decimal)

=
=
=
=
=
=
=
=
=
=
=
=
=
=
=

0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110

(binario)
(binario)
(binario)
(binario)
(binario)
(binario)
(binario)
(binario)
(binario)
(binario)
(binario)
(binario)
(binario)
(binario)
(binario)

dgito hexadecimal equivale a una secuencia de 4 bits:

Revisin 0.99zz Pgina 396

El paso de hexadecimal a binario tambin es (relativamente) rpido, porque cada

A2B5 (hexadecimal) = 10 16

ejemplo el nmero A2B5

Ahora vamos a dar el paso inverso: convertir de hexadecimal a decimal, por

54331 (decimal) = D43B (hexadecimal)

es decir

254 = 13 16

o bien

54331 = 13 4096 + 4 256 + 3 16 + 11 1

de modo que

54331 (decimal) ->


54331 / 4096 = 13 (resto: 1083)
1083 / 256 = 4 (resto: 59)
59 / 16 = 3 (resto: 11)
11 / 1 = 11 (se termin)

Vamos a repetirlo para un convertir de decimal a hexadecimal nmero ms


grande:

El sistema octal tiene un inconveniente: se agrupan los bits de 3 en 3, por lo que

254 (decimal) = FE (hexadecimal)

Introduccin a la programacin con C#, por Nacho Cabanes

Ap3.3. Sistema hexadecimal

Introduccin a la programacin con C#, por Nacho Cabanes

salen bien, y que slo tiene como inconveniente que hay dos formas de expresar
el nmero 0 (0000 0000 o 1111 1111), lo que complica algunos trabajos internos
del ordenador.

base 10) que introduzca el usuario.

(Ap3.3.6) Crea un programa en C# que convierta a base 10 los nmeros

3 (decimal) = 0011
6 (decimal) = 0110

-3 = 1011
-6 = 1110

Por ejemplo, si usamos 4 bits, tendramos

visto.

Revisin 0.99zz Pgina 397

es negativo y se deja a 0 si es positivo. Los dems bits se calculan como ya hemos

Signo y magnitud: el primer bit (el de ms a la izquierda) se pone a 1 si el nmero

-3 = 1101
-6 = 1010

almacena como 00000000).

Revisin 0.99zz Pgina 398

correcta, y no tiene problemas para expresar el nmero 0 (que siempre se

con el que las operaciones con nmeros negativos siempre se realizan de forma

Es un mtodo que parece algo ms complicado, pero que no es difcil de seguir,

3 (decimal) = 0011
6 (decimal) = 0110

Por ejemplo, con 4 bits

Complemento a 2: para los negativos, se cambian los ceros por unos y se suma
uno al resultado.

representarlos. Las ms habituales son:

comprueba que los resultados que se obtienen son los correctos.

Para los nmeros enteros negativos, existen varias formas posibles de

Ap3.4. Representacin interna de los enteros negativos

binario, usando complemento a uno para expresar los nmeros negativos. Calcula

binarios que introduzca el usuario.

(en binario) el resultado de las operaciones 13+34, (-13)+(-34), 13+(-34) y

Ejercicio propuesto: convierte los nmeros decimales 13, 34, -13, -34 a sistema

(Ap3.3.7) Crea un programa en C# que convierta a hexadecimal los nmeros

hexadecimales que introduzca el usuario.

Tambin es un mtodo sencillo, en el que las operaciones con nmeros negativos

-3 = 1100
-6 = 1001

(Ap3.3.5) Crea un programa en C# que convierta a hexadecimal los nmeros (en

3 (decimal) = 0011
6 (decimal) = 0110

Por ejemplo, con 4 bits

negativos.

Complemento a 1: se cambian los ceros por unos para expresar los nmeros

13 (decimal) = 0000 1101 - 13 (decimal) = 1000 1101


34 (decimal) = 0010 0010 - 34 (decimal) = 1010 0010
13 + 34 = 0000 1101 + 0010 0010 = 0010 1111 = 47 (correcto)
(-13) + (-34) = 1000 1101 + 1010 0010 = 0010 1111 = 47 (INCORRECTO)
13 + (-34) = 0000 1101 + 1010 0010 = 1010 1111 = -47 (INCORRECTO)

correctamente. Vamos a ver un ejemplo, con nmeros de 8 bits:

operaciones en las que aparecen nmeros negativos no se comportan

Es un mtodo muy sencillo, pero que tiene el inconveniente de que las

Introduccin a la programacin con C#, por Nacho Cabanes

2A.

(Ap3.3.4) Expresa en el sistema decimal los nmeros hexadecimales 1B2, 76, E1,

1A2.

(Ap3.3.3) Expresa en el sistema binario los nmeros hexadecimales 2F, 37, A0,

01100110, 10110010, 11111111, 00101101

(Ap3.3.2) Expresa en sistema hexadecimal los nmeros binarios de 8 bits:

(Ap3.3.1) Expresa en sistema hexadecimal los nmeros decimales 18, 131, 83, 245.

Ejercicios propuestos:

110010100100100101010100111 =>
0110 0101 0010 0100 1010 1010 0111 = 6524AA7

el valor de cada uno de ellos:

y de igual modo, de binario a hexadecimal es dividir en grupos de 4 bits y hallar

de modo que A2B5 (hexadecimal) = 1010 0010 1011 0101 (binario)

F (hexadecimal) = 15 (decimal) = 1111 (binario)

Introduccin a la programacin con C#, por Nacho Cabanes

signo) podra tomar valores entre +32.767 y 32.768.

Revisin 0.99zz Pgina 399

podra tomar valores entre 0 y 65.535, mientras que un "short" (entero corto con

nmeros ms grandes. Por ejemplo, un "ushort" (enterno corto sin signo) en C#

primer bit se puede utilizar como parte de los datos, y podemos almacenar

primer bit para el signo. Por eso, si declaramos una variable como "unsigned", ese

En general, todos los formatos que permiten guardar nmeros negativos usan el

comprueba que los resultados que se obtienen son los correctos.

Calcula (en binario) el resultado de las operaciones 13+34, (-13)+(-34), 13+(-34) y

sistema binario, usando complemento a dos para expresar los nmeros negativos.

Ejercicio propuesto (Ap3.4.1): Convierte los nmeros decimales 13, 34, -13, -34 a

Introduccin a la programacin con C#, por Nacho Cabanes

// Inicializamos SDL
Sdl.SDL_Init(Sdl.SDL_INIT_EVERYTHING);
Revisin 0.99zz Pgina 400

short anchoPantalla = 800;


short altoPantalla = 600;
int bitsColor = 24;
int flags = Sdl.SDL_HWSURFACE|Sdl.SDL_DOUBLEBUF|Sdl.SDL_ANYFORMAT;
IntPtr pantallaOculta;

public static void Main()


{

public class Sdl01


{

using Tao.Sdl;
using System; // Para IntPtr (puntero: imgenes, etc)

// sdl01.cs
// Primer acercamiento a SDL
// Introduccin a C#, por Nacho Cabanes

funciones.

volver al sistema operativo. Tras el fuente comentaremos las principales

modo grfico, cargar una imagen, dibujarla en pantalla, esperar cinco segundos y

Vamos a ver un primer ejemplo, bsico pero completo, que muestre cmo entrar a

Ap4.2. Mostrar una imagen esttica

haremos un poco ms adelante.

detalles de SDL creando nuestras propias clases "Hardware", "Imagen", etc., como

realizar tareas muy bsicas. Por eso, muchas veces es preferible "ocultar" los

as que los fuentes siguientes pueden resultar difciles de entender, a pesar de

SDL no es una librera especialmente sencilla, y tampoco lo acaba de ser Tao.SDL,

las versiones ms recientes desde http://sourceforge.net/projects/taoframework/

primeras versiones se pueden descargar desde http://www.mono-project.com/Tao y

Tao.SDL es una adaptacin de esta librera, que permite emplearla desde C#. Las

comprobar el teclado, el ratn o el joystick/gamepad, as como reproducir sonidos.

para diversos sistemas operativos y que permite tanto dibujar imgenes como

SDL es una conocida biblioteca para la realizacin de juegos, que est disponible

Ap4.1. Juegos con Tao.SDL

Apnd ice 4. SDL

Introduccin a la programacin con C#, por Nacho Cabanes

destructor).

SDL_Quit libera los recursos (algo que generalmente haramos desde un

que ya habamos comentado en el apartado sobre temporizacin.

Para la pausa no hemos usado ninguna funcin de SDL, sino Thread.Sleep,

"doble buffer").

SDL_Flip vuelca esa pantalla oculta a la pantalla visible (el paso final de ese

parpadeos (es una tcnica que se conoce como "doble buffer").

volcar toda esa pantalla oculta a la pantalla visible, con lo que se evitan

para ir dibujando todas las imgenes en una pantalla oculta, y finalmente

// Y esperamos 5 segundos
System.Threading.Thread.Sleep( 5000 );

// Finalmente, cerramos SDL


Sdl.SDL_Quit();

Copiar en la misma carpeta los ficheros DLL (Tao.Sdl.Dll y SDL.Dll) y las

(Tao.Sdl.Dll y SDL.Dll) y las imgenes (en este caso, "personaje.bmp").

Cuando todo funcione correctamente, podremos cambiar el "tipo de


x

consola cuando lanzamos nuestro programa.

como el JPG, o transparencia, como el PNG). El tipo de dato que se obtiene

Revisin 0.99zz Pgina 402

"Aplicacin de Windows", para que no aparezca la ventana negra de

"puro", no podremos emplear otros tipos que permitan menores tamaos,

Revisin 0.99zz Pgina 401

proyecto" (desde el men "Proyecto", en la opcin "Propiedades") a

SDL_LoadBMP carga una imagen en formato BMP (si slo usamos SDL

imagen parcialmente (o completamente) fuera de la pantalla visible.

referencia").
Compilar y probar.
x

pantalla, para que no tengamos que preocuparnos por si dibujamos una

ventana del Explorador de soluciones y escogiendo la opcin "Agregar

ancho y su alto, y se usa en muchas operaciones.

SDL_SetClipRect indica la zona de recorte (clipping) del tamao de la

pulsando el botn derecho del ratn en el apartado "Referencias" de la

El tipo SDL_Rect define un "rectngulo" a partir de su origen (x e y), su

Aadir el fichero Tao.Sdl.Dll a las referencias del proyecto (normalmente,

Copiar en la carpeta de ejecutables (tpicamente bin/debug) los ficheros DLL

Reemplazar nuestro programa principal por ste.

Crear un proyecto de "aplicacin de consola".

adicionales.

ancho y alto de pantalla, cierta cantidad de colores y ciertas opciones

SDL_Init es la rutina de inicializacin, que entra a modo grfico, con cierto

/r:Tao.Sdl.dll /platform:x86

Y si empleamos Visual Studio o SharpDevelop, tendremos que:

gmcs sdl01.cs

Compilar con:

imgenes (en este caso, "personaje.bmp").

Teclear (o copiar y pegar) el fuente.

Algunas ideas bsicas:

entonces la imagen se habra leido sin problemas).


SDL_BlitSurface vuelca un rectngulo (SDL_Rect) sobre otro, y lo usamos

Para compilar este ejemplo usando Mono, deberemos:

IntPtr.Zero (y en ese caso, no se habra podido cargar) u otro distinto (y

realmente se ha podido cargar la imagen es mirando si el valor obtenido es

es un "IntPtr" (del que no daemos ms detalles), y la forma de comprobar si

Introduccin a la programacin con C#, por Nacho Cabanes

// Mostramos la pantalla oculta


Sdl.SDL_Flip(pantallaOculta);

// Dibujamos la imagen
short x = 400;
short y = 300;
short anchoImagen = 50;
short altoImagen = 50;
Sdl.SDL_Rect origen = new Sdl.SDL_Rect(0,0,anchoImagen,altoImagen);
Sdl.SDL_Rect dest = new Sdl.SDL_Rect(x,y,anchoImagen,altoImagen);
Sdl.SDL_BlitSurface(imagen, ref origen, pantallaOculta, ref dest);

// Cargamos una imagen


IntPtr imagen;
imagen = Sdl.SDL_LoadBMP("personaje.bmp");
if (imagen == IntPtr.Zero) {
System.Console.WriteLine("Imagen inexistente!");
Environment.Exit(4);
}

// Indicamos que se recorte lo que salga de la pantalla oculta


Sdl.SDL_Rect rect2 =
new Sdl.SDL_Rect(0,0, (short) anchoPantalla, (short) altoPantalla);
Sdl.SDL_SetClipRect(pantallaOculta, ref rect2);

pantallaOculta = Sdl.SDL_SetVideoMode(
anchoPantalla,
altoPantalla,
bitsColor,
flags);

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 403

// Indicamos que se recorte lo que salga de la pantalla oculta


Sdl.SDL_Rect rect2 =
new Sdl.SDL_Rect(0,0, (short) anchoPantalla, (short) altoPantalla);

// Inicializamos SDL
Sdl.SDL_Init(Sdl.SDL_INIT_EVERYTHING);
pantallaOculta = Sdl.SDL_SetVideoMode(
anchoPantalla,
altoPantalla,
bitsColor,
flags);

short anchoPantalla = 800;


short altoPantalla = 600;
int bitsColor = 24;
int flags = Sdl.SDL_HWSURFACE | Sdl.SDL_DOUBLEBUF | Sdl.SDL_ANYFORMAT
| Sdl.SDL_FULLSCREEN;
IntPtr pantallaOculta;

public static void Main()


{

public class Sdl02


{

using Tao.Sdl;
using System; // Para IntPtr (puntero: imgenes, etc)

// sdl02.cs
// Segundo acercamiento a SDL
// Introduccin a C#, por Nacho Cabanes

con las flechas del teclado, a una velocidad de 50 fotogramas por segundo, as:

Un segundo ejemplo algo ms detallado podra permitirnos mover el personaje

Ap4.3. Una imagen que se mueve con el teclado

segundo de pausa entre una imagen y la siguiente).

imgenes que se mostrarn de forma repetitiva (por ejemplo, 10 veces, con medio

(Ap4.2.1) Crea una animacin con al menos 4 fotogramas, utilizando varias

Ejercicios propuestos

http://www.nachocabanes.com/fich/descargar.php?nombre=SdlBasico.zip

ficheros DLL necesarios y una imagen de ejemplo, desde:

Puedes descargar este fuente, incluyendo el proyecto de Visual Studio 2010, los

funciones adicionales de dibujo (lneas, recuadros, crculos, etc).

comprimidas (PNG o JPG), ni tipos de letra TTF, ni sonidos en formato MP3, ni

No necesitaremos ninguna DLL adicional si no vamos a usar imgenes

Introduccin a la programacin con C#, por Nacho Cabanes

// Y esperamos 20 ms
System.Threading.Thread.Sleep( 20 );

// Mostramos la pantalla oculta


Sdl.SDL_Flip(pantallaOculta);

// Finalmente, cerramos SDL


Sdl.SDL_Quit();
Revisin 0.99zz Pgina 404

// Borramos pantalla
Sdl.SDL_Rect origen = new Sdl.SDL_Rect(0,0,
anchoPantalla,altoPantalla);
Sdl.SDL_FillRect(pantallaOculta, ref origen, 0);
// Dibujamos en sus nuevas coordenadas
origen = new Sdl.SDL_Rect(0,0,anchoImagen,altoImagen);
Sdl.SDL_Rect dest = new Sdl.SDL_Rect(x,y,
anchoImagen,altoImagen);
Sdl.SDL_BlitSurface(imagen, ref origen,
pantallaOculta, ref dest);

// Miramos si se ha pulsado alguna flecha del cursor


if (teclas[Sdl.SDLK_UP] == 1)
y -= 2;
if (teclas[Sdl.SDLK_DOWN] == 1)
y += 2;
if (teclas[Sdl.SDLK_LEFT] == 1)
x -= 2;
if (teclas[Sdl.SDLK_RIGHT] == 1)
x += 2;
if (teclas[Sdl.SDLK_ESCAPE] == 1)
terminado = true;

// Comprobamos sucesos
Sdl.SDL_PollEvent(out suceso);
teclas = Sdl.SDL_GetKeyState(out numkeys);

} while (!terminado);

do
{

// Parte repetitiva
bool terminado = false;
short x = 400;
short y = 300;
short anchoImagen = 50;
short altoImagen = 50;
Sdl.SDL_Event suceso;
int numkeys;
byte[] teclas;

// Cargamos una imagen


IntPtr imagen;
imagen = Sdl.SDL_LoadBMP("personaje.bmp");
if (imagen == IntPtr.Zero) {
System.Console.WriteLine("Imagen inexistente!");
Environment.Exit(4);
}

Sdl..SDL_SetClipRect(pantallaOculta, ref rect2);

Introduccin a la programacin con C#, por Nacho Cabanes

analizar.

de borrar la pantalla o parte de sta.

SDL_FillRect rellena un rectngulo con un cierto color. Es una forma sencilla

array con el nombre de la tecla en ingls, as: teclas[Sdl.SDLK_RIGHT]

cada tecla. Luego podemos mirar cada una de esas teclas accediendo a ese

SDL_GetkeyState obtenemos un array que nos devuelve el estado actual de

// Parte repetitiva
bool terminado = false;
short x = 400;
short y = 300;
Revisin 0.99zz Pgina 405

public static void Main()


{
bool pantallaCompleta = true;
Hardware h = new Hardware(800, 600, 24, pantallaCompleta);
Imagen img = new Imagen("personaje.bmp", 50, 50);

public class Sdl03


{

// sdl03.cs
// Tercer acercamiento a SDL: clases auxiliares
// Introduccin a C#, por Nacho Cabanes

Por ejemplo, podemos buscar que el programa anterior quede simplemente as:

legible:

auxiliares que nos permitan ocultar los detalles de SDL y hacer un Main ms

Podemos simplificar un poco la estructura del programa si creamos unas clases

Ap4.4. Simplificando con clases auxiliares

(al menos) dos imgenes, para dar una impresin de movimiento ms real.

(Ap4.3.1) Ampla el ejemplo 2 de SDL (sdl02.cs) para que al moverse alterne entre

Ejercicios propuestos

Con SDL_PollEvent forzamos a que se mire qu sucesos hay pendientes de

pulsaciones de teclas, o de ratn, o el uso del joystick.

SDL_Event es el tipo de datos que se usa para comprobar "sucesos", como

Usamos un bucle "do...while" para repetir hasta que se pulse la tecla ESC.

"juego" se ejecute a pantalla completa, en vez de hacerlo en ventana.

Al inicializar, aadimos una nueva opcin, Sdl.SDL_FULLSCREEN, para que el

Las diferencias de este fuente con el anterior son:

Introduccin a la programacin con C#, por Nacho Cabanes

} while (!terminado);

// Y esperamos 20 ms
h.Pausa(20);

// Dibujar en pantalla
h.BorrarPantallaOculta();
h.DibujarImagenOculta(img);
h.VisualizarOculta();

// Miramos si se ha pulsado alguna flecha del cursor


if (h.TeclaPulsada(Hardware.TECLA_ARR))
y -= 2;
if (h.TeclaPulsada(Hardware.TECLA_ABA))
y += 2;
if (h.TeclaPulsada(Hardware.TECLA_IZQ))
x -= 2;
if (h.TeclaPulsada(Hardware.TECLA_DER))
x += 2;
if (h.TeclaPulsada(Hardware.TECLA_ESC))
terminado = true;
img.MoverA(x, y);

// Inicializamos SDL
Sdl.SDL_Init(Sdl.SDL_INIT_EVERYTHING);
pantallaOculta = Sdl.SDL_SetVideoMode(
anchoPantalla,
Revisin 0.99zz Pgina 406

public Hardware(int ancho, int alto, int colores, bool pantallaCompleta)


{
int flags = Sdl.SDL_HWSURFACE | Sdl.SDL_DOUBLEBUF |
Sdl.SDL_ANYFORMAT;
if (pantallaCompleta)
flags = flags | Sdl.SDL_FULLSCREEN;

IntPtr pantallaOculta;

public class Hardware


{
short anchoPantalla = 800;
short altoPantalla = 600;
int bitsColor = 24;

using Tao.Sdl; // Para acceder a SDL


using System; // Para IntPtr
using System.Threading; // Para Pausa (Thread.Sleep)

// hardware.cs
// Clases auxiliar Hardware para SDL
// Introduccin a C#, por Nacho Cabanes

la pantalla y al teclado. Podra ser as:

Para eso necesitaramos una clase "Hardware", que oculte los detalles del acceso a

do
{

Introduccin a la programacin con C#, por Nacho Cabanes

// Definiciones de teclas
public static int TECLA_ESC = Sdl.SDLK_ESCAPE;
public static int TECLA_ARR = Sdl.SDLK_UP;
public static int TECLA_ABA = Sdl.SDLK_DOWN;

public void Pausa(int milisegundos)


{
Thread.Sleep(milisegundos);
}

Revisin 0.99zz Pgina 407

public bool TeclaPulsada(int c)


{
bool pulsada = false;
Sdl.SDL_PumpEvents();
Sdl.SDL_Event suceso;
Sdl.SDL_PollEvent(out suceso);
int numkeys;
byte[] teclas = Tao.Sdl.Sdl.SDL_GetKeyState(out numkeys);
if (teclas[c] == 1)
pulsada = true;
return pulsada;
}

public void VisualizarOculta()


{
Sdl.SDL_Flip(pantallaOculta);
}

public void DibujarImagenOculta(Imagen imagen)


{
Sdl.SDL_Rect origen = new Sdl.SDL_Rect(0, 0,
anchoPantalla, altoPantalla);
Sdl.SDL_Rect dest = new Sdl.SDL_Rect(
imagen.GetX(), imagen.GetY(),
imagen.GetAncho(), imagen.GetAlto());
Sdl.SDL_BlitSurface(imagen.GetPuntero(), ref origen,
pantallaOculta, ref dest);
}

public void BorrarPantallaOculta()


{
Sdl.SDL_Rect origen = new Sdl.SDL_Rect(0, 0,
anchoPantalla, altoPantalla);
Sdl.SDL_FillRect(pantallaOculta, ref origen, 0);
}

~Hardware()
{
Sdl.SDL_Quit();
}

// Indicamos que se recorte lo que salga de la pantalla oculta


Sdl.SDL_Rect rect2 =
new Sdl.SDL_Rect(0, 0, (short)anchoPantalla, (short)altoPantalla);
Sdl.SDL_SetClipRect(pantallaOculta, ref rect2);

altoPantalla,
,
bitsColor,
flags);

Introduccin a la programacin con C#, por Nacho Cabanes

IntPtr GetPuntero() { return imagen; }


short GetX() { return (short)x; }
short GetY() { return (short)y; }
short GetAncho() { return (short)ancho; }
short GetAlto() { return (short)alto; }

(Ap4.4.1) Descompn en clases el ejercicio Ap4.3.1.

Ejercicios propuestos

Tao.Sdl.Dll, SDL.Dll y la imagen "personaje.bmp".

Revisin 0.99zz Pgina 408

sus referencias, y tendremos que copiar en la carpeta de ejecutables los ficheros

Al igual que antes, al crear el proyecto deberemos aadir el fichero Tao.Sdl.Dll a

public
public
public
public
public

public void MoverA(int x, int y)


{
this.x = x;
this.y = y;
}

public Imagen(string nombreFichero, int ancho, int alto)


{
imagen = Sdl.SDL_LoadBMP(nombreFichero);
if (imagen == IntPtr.Zero)
{
System.Console.WriteLine("Imagen inexistente!");
Environment.Exit(1);
}
this.ancho = ancho;
this.alto = alto;
}

public class Imagen


{
IntPtr imagen;
int x, y;
int ancho, alto;

using Tao.Sdl; // Para acceder a SDL


using System; // Para IntPtr

// imagen.cs
// Clases auxiliar Imagen para SDL
// Introduccin a C#, por Nacho Cabanes

comprobar colisiones):

adelante nos resultarn tiles, como el ancho y el alto (que nos servirn para

adicionales, como la posicin en la que se encuentra esa imagen, y otros que ms

Y una clase "Imagen" podra ocultar ese "IntPtr", adems de aadirle datos

public static int TECLA_DER = Sdl.SDLK_RIGHT;


public static int TECLA_IZQ = Sdl.SDLK_LEFT;

Introduccin a la programacin con C#, por Nacho Cabanes

Comprobar colisiones entre elementos del juego (que pueden suponer

Hacer una pausa al final de cada "fotograma", para que la velocidad del

void inicializar()
{
h = new Hardware(800, 600, 24, pantallaCompleta);
img = new Imagen("personaje.bmp", 50, 50);
x = 400;
y = 300;

public class Juego


{
bool pantallaCompleta = true;
Hardware h;
Imagen img;
bool terminado = false;
short x, y;

using Tao.Sdl;
using System; // Para IntPtr (puntero: imgenes, etc)

// sdl04.cs
// Cuarto acercamiento a SDL: bucle de juego
// Introduccin a C#, por Nacho Cabanes

Revisin 0.99zz Pgina 409

elemento, como un premio que recoger y un enemigo que se mueve:

Podemos descomponer en funciones nuestro juego y, de paso, aadir algn otro

multitarea del sistema operativo.

juego sea la misma en cualquier ordenador, y, de paso, para ayudar a la

Dibujar todos los elementos en pantalla en su estado actual

perder vidas o energa, ganar puntos, etc)

Mover los elementos del juego (personaje, enemigos, fondos mviles)

de joystick...)

Comprobar eventos (pulsaciones de teclas, clics o movimiento de ratn, uso

Un "bucle de juego clsico" tendra una apariencia similar a esta:

"Inicializar", "CargarImagen", "ComprobarTeclas", "DibujarImagenes", etc.

crear nuestras propias funciones que la oculten un poco: funciones como

dentro de "Main" y va creciendo arbitrariamente. Por eso, suele ser preferible

difcil de leer, y ms an si no est estructurado, sino que tiene toda la lgica

A medida que nuestro juego se va complicando, el fuente puede irse haciendo ms

Ap4.5. Un fuente ms modular: el "bucle de juego"

Introduccin a la programacin con C#, por Nacho Cabanes

// Bucle de juego
do
{
j.comprobarTeclas();
j.moverElementos();

private static void Main()


{
Juego j = new Juego();
j.inicializar();

bool partidaTerminada()
{
return terminado;
}

void pausaFotograma()
{
// Esperamos 20 ms
h.Pausa(20);
}

void dibujarElementos()
{
h.BorrarPantallaOculta();
h.DibujarImagenOculta(img);
h.VisualizarOculta();
}

void moverElementos()
{
// Todavia no hay ningun elemento que se mueva solo
}

void comprobarColisiones()
{
// Todavia no comprobamos colisiones con enemigos
// ni con obstaculos
}

void comprobarTeclas(()
{
if (h.TeclaPulsada(Hardware.TECLA_ARR))
y -= 2;
if (h.TeclaPulsada(Hardware.TECLA_ABA))
y += 2;
if (h.TeclaPulsada(Hardware.TECLA_IZQ))
x -= 2;
if (h.TeclaPulsada(Hardware.TECLA_DER))
x += 2;
if (h.TeclaPulsada(Hardware.TECLA_ESC))
terminado = true;
img.MoverA(x, y);
}

Revisin 0.99zz Pgina 410

Introduccin a la programacin con C#, por Nacho Cabanes

public void Cargar(string nombreFichero, short tamanyo)


{

public Fuente(string nombreFichero, short tamanyo)


{
Cargar(nombreFichero, tamanyo);
}

public class Fuente


{
IntPtr tipoDeLetra;

using Tao.Sdl; // Para acceder a SDL


using System; // Para IntPtr

// fuente.cs
// Clases auxiliar Fuente para SDL
// Introduccin a C#, por Nacho Cabanes

una clase auxiliar, llamada "Fuente":

Revisin 0.99zz Pgina 411

ocurra con las imgenes, por lo que, igual que hicimos con stas, podemos crear

El tipo de letra estar accesible a travs de un puntero genrico "IntPtr", igual que

SdlTtf.TTF_Init();

(al final del mtodo Inicializar de la clase Hardware):

Tambin tenemos que inicializar SdlTtf despus de la inicializacin bsica de SDL

que queramos usar.

nuestro programa, as como el fichero TTF correspondiente a cada tipo de letra

Debemos incluir el fichero DLL llamado SDL_ttf.DLL en la carpeta del ejecutable de

Windows y Linux), los cambios no son grandes:

Si queremos escribir texto usando tipos de letra TrueType (los habituales en

Ap4.6. Escribir texto

un bucle de juego clsico.

(Ap4.5.1) Refina el ejercicio Ap4.4.1, para que tenga un fuente modular, siguiente

Ejercicios propuestos

(Las clases Hardware e Imagen no cambian).

j.
.comprobarColisiones();
j.dibujarElementos();
j.pausaFotograma();
} while (!j.partidaTerminada());

Introduccin a la programacin con C#, por Nacho Cabanes

void dibujarElementos()
{
h.BorrarPantallaOculta();

el color que nos apetezca, desde el mtodo "dibujarElementos":

Revisin 0.99zz Pgina 412

Y escribiremos el texto que nos interese, en las coordenadas que queramos y con

void inicializar()
{
h = new Hardware(800, 600, 24, pantallaCompleta);
img = new Imagen("personaje.bmp", 50, 50);
letra = new Fuente("FreeSansBold.ttf", 18);
x = 400;
y = 300;
}

letra (con el tamao que deseemos) dentro del "inicializar":

Y ya lo podemos usar desde nuestro juego. Por una parte, cargaremos el tipo de

Sdl.SDL_BlitSurface(textoComoImagen, ref origen,


pantallaOculta, ref dest);

Sdl.SDL_Rect origen = new Sdl.SDL_Rect(0, 0,


anchoPantalla, altoPantalla);
Sdl.SDL_Rect dest = new Sdl.SDL_Rect(x, y,
anchoPantalla, altoPantalla);

public void EscribirTextoOculta(string texto,


short x, short y, byte r, byte g, byte b, Fuente fuente)
{
Sdl.SDL_Color color = new Sdl.SDL_Color(r, g, b);
IntPtr textoComoImagen = SdlTtf.TTF_RenderText_Solid(
fuente.GetPuntero(), texto, color);
if (textoComoImagen == IntPtr.Zero)
Environment.Exit(5);

incluirla dentro de un rectngulo y volcarlo a otro rectngulo en la pantalla oculta:

nosotros lo pasos que son necesarios en SDL: crear una imagen a partir del texto,

Y en la clase Hardware aadiremos un mtodo EscribirTextoOculta, que d por

public IntPtr GetPuntero()


{
return tipoDeLetra;
}

tipoDeLetra = SdlTtf.TTF_OpenFont(nombreFichero, tamanyo);


if (tipoDeLetra == IntPtr.Zero)
{
System.Console.WriteLine("Tipo de letra inexistente!");
Environment.Exit(2);
}

Introduccin a la programacin con C#, por Nacho Cabanes

public bool ColisionCon(Imagen i)


{
if ((x + ancho > i.x)
&& (x < i.x + i.ancho)
&& (y + alto > i.y)
&& (y < i.y + i.alto))
return true;
else
return false;
}

la clase Imagen que compruebe colisiones con otra imagen, as:

Revisin 0.99zz Pgina 413

Lo mismo ocurrir con las coordenadas Y. Entonces, podemos crear un mtodo en

posX1+anchura1. Si est ms a la izquierda, estar entre posX1-anchura2 y posX1.

rectngulo 1 (azul), entonces su posicin X (posX2) debe estar entre posX1 y

el que ocupa la otra: si el rectngulo 2 (verde) est ms a la derecha que el

Deberemos comprobar si el rectngulo que ocupa una imagen se superpone con

misma posicin.

cada elemento, porque pueden solaparse aunque no estn exactamente en la

vida si nos toca el enemigo o un disparo, etc. No basta con comparar la X y la Y de

En cualquier juego habr que comprobar colisiones: recoger premios, perder una

Ap4.7. Colisiones simples

pantalla (que, por ahora, siempre ser cero).

(Ap4.6.1) Ampla el ejercicio Ap4.5.1, para que muestre una "puntuacin" en

Ejercicios propuestos

h.
.DibujarImagenOculta(img);
h.EscribirTextoOculta("Texto de ejemplo",
200, 100, // Coordenadas
255, 0, 0, // Color: rojo
letra);
h.VisualizarOculta();

Introduccin a la programacin con C#, por Nacho Cabanes

public class Juego


{
bool pantallaCompleta = false;
Hardware h;
Imagen imgPersonaje, imgEnemigo, imgPremio;

using Tao.Sdl;
using System; // Para IntPtr (puntero: imgenes, etc)

// sdl06.cs
// Sexto acercamiento a SDL: colisiones
// Introduccin a C#, por Nacho Cabanes

El fuente completo podra ser as:

if ((yEnemigo < 10) || (yEnemigo > 550))


velocYEnemigo = (short)(-velocYEnemigo);

if ((xEnemigo < 10) || (xEnemigo > 750))


velocXEnemigo = (short) (-velocXEnemigo);

xEnemigo += velocXEnemigo;
yEnemigo += velocYEnemigo;
imgEnemigo.MoverA(xEnemigo, yEnemigo);

alcance:

Revisin 0.99zz Pgina 414

cambiando el signo de su velocidad (de positiva a negativa, o viceversa) cuando los

su posicin. Y podemos hacer que "rebote" en los extremos de la pantalla,

posicin, su velocidad, de modo que el mtodo "MoverElementos" vaya alterando

Para que el enemigo se mueva "por s mismo", podemos indicar, adems de su

if (imgPersonaje.ColisionCon(imgPremio))
{
puntos += 10;
xPremio = (short)generadorAzar.Next(750);
yPremio = (short)generadorAzar.Next(550);
imgPremio.MoverA(xPremio, yPremio);
}

posicin distinta de la pantalla:

O bien, que al tocar un premio obtengamos puntos y ste se recoloque en una

if (imgPersonaje.ColisionCon(imgEnemigo))
{
terminado = true;
}

partida:

ver si un enemigo toca a nuestro personaje, para que en ese momento acabe la

Ahora podemos comprobar si dos imgenes se solapan. Por ejemplo, podemos

Introduccin a la programacin con C#, por Nacho Cabanes

// Si toca el enemigo: acab la partida


if (imgPersonaje.ColisionCon(imgEnemigo))
{
terminado = true;
}

void comprobarColisiones()
{
// Si toca el premio: puntos y nuevo premio
if (imgPersonaje.ColisionCon(imgPremio))
{
puntos += 10;
xPremio = (short)generadorAzar.Next(750);
yPremio = (short)generadorAzar.Next(550);
imgPremio.MoverA(xPremio, yPremio);
}

void comprobarTeclas()
{
if (h.TeclaPulsada(Hardware.TECLA_ARR))
y -= 4;
if (h.TeclaPulsada(Hardware.TECLA_ABA))
y += 4;
if (h.TeclaPulsada(Hardware.TECLA_IZQ))
x -= 4;
if (h.TeclaPulsada(Hardware.TECLA_DER))
x += 4;
if (h.TeclaPulsada(Hardware.TECLA_ESC))
terminado = true;
imgPersonaje.MoverA(x, y);
}

void inicializar()
{
h = new Hardware(800, 600, 24, pantallaCompleta);
imgPersonaje = new Imagen("personaje.bmp", 32, 30);
imgEnemigo = new Imagen("enemigo.bmp", 36, 42);
imgPremio = new Imagen("premio.bmp", 36, 14);
letra = new Fuente("FreeSansBold.ttf", 18);
generadorAzar = new Random();
x = 400; y = 300;
xEnemigo = 100; yEnemigo = 100;
velocXEnemigo = 3; velocYEnemigo = -3;
xPremio = (short) generadorAzar.Next(750);
yPremio = (short) generadorAzar.Next(550);
imgPremio.MoverA(xPremio, yPremio);
puntos = 0;
}

Fuente letra;
;
bool terminado = false;
short x, y;
short xEnemigo, yEnemigo, velocXEnemigo, velocYEnemigo;
short xPremio, yPremio;
int puntos;
Random generadorAzar;

Revisin 0.99zz Pgina 415

Introduccin a la programacin con C#, por Nacho Cabanes

// Bucle de juego
do
{
j.comprobarTeclas();
j.moverElementos();
j.comprobarColisiones();
j.dibujarElementos();
j.pausaFotograma();
} while (!j.partidaTerminada());

public static void Main()


{
Juego j = new Juego();
j.inicializar();

bool partidaTerminada()
{
return terminado;
}

void pausaFotograma()
{
// Esperamos 20 ms
h.Pausa(20);
}

void dibujarElementos()
{
h.BorrarPantallaOculta();
h.DibujarImagenOculta(imgPersonaje);
h.DibujarImagenOculta(imgPremio);
h.DibujarImagenOculta(imgEnemigo);
h.EscribirTextoOculta("Puntos: "+puntos,
200, 100, // Coordenadas
255, 0, 0, // Color: rojo
letra);
h.VisualizarOculta();
}

void moverElementos(()
{
xEnemigo += velocXEnemigo;
yEnemigo += velocYEnemigo;
imgEnemigo.MoverA(xEnemigo, yEnemigo);
// Para que rebote en los extremos de la pantalla
if ((xEnemigo < 10) || (xEnemigo > 750))
velocXEnemigo = (short) (-velocXEnemigo);
if ((yEnemigo < 10) || (yEnemigo > 550))
velocYEnemigo = (short)(-velocYEnemigo);
}

Revisin 0.99zz Pgina 416

Introduccin a la programacin con C#, por Nacho Cabanes

imgenes JPG).
Revisin 0.99zz Pgina 417

(para imgenes PNG), zlib1.dll (auxiliar para el anterior) y jpeg.dll (si queremos usar

Los nuevos ficheros que necesitamos son: SDL_image.dll (el principal), libpng13.dll

en el programa.

tenemos que incluir unos cuantos ficheros DLL ms y hacer un pequeo cambio

imgenes en formatos ms modernos y ms optimizados, como JPG o PNG, slo

avanzadas, como la transparencia (aunque se podra imitar). Si queremos usar

Las imgenes BMP ocupan mucho espacio, y no permiten caractersticas

Ap4.8. Imgenes PNG y JPG

guardar en fichero y se leer al principio de cada nueva partida.

(Ap4.7.7) Aade al ejercicio Ap4.7.6 un tabla de mejores puntuaciones, que se

ms rpido (puedes conseguirlo reduciendo la pausa de final del bucle de juego).

aparecer un nuevo obstculo, y en cada nuevo nivel, el movimiento ser un poco

(Ap4.7.6) Aade dificultad creciente al ejercicio Ap4.7.5: cada cierto tiempo

cantidad de premios y de obstculos.

vez de una; si se recogen todos los premios, comenzar un nuevo nivel, con mayor

(Ap4.7.5) Mejora la jugabilidad del ejercicio Ap4.7.4: el jugador tendr 3 vidas, en

partida terminar.

har ms larga en un segmento. Si la "cabeza" de la serpiente toca la cola, la

formada por varios segmentos; cada vez que se recoga un premio, la serpiente se

(Ap4.7.4) Ampla el ejercicio Ap4.7.3, para que el jugador sea una serpiente,

choque con un obstculo (y entonces acabar la partida).

movindose hasta que se pulse otra flecha (y entonces cambiar de direccin) o

jugador no se mover slo cuando se pulse una flecha, sino que continuar

(Ap4.7.3) Ampla el ejercicio Ap4.7.2, para que el movimiento sea continuo: el

partida.

una serie de obstculos, que "nos maten": si el personaje los toca, acabar la

(Ap4.7.2) Ampla el ejercicio Ap4.7.1, para que haya un "margen de la pantalla" y

obtendrn 10 puntos. Al recoger todos los premios, acabar la partida.

posiciones al azar. Cada vez que se toque un premio, ste desparecer y se

(Ap4.7.1) Ampla el esqueleto Ap4.6.1, para que muestre varios premios en

Ejercicios propuestos

http://www.nachocabanes.com/fich/descargar.php?nombre=SdlClases04.zip

desde

Puedes descargar todo el proyecto, incluyendo fuentes, imgenes y ficheros DLL

Introduccin a la programacin con C#, por Nacho Cabanes

(y este cambio slo afectara al

la animacin.
Revisin 0.99zz Pgina 418

existir un "SiguienteFotograma", que pase a mostrar la siguiente imagen de

direccin en que se est moviendo el personaje. Entre sus mtodos, podra

una secuencia de imgenes, o incluso varias secuencias distintas, segn la

extensin del concepto de imagen: un elemento grfico podr contener

manejo, podemos crear una clase ElementoGrfico, de modo que sea una

fotogramas, podemos usar un array de imgenes. Para simplificar su

Si queremos que una imagen sea "animada", es decir, formada por varios

incluir tambin Sdl_Gfx.dll, con funciones como SdlGfx.rectangleRGBA.

Si queremos dibujar lneas, puntos, rectngulos, crculos o elipses, podemos

reproducir un sonido una vez, o varias, o de forma ininterrumpida.

SDL_mixer.dll, que nos permitir usar SdlMixer.Mix_PlayMusic para

como MP3 o MID, podemos aadir a nuestra carpeta el fichero

formato WAV, sin comprimir, pero si preferimos formatos ms compactos

Tambin permite reproduccin de sonidos. La biblioteca bsica soporta el

para comprobar los botones.

para ver si se ha inclinado en alguno de los ejes y Sdl.SDL_JoystickGetButton

dispositivos similar, como un volante) se usara Sdl.SDL_JoystickGetAxis

Sdl.SDL_GetMouseState y para el joystick (o gamepad, o cualquier otro

uso del ratn y de joystick/gamepad. Para ver el estado del ratn se usara

SDL, al igual que la mayora de bibliotecas de juegos, tiene soporte para el

profundizar:

que el lector pueda intentar implementarlas o, al menos, saber por dnde podra

que muchas cosas quedan en el tintero. Aun as, vamos a mencionar algunas, para

Este texto no pretende ser un curso de programacin de videojuegos, de modo

Ap4.9. Por dnde seguir?

de las que se pueda ver dicho fondo.

de la pantalla, y que los premios sean imgenes PNG con transparencia, a travs

(Ap4.8.1) Mejora el juego de la serpiente, para que tenga una imagen JPG de fondo

Ejercicios propuestos

imagen = SdlImage.IMG_Load("personaje.png");

constructor de la clase Imagen):

Sdl.SDL_LoadBMP sino SdlImage.IMG_Load

En el fuente, slo cambiara la orden de cargar cada imagen, que no utilizara

Introduccin a la programacin con C#, por Nacho Cabanes

de mantener.

responsabilidades ms delimitadas, y el programa resultante es ms fcil

disparo, pantallaDeFondo, pantallaDeAyuda. As, cada clase tiene unas

una serie de clases que se interrelacionan: juego, personaje, enemigo,

Revisin 0.99zz Pgina 419

Main), Presentacion, PantallaAyuda, PantallaCreditos, Nivel, Personaje, Premio.

repartida entre varias clases que colaborar: JuegoSerpiente (que contendr el

(Ap4.9.1) Crea una versin del juego de la serpiente en la que la lgica est

aunque Visual Studio s permitira los acentos-):


Revisin 0.99zz Pgina 420

espacios ni acentos, que suelen ser caracteres no vlidos en un identificador -

nosotros podramos cambiar por "AplicacionVentanas1" (como siempre, sin

y como nombre se nos propondr algo como "WindowsFormsApplication1", que

as como su nombre. En nuestro caso, ser una "Aplicacin de Windows Forms",

Al elegir un "Nuevo proyecto", se nos preguntar de qu tipo queremos que sea,

proyecto:

ltimos proyectos que hemos realizado y nos da la posibilidad de crear un nuevo

Cuando lanzamos Visual Studio 2010, aparece una pantalla que nos muestra los

ms, o bien procesador de doble ncleo), vamos a centrarnos en su manejo.

"moderno" (ms de 1 Gb de memoria RAM, procesador de un ncleo de 2 Ghz o

es gratis para uso personal y se mueve con una soltura razonable en un ordenador

manejo muy similar a ste. Aun as, dado que la versin Express de Visual Studio

SharpDevelop necesita un ordenador menos potente que Visual Studio y tiene un

A medida que el juego crece, puede ser interesante descomponerlo como

siguiente paso: if (cayendo && posibleBajar) y+=2;

editor visual, como Visual Studio o SharpDevelop.

La forma ms cmoda de conseguirlo es usando herramientas que incluyan un

mens botones, listas desplegables, etc.

bsicamente una comprobacin de una o dos condiciones que dan lugar al

Ese caso se tratara dentro del mtodo "MoverElementos" y sera

suponer que se siga moviendo aunque el usuario no pulse ninguna tecla.

Algunos movimientos repetitivos del personaje (caer, saltar) pueden

imgenes.

En C# podemos crear con una cierta facilidad programas en entornos grficos, con

Ap5.1. Creacin de formularios, botones y etiquetas

comprobaramos antes si supondra colisionar con alguna de esas

Para saber si es posible moverse a una cierta posicin de la pantalla o no,

Apnd ice 5. Contacto con los entornos grficos

Introduccin a la programacin con C#, por Nacho Cabanes

plataformas clsicos se pueden realizar mediante un array de imgenes.

Los fondos repetitivos que aparecen en la mayora de juegos de

Ejercicios propuestos

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 421

mens y listas desplegables. Ambos los podemos aadir desde el men "Ver":

herramientas", que nos permitir aadir componentes visuales, como botones,

por las distintas clases que forman nuestro proyecto. La segunda es el "Cuadro de

auxiliares. La primera es el "Explorador de soluciones", que nos permitir pasear

Si nuestra pantalla est as de vaca, nos interesar tener un par de herramientas

Nos aparecer un formulario ("una ventana") vaco:

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 422

izquierdo) y luego clic dentro del formulario, para que aparezca un botn en esa

Hacemos clic en el componente Button del Cuadro de Herramientas (panel

de la etiqueta cuando pulsemos el botn.

una etiqueta de texto (Label), para hacer un primer programa que cambie el texto

Como primer ejemplo, vamos a aadir a nuestro formulario un botn (Button) y

De modo que ahora nuestra pantalla debera ser algo as:

Introduccin a la programacin con C#, por Nacho Cabanes

por

crear

un

nuevo

proyecto

llamado

feo

y,

posiblemente,

con

los

componentes

(por

ejemplo)

Revisin 0.99zz Pgina 423

Revisin 0.99zz Pgina 424

avisarnos de que en ese momento estn alineados varios componentes:

herramientas:

de ellos con el ratn, cuando lo movamos es fcil que aparezcan unas rayas para

comprobar que funciona. Pulsamos el botn de "Iniciar depuracin" en la barra de

Vamos a comenzar por alinear los componentes. Si pinchamos y arrastramos uno

desalineados:

ser

para que se calcule dicho resultado. El resultado todava

texto) para los datos y el resultado, y tambin un botn

explicativos, tres TextBox (casillas de introduccin de

En el formulario, aadiremos dos Label para incluir textos

de Windows Forms".

"AplicacionVentanas2", que tambin ser una "Aplicacin

Comenzamos

poco ms la apariencia.

un programa que calcule y muestre la suma de dos nmeros, y cuidaremos un

cambiado el texto del botn, ni su tamao, ni el tipo de letra. Ahora vamos a hacer

Hemos visto cmo colocar un botn y una casilla de texto, pero no hemos

Ap5.2. Cambios de apariencia. Casillas de texto para


sumar dos nmeros

ayude a entender mejor el funcionamiento del entorno.

Ahora vamos a crear un segundo proyecto, un poco ms elaborado y que nos

no est guardado.

memoria", de modo que nuestro programa quiz todava

algunas versiones de Visual Studio permiten "compilar a

Antes de seguir, deberamos grabar los cambios, porque

pulsamos el botn, cambiar el texto de la etiqueta:

Y nos aparecer nuestra ventana, lista para probar. Si

Introduccin a la programacin con C#, por Nacho Cabanes

Antes de ver con ms detalle por qu ocurre todo esto y mejorarlo, vamos a

private void button1_Click(object sender, EventArgs e)


{
label1.Text = "Hola";
}

as:

("button1_Click"). En nuestro caso, simplemente ser cambiar el texto del "label",

En ese hueco indicaremos lo que debe ocurrir cuando se pulse el botn

de programa que podemos rellenar:

botn. Para eso, hacemos doble clic sobre dicho botn, y aparecer un esqueleto

Ahora vamos a hacer que nuestro programa responda a un clic del ratn sobre el

ventana debera estar quedando as:

etiqueta de teto, y luego clic en cualquier punto de nuestro formulario. Nuestra

posicin. De igual modo, hacemos clic en Label para indicar que queremos una

Introduccin a la programacin con C#, por Nacho Cabanes

Text, el texto que muestra un elemento.


ForeColor, el color con el que se muestra el componente.
BackColor, el color de fondo.
TextAlign, para indicar la alineacin del texto (y poder centrarlo, por

x
x
x
x

inicialmente con el ratn).


Size, el tamao (ancho y alto, que tambin se puede ajustar inicialmente

con componentes X e Y:

con el ratn, pero tambin tenemos una propiedad "Size",

podemos cambiar simplemente pinchando y arrastrando

Revisin 0.99zz Pgina 425

cambiar el texto de todos (incluyendo el "nombre de la ventana"):

La anchura de las casillas de texto y el tamao del botn los

ReadOnly, para poder hacer que un TextBox sea slo de lectura y no se

componente muestra en pantalla. Haciendo clic en cada uno de ellos, podemos

El formulario se llamar frmSumador.


La casilla del resultado usar el mismo tipo de letra, pero en negrita (Bold).

x
x

pestaa que hay en la parte superior:


Revisin 0.99zz Pgina 426

Podemos volver a la vista de diseo en cualquier momento, haciendo clic en la

private void btCalcular_Click(object sender, EventArgs e)


{
tbResultado.Text = Convert.ToString( Convert.ToInt32(tbNumero1.Text)
+ Convert.ToInt32(tbNumero2.Text) );
}

almacenar el resultado:

convertir a int32 para poder sumar, y luego volver a convertir a string para

otros TextBox. Eso s, como las casillas de texto contienen cadenas, habr que

doble clic sobre l. En este caso, el texto de tbResultado ser la suma de los de los

Nuevamente, para hacer que se calcule el resultado al pulsar el botn, hacemos

Adems, ser slo de lectura.

El botn, en vez de Button1, pasar a llamarse btCalcular.

se llamarn tbNumero1, tbNumero2 y tbResultado.

De igual modo, las casilla de texto, en vez de textBox1, textBox2, y textBox3

lbNumero2.

Las etiquetas de texto, en vez de label1 y label2, se llamarn lbNumero1 y

En nuestro caso, vamos a hacer los siguientes cambios:

pueda modificar su contenido.

con el ratn).
Font, el tipo de letra.

men "Ver". Ah tenemos la propiedad "Text", que es el texto que cada

obtener al pulsar el botn derecho sobre uno de los componentes o desde el

Location, la posicin en que se encuentra (que podemos ajustar

cambiar el texto de un Label desde cdigo, pero tambin podemos hacerlo desde

el diseador visual. Basta con tener la ventana de "Propiedades", que podemos

Enabled, para poder activar o desactivar un elemento.

ejemplo).

Name, el nombre con el que se acceder desde el cdigo.

Algunas de las propiedades son:

Introduccin a la programacin con C#, por Nacho Cabanes

Una vez que estn colocados, vamos a cambiar sus propiedades. Sabemos

Introduccin a la programacin con C#, por Nacho Cabanes

cuando se modifica el texto que contiene un TextBox.


Revisin 0.99zz Pgina 427

una casilla de texto, aparecer el evento "TextChanged", que es el que se lanza

etiquetas de texto el equivalente del nmero actual. Pista: al hacer doble clic sobre

el recuadro de texto se pulse una tecla, se mostrar automticamente en las 3

convertir el nmero a binario, octal y hexadecimal. En vez de eso, cada vez que en

(Ap5.2.4) Haz una variante del programa anterior, que no use un botn para

equivalente de ese nmero en binario, octal y hexadecimal.

decimal). Cada vez que se pulse el botn, se mostrar en las 3 etiquetas de texto el

botn y 3 etiquetas. En el recuadro de texto se escribir un nmero (en sistema

(Ap5.2.3) Un programa que muestre una ventana con un recuadro de texto, un

tambin la resta, la multiplicacin, la divisin y el resto de la divisin.

(Ap5.2.2) Crea una nueva versin del programa, que no solo muestre la suma, sino

lugar de nmeros.

a la derecha y para que no falle si las casillas estn vacas o contienen texto en

(Ap5.2.1) Mejora el ejemplo anterior para que las casillas tengan el texto alineado

Ejercicios propuestos:

propuestos.

Es muy mejorable, pero algunas de las mejoras son parte de los ejercicios

La apariencia del programa, ya en funcionamiento, sera algo como:

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 428

Y la tercera variante permite indicar adems el que ser el botn por defecto:

MessageBox.Show("Ese nmero no es vlido", "Aviso",


MessageBoxButtons.OK, MessageBoxIcon.Exclamation);

iconos de aviso:

La segunda variante es indicar adems qu botones queremos mostrar, y qu

MessageBox.
.Show("Ese nmero no es vlido", "Aviso");

dado:

podemos mostrar un cierto texto de aviso en una ventana que tenga un ttulo

posibles, segn el nmero de parmetros que queramos utilizar. Por ejemplo,

stas se pueden crear llamando a "MessageBox.Show", que tiene varias sintaxis

Una forma alternativa y sencilla de conseguirlo es usando "ventanas de mensaje".

pretende este texto.

un programa basado en mltiples ventanas, pero eso queda ms all de lo que

mensaje de aviso, o pedir una confirmacin al usuario. Para ello podramos crear

En una aplicacin basada en ventanas, tpicamente tendremos que mostrar algn

Ap5.3. Usando ventanas predefinidas

Introduccin a la programacin con C#, por Nacho Cabanes

Cambiamos el "Text" de la etiqueta para que muestre


"Nombre y apellidos", y cambiamos la propiedad
"ReadOnly" de la casilla de texto para que sea "true"
(verdadero), de modo que no se pueda escribir en esa
casilla. Tambin podemos cambiar el color de la casilla,
para que sea ms evidente que "no es una casilla
normal". Visual Studio 2010 lo hace automticamente,
pero si un entorno ms antiguuo no lo hace por nosotros, podramos pedir que
fuera gris, como el resto de la ventana. Para eso, cambiamos su propiedad
BackColor (color de fondo). Es recomendable no usar colores prefijados, como el
"gris", sino colores de la paleta de Windows, de modo que los elementos cambien
correctamente si el usuario elige otra combinacin de colores para el sistema

(Aceptar y Cancelar), AbortRetryIgnore (Anular, Reintentar y Omitir),

YesNoCancel (S, No y Cancelar), YesNo (S y No), RetryCancel (Reintentar y

Cancelar).

Los iconos (MessageBoxIcon) pueden ser: None (ninguno), Hand (X blanca

en un crculo con fondo rojo), Question (signo de interrogacin en un

crculo, no recomendado actualmente), Exclamation (signo de exclamacin

en un tringulo con fondo amarillo), Asterisk (letra 'i' minscula en un

crculo), Stop (X blanca en un crculo con fondo rojo), Error (X blanca en un

crculo con fondo rojo), Warning (signo de exclamacin en un tringulo con

fondo amarillo), Information (letra 'i' minscula en un crculo).

Los botones por defecto (MessageBoxDefaultButton) pueden ser: Button1

(el primero), Button2 (el segundo), Button3 (el tercero).

casillas estn vacas o contienen texto en lugar de nmeros.

Revisin 0.99zz Pgina 429

(Ap5.3.1) Mejora el ejercicio Ap5.2.1, para que muestre un mensaje de aviso si las

Ejercicios propuestos:

elemento.

de introduccin de datos desde el editor visual o mediante cdigo, elemento por

La apariencia de nuestra ventana debera ser parecida a sta:

Revisin 0.99zz Pgina 430

"Control".

programacin, como Visual Basic), as que deberamos crear nosotros esa ventana

los controles de Windows), para la casilla de texto, escogeramos tambin el color

predefinida que nos lo permita (s existe un "InputBox" en otros entornos de

operativo. Como el color de fondo de la ventana es "Control" (el color que tengan

texto, y el "Label" que aclarar qu es ese texto.

Los botones (MessageBoxButtons) pueden ser: OK (Aceptar), OKCancel

Comenzamos por crear el "TextBox" que mostrar el

ventana secundaria, en la que s podremos introducir datos.

sino que slo se mostrarn resultados, y un botn que har que aparezca la

Vamos a crear en ella una casilla de texto (TextBox) en la que no se podr escribir,

diseo para crear la que ser la ventana principal de nuestra aplicacin.

Forms", que llamaremos (por ejemplo) "DosVentanas" y entraremos a la vista de

En primer lugar, crearemos un nuevo proyecto, de tipo "Aplicacin de Windows

Vamos a ver los pasos necesarios.

deberemos crear un segundo formulario, y llamarlo desde la ventana principal.

Si queremos una ventana auxiliar, que permita al usuario introducir varios datos,

Ap5.4. Una aplicacin con dos ventanas

Introduccin a la programacin con C#, por Nacho Cabanes

Si queremos que el usuario responda tecleando, no tenemos ninguna ventana

qu botones o iconos queremos mostrar:

Como se ve en estos ejemplos, tenemos algunos valores predefinidos para indicar

MessageBox.
.Show("Seguro que desea continuar?", "Confirma, por favor",
MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation,
MessageBoxDefaultButton.Button1);

Introduccin a la programacin con C#, por Nacho Cabanes

haremos que el botn "Aceptar" cierre la ventana. Lo podemos conseguir con

Windows Forms ", del men "Proyecto":

Revisin 0.99zz Pgina 431

texto (TextBox), con sus etiquetas aclaratorias (Label), y el botn de Aceptar:

Nos aparecer una nueva ventana, en su vista de diseo. Aadimos dos casillas de

y le damos un nombre, por ejemplo "Introduccion.cs":

Llega el momento de aadir el cdigo a nuestro programa. Por una parte,

Para crear el segundo formulario (la ventana auxiliar), usamos la opcin "Agregar

Revisin 0.99zz Pgina 432

void Button1Click(object sender, EventArgs e)


{
ventanaIntro.ShowDialog();
tbNombreApellido.Text = ventanaIntro.GetNombreApellido();

que se haba tecleado en dicha ventana:




permitirnos seguir trabajando en la ventana principal, y despus leemos el valor

secundaria usando ShowDialog, que espera a que se cierre sta antes de

Finalmente, en el suceso Click del botn hacemos que se muestre la ventana

Y la inicializamos al final del constructor:



public MainForm()
{
InitializeComponent();
ventanaIntro = new Introduccion();
}

principal, que represente la ventana auxiliar:



public partial class MainForm : Form
{
Introduccion ventanaIntro;
...

lean los valores al terminar. Para eso, aadimos un atributo en la ventana

Ya slo falta que desde la ventana principal se muestre la ventana secundaria y se

public string GetNombreApellido()


{
return tbNombre.Text + " " + tbApellidos.Text;
}

devolver el nombre y el apellido como parte de una nica cadena de texto, as:

"Get" que devuelva el contenido de estos componentes. Por ejemplo, podemos

podemos hacer que sus componentes sean pblicos, o, mejor, crear un mtodo

Adems, para que desde la ventana principal se puedan leer los datos de sta,

void Button1Click((object sender, EventArgs e)


{
Close();
}

cuerpo de esa funcin, as:

botn (cuando se pulse el ratn sobre l), y aadimos la orden "Close()" en el

doble clic, para que nos aparezca la funcin que se lanzar con el suceso Click del

Introduccin a la programacin con C#, por Nacho Cabanes

Introduccin a la programacin con C#, por Nacho Cabanes

PictureBox, para mostrar una imagen.

ProgressBar, para una barra de progreso.

escoger de una lista desplegable.

ComboBox para permitir introducir un valor o

ListBox, para mostrar una lista de valores, y

puede elegir una de dichas opciones.

varias opciones, y RadioButton, cuando slo se

CheckBox, para permitir al usuario escoger entre

ser frecuentes y razonablemente sencillos de utilizar:

quedan a la curiosidad del lector, cabe mencionar, por

Entre los otros muchos componentes existentes, y que

consola.

alternativa a la entrada y salida convencional a travs de

dominar todos los componentes existentes, sino dar una

los que hemos visto, pero en esto texto no se pretende

Por supuesto, hay muchos ms controles visuales que

Ap5.5. Otros componentes visuales

datos de ficheros" (ejemplo 04_06a).

(Ap5.4.3) Crea una versin "con ventanas" de la "base de

texto.

Revisin 0.99zz Pgina 433

puede introducir frases. Todas estas frases se irn guardando en un fichero de

(Ap5.4.2) Crea un programa que muestre una casilla de texto en la que el usuario

factores primos, usando ventanas.

(Ap5.4.1) Crea un programa que descomponga un nmero como producto de sus

Ejercicios propuestos

El resultado sera una secuencia como esta:

Introduccin a la programacin con C#, por Nacho Cabanes

el sistema de ficheros, etc.

vistas previas de impresin, crear temporizadores, monitorizar cambios en

componentes semiautomticos para acceder a bases de datos, mostrar

realizar otras muchas tareas de mayor complejidad, como crear

por carpetas, la de elegir un color, la de elegir un tipo de letra), as como

dilogo estndar (como la de abrir un fichero, la de guardarlo, la de navegar

elementos, incluir mens y barras de herramientas, mostrar ventanas de

Tambin, dentro de otras categoras, podemos crear paneles para agrupar

recorriendo sus "Lines".

lneas. En ese caso, su contenido no se obtendra con "Text", sino

TextBox tiene una propiedad "MultiLine", para indicar si es de mltiples

// Liberamos la memoria que habamos reservado


contornoRojo.Dispose();
rellenoAzul.Dispose();
ventanaGrafica.Dispose();

Revisin 0.99zz Pgina 434

// Dibujamos
ventanaGrafica.DrawLine(contornoRojo, 200, 100, 300, 400);
ventanaGrafica.FillEllipse(rellenoAzul, new Rectangle(0, 0, 200, 300));

void Button1Click(
(object sender, EventArgs e)
{
// Creamos la pluma, el relleno y la ventana grfica
System.Drawing.Pen contornoRojo = new System.Drawing.Pen(
System.Drawing.Color.Red);
System.Drawing.SolidBrush rellenoAzul = new System.Drawing.SolidBrush(
System.Drawing.Color.Blue);
System.Drawing.Graphics ventanaGrafica;
ventanaGrafica = this.CreateGraphics();

del formulario podra ser as:

ejemplo que dibujara una lnea roja y una elipse azul cuando pulsemos un botn

contornos) y las "brochas" ("Brush", para los rellenos) que queramos usar. Un

nuestro formulario. Deberemos preparar tambin las "plumas" ("Pen", para los

posibilidades de "System.Drawing" para crear una ventana grfica dentro de

dibujando lneas, crculos y dems figuras bsicas. En efecto, podemos usar las

tener la posibilidad de trabajar en "modo grfico" desde dentro de Windows,

Windows es un entorno grfico, por lo que se podra suponer que deberamos

Ap5.6. Dibujando con Windows Forms

Introduccin a la programacin con C#, por Nacho Cabanes

DrawEllipse, para dibujar una elipse, a partir del rectngulo que la contiene.

DrawIcon, para dibujar una imagen representada por un icono (Icon).

DrawImage, para mostrar una imagen (Image).

DrawLine, para una lnea.

DrawPolygon, para un polgono, a partir de un array de puntos.

DrawRectangle, para un rectngulo.

DrawString, para mostar una cadena de texto.

FillEllipse, para rellenar el interior de una elipse.

FillPolygon, para rellenar el interior de un polgono.

FillRectangle, para rellenar el interior de un rectngulo.

patbulo".
Revisin 0.99zz Pgina 435

Windows Forms, en la que, a medida que el usuario falle, se vaya "dibujando un

(Ap5.6.1) Crea una versin del "juego del ahorcado" (ejercicio 5.9.1.2) basada en

Ejercicios propuestos

http://msdn.microsoft.com/es-es/library/system.drawing.graphics_methods.aspx

(MSDN), por ejemplo en la pgina

Se puede encontrar ms detalles sobre la clase Graphics en la referencia en lnea

la misma que el fuente), y puede estar en formato BMP, GIF, PNG, JPG o TIFF.

Esta imagen debera estar en la carpeta del programa ejecutable (que quiz no sea

void Button2Click(
(object sender, EventArgs e)
{
Graphics ventanaGrafica = this.CreateGraphics();
Image imagen = new Bitmap("MiImagen.png");
ventanaGrafica.DrawImage(imagen,20,20,100,90);
}

Por otra parte, un ejemplo de cmo mostrar una imagen predefinida podra ser:

DrawCurve, para una curva.

puntos.

DrawClosedCurve, para una curva spline cerrada, a partir de un array de

(estructuras Point).

DrawBezier, para una curva spline de Bzier definida por cuatro puntos

DrawArc, para dibujar un arco.

para realizar dibujos sencillos son:

clase Graphics. Algunos de los mtodos que sta contiene y que pueden ser tiles

Los mtodos para dibujar lneas, rectngulos, elipses, curvas, etc. son parte de la

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 436

Introduccin a la programacin con C#, por Nacho Cabanes

Revisin 0.99zz Pgina 437

ejercicios propuestos en los apartados 4.4.8, 5.5 (2), 5.7 (2), 5.9.1.

comparaciones de cadenas y otro sobre mtodos de ordenacin. Aadidos

0.92, de 22-nov-09. Ampliado el tema 4 con un apartado sobre

SharpDevelop y cmo crear programas a partir de varios fuentes.

(por ejemplo, 2.1, 2.2, 3.1.2, 3.1.9, 4.1.4). Aadido el apartado 6.13 sobre

0.93, de 10-mar-10. Algunas correcciones menores en algunos apartados

Express y 2010 Express).

sobre la instalacin y uso bsico de Visual Studio (en sus versiones 2008

(por ejemplo, 6.3). Aadido el apartado 8.13 sobre Tao.SDL y el apndice 4

0.94, de 07-may-10. Algunas correcciones menores en algunos apartados

propuestos al apartado 4.1 y otros dos al 4.4.3

convertir un nmero a binario o hexadecimal. Aadidos tres ejercicios

datos con SQLite en 10.10. Ampliado el apartado 2.2.3 para ver cmo

expresiones regulares e incluido un segundo ejemplo de acceso a bases de

pgina web y comunicar dos ordenadores). Ampliado el apartado 9.6 sobre

Aadido el apartado 10.12 sobre servicios de red (cmo descargar una

que el apartado sobre "otras bibliotecas" pase a ser el ltimo de esos tres.

0.95, de 01-jun-10. Recolocados (en distinto orden) los temas 8, 9, 10, para

cambios entre versiones (este apartado) pasa al final del texto.

apartado sobre expresiones regulares, al que faltaba un prrafo. La lista de

temas. Aadidos 4 apartados sobre SDL (10.11.3 a 10.11.6). Completado el

carga terica al principio. Ligeramente ampliado algn apartado de estos

0.96, de 03-oct-10. Intercambiados los temas 2 y 3, para que no haya mucha

de Get y Set, de constructores que se basan en otros, y de la palabra "this".

ejemplo 14b, sobre el uso de "switch". Ampliado el apartado 6, para hablar

hablaban de ejemplos cuya numeracin haba cambiado. Incluido el

0.97, de 01-feb-11. Corregida alguna errata en referencias del tema 2, que

Errata en "operaciones de bits" (suma lgica).

0.98, de abr-11. Lanzamiento de excepciones. Resultado de un MessageBox.

algunos ms sobre Windows Forms.

acceso a bases de datos con SQLite. Muchos ms detalles sobre SDL y

ms ejercicios propuestos. Incluidos apartados sobre persistencia y sobre

0.99, de 30-dic-12. La mayora de temas estn ligeramente ampliados y con

apartados sobre SDL y Windows Forms pasan a ser apndices.

ampliados, con ms ejemplos y con ms ejercicios propuestos. Los

0.99zz, de 22-ene-15. Nueva revisin, con la mayora de temas ligeramente

Revisiones de este texto

Introduccin a la programacin con C#, por Nacho Cabanes

distribucin muy limitada).

Revisin 0.99zz Pgina 438

versin completa; ha habido 4 versiones previas, incompletas, de

Programacin en Lenguajes Estructurados en el I.E.S. San Vicente. (Primera

0.90, de 24-may-09, como texto de apoyo para los alumnos de

(como el 4.4.6 y el 8.1).

4.1.2, 4.3.2, 4.5 y 5.10) y algunos apartados con su contenido ampliado

(en los apartados 1.2, 1.4, 1.8, 3.1.4, 3.1.5, 3.1.9, 3.2.1, 3.2.2, 3.2.3, 4.1.1,

0.91, de 19-nov-09, que incluye unos 30 ejercicios propuestos adicionales

Introduccin a la programacin con C#, por Nacho Cabanes

&

?, 58

: (goto), 82

/, 34
/**, 382
//, 42
///, 382
/=, 96

.Net, 13

,, 364

*, 34
*=, 96

&, 356
& (direccin de una variable, 330
&&, 52

%, 34
%=, 96

#, 104

0x (prefijo), 106

>, 49
>>, 356

=, 37
-=, 96
==, 49

<, 49
<<, 356
<> (Generics), 326

+, 34
++, 68, 94
+=, 96

~, 214, 356

|, 356
||, 52

{ y }, 17, 48

^, 356

\, 109

--, 94

[,] (arrays), 123


[] (arrays), 113
[Serializable], 275

-, 34

!, 52
!=, 49

@, 109, 383

ndice alfabtico

>

<

Revisin 0.99zz Pgina 439

Introduccin a la programacin con C#, por Nacho Cabanes

BackgroundColor, 340
bajo nivel, 10
base, 230
Base numrica, 105
Bases de datos, 292
Bases de datos con SQLite, 289
BaseStream, 262
BASIC, 9
Begin (SeekOrigin), 259
Binario, 105, 391
BinaryReader, 261
BinarySearch, 318
BinaryWriter, 269
bit, 386
Bloque de programa, 70
BMP (tipo de fichero), 263
bool, 111
Booleanos, 111, 121
Borrar en un array, 118
borrar la pantalla, 340
break, 60
bucle de juego, 409
bucle sin fin, 69
Bucles, 63

Abs, 172
Acceso aleatorio, 253
Acceso secuencial, 253
Acos, 172
Add (ArrayList), 316
AddDays, 337
Al azar, nmeros, 170
Aleatorio, acceso, 253
Aleatorios, nmeros, 170
algoritmo, 14
alto nivel, 9
and, 356
Aadir a un array, 118
Aadir a un fichero, 247
Apilar, 312
Aplicacin Windows, 420
Append, 271
AppendText, 247
Arco coseno, 172
Arco seno, 172
Arco tangente, 172
args, 178
Argumentos de un programa, 177
Aritmtica de punteros, 334
array, 113
Array de objetos, 221
ArrayList, 316
Arrays bidimensionales, 122
Arrays de struct, 126
arreglo, 113
ASCII, 387, 389, 400, 420
Asignacin de valores, 37
Asignacin en un "if", 54
asignaciones mltiples, 96
Asin, 172
Atan, 172
Atan2, 172
azar, 170

Ch

Revisin 0.99zz Pgina 440

cifrar mensajes, 358


Cifras decimales, 103
Cifras significativas, 99
class, 18
Clear, 340
Close, 243
cdigo mquina, 9
Cdigos de formato, 103
Cola, 314
Colisiones entre imgenes, 413
Color de texto, 340
Coma (operador, for), 364
Coma fija, 97
Coma flotante, 97
Comentarios
recomendaciones, 378
Comentarios de documentacin, 381
Comillas (escribir), 109
Comparacin de cadenas, 137
CompareTo, 137
compiladores, 12
Compilar con mono, 31
Complemento, 356
Complemento a 1, 398
Complemento a 2, 398
Consola, 340
Console, 17, 340
ConsoleKeyInfo, 341
constantes, 358
constructor, 212
Contador, 65
Contains, 132, 313, 320
Contains (Hash), 321
ContainsKey, 321
ContainsValue, 320
continue, 77
Convert, 93, 100
Convert.ToInt32, 43
Convertir a binario, 105

char, 60, 107

C, 10
C#, 10
Cadena modificable, 138
Cadenas de caracteres, 128
Cadenas de texto, 110
Cambio de base, 105
Campo (bases de datos), 290
Carcter, 107
Carpetas, 248
case, 60
Caso contrario, 50
catch, 88, 250

Bucles anidados, 69
bug, 369
burbuja, 145
Buscar en un array, 118
Button, 422
byte, 93, 385

Introduccin a la programacin con C#, por Nacho Cabanes

E, 172
ejecutable, 12
elevado a, 172
else, 50
Encolar, 314
End (SeekOrigin), 259
Enqueue, 314
ensamblador, 10
ensambladores, 11
enteros negativos, 397
Entorno, 347, 348
enum, 358
Enumeraciones, 358

DataGridView, 310
DateTime, 337
Day, 337
debug, 369
decimal, 99
Decimal (sistema de numeracin), 391
Declarar una variable, 36
Decremento, 94
default, 60
Depuracin, 369
Dequeue, 314
Desapilar, 312
Desbordamiento, 36
Descomposicin modular, 156
Desplazamiento a la derecha, 356
Desplazamiento a la izquierda, 356
destructor, 214
Diagramas de Chapin, 83
Diagramas de flujo, 55
Dibujo con Windows Forms, 434
Diccionario, 319
Dinmica, memoria, 311
Direccin de memoria, 329
Directorios, 344
DirectoryInfo, 344
Diseo modular de programas, 156
Distinto de, 49
Divisin, 34
do ... while, 65
Doble precisin, 97, 98
Documentacin, 377
Documentacin desde comentarios, 381
Dos dimensiones (array), 122
Dos ventanas (Windows Forms), 430
Dot Net Framework, 13
double, 99
Doxygen, 381
DrawLine, 435

Convertir a hexadecimal, 105


Cos, 172
Coseno, 172
Coseno hiperblico, 172
Cosh, 172
Create, 267
CreateDirectory, 344
CreateNew, 271
CreateText, 242
Current (SeekOrigin), 259

Hash, 320

Generics, 326
get, 360
Get, 189
GetEnumerator, 322
GetFiles, 345
GetKey, 319
gigabyte, 385
Global (variable), 163
gmcs, 31
goto, 82
goto case, 60

Revisin 0.99zz Pgina 441

factorial, 175
false, 111, 121
falso, 111, 121
Fecha y hora, 337
Fibonacci, 176
Fichero fsico, 253
Fichero lgico, 253
Ficheros, 242
Ficheros binarios, 253
Ficheros de texto, 242
Ficheros en directorio, 345
FIFO, 314
File.Exists, 249
FileAccess.ReadWrite, 271
FileStream, 258
fin de fichero, 245
fixed, 335
float, 99
for, 67
foreach, 139
ForegroundColor, 340
Formatear nmeros, 102, 103
fuente, 16
Funcin de dispersin, 320
Funciones, 156
Funciones matemticas, 171
Funciones virtuales, 225

Enumeradores, 322
Environment, 348
Environment.Exit, 178
ERRORLEVEL, 178
Escritura indentada, 49
Espacios de nombres, 354
Estructuras, 125
Estructuras alternativas, 47
Estructuras anidadas, 127
Estructuras dinmicas, 311
Estructuras repetitivas, 63
Euclides, 177
Excepciones, 88, 250
EXE, 12
Exists (ficheros), 249
Exit, 178
Exp, 172
Exponencial, 172
Expresiones regulares, 361

Introduccin a la programacin con C#, por Nacho Cabanes

Ll

Local (variable), 163


Log, 172
Log10, 172
Logaritmo, 172
long, 93
Longitud de una cadena, 130

llaves, 17

Label, 424
LastIndexOf, 132
Lectura y escritura en un mismo fichero, 271
Length (cadenas), 130
Length (fichero), 260
lenguaje C, 10
lenguaje mquina, 9
LIFO, 312
Lnea de comandos, 177
Lneas, dibujar, 434
List, 326
lista, 316

Key, 341
KeyAvailable, 340
KeyChar, 341
kilobyte, 385

JavaDoc, 383
JPG, 417
Juegos, 400

Identificadores, 40
if, 47
Igual a, 49
Imgenes con SDL, 400
Incremento, 94
IndexOf, 132
Inseguro (bloque "unsafe"), 330
Insercin directa, 146
Insert, 133, 316
Insertar en un array, 118
int, 36, 37, 93
Internet, 349
intrprete, 12
Interrumpir un programa, 178
Introduccin de datos, 43
IOException, 271
iterativa, 176

Hexadecimal, 105, 395


Hora, 337

Revisin 0.99zz Pgina 442

O, 52
Objetos, 180
octal, 393
Octal, 105
Ocultacin de datos, 189
OpenOrCreate, 271
OpenText, 244
OpenWrite, 267
Operaciones abreviadas, 96
Operaciones aritmticas, 34
Operaciones con bits, 356
operador coma, 364
Operador condicional, 58
Operadores, 34
Operadores lgicos, 52
Operadores relacionales, 49
Operator (sobrecarga de operadores), 237
or, 356
Ordenaciones simples, 145

n, 108
namespace, 354
Negacin, 34
Negativos (nmeros, representacin), 397
Net, 13
NetworkStream, 350
new (objetos), 187
new (redefinir mtodos), 206
Next (nmeros al azar), 170
nibble, 392
No, 52
not, 356
Notepad++, 33
Now, 337
null (fin de fichero), 246
Nmeros aleatorios, 170
nmeros enteros, 34
Nmeros reales, 97

Main, 17
mquina virtual, 12
matemticas, funciones, 171
matriz, 113
Mayor que, 49
maysculas, 133
Maysculas y minsculas, 40
mcs, 31
megabyte, 385
Memoria dinmica, 311
Menor que, 49
MessageBox, 428
mtodos, 219
Mientras (condicin repetitiva), 63
Modificar parmetros, 167
Mdulo (resto de divisin), 34
Mono, 16, 19
MonoDevelop, 204
Month, 337
Mostrar el valor de una variable, 38
MoveNext, 323
Multiplicacin, 34

Introduccin a la programacin con C#, por Nacho Cabanes

Raz cuadrada, 172


Random, 170
Rango de valores (enteros), 93
Read (FileStream), 258
Readkey, 340
ReadLine, 43, 44, 45, 46
ReadLine (fichero), 244
real (tipo de datos), 97
recolector de basura, 335
Recursividad, 174
Red local, 349
Redondear un nmero, 172
ref, 168

Queue, 314

Palabra reservada, 40
Parmetros de Main, 177
Parmetros de una funcin, 158
parmetros por referencia, 168
parmetros por valor, 167
Pascal, 9
Paso a paso (depuracin), 370
Pausa (Sleep), 338
Peek, 313
Persistencia de objetos, 274
Pi, 172
Pila, 312
PNG, 417
Polimorfismo, 215
POO, 180
pop, 312
Posicin del cursor, 340
Posicin en el fichero, 259
postdecremento, 95
postincremento, 95
Potencia, 172
Pow, 172
Precedencia de los operadores, 35
predecremento, 95
preincremento, 95
Prioridad de los operadores, 35
private, 209
Process.Start, 347
Producto lgico, 356
programa, 9
Programacin orientada a objetos, 180
Propiedades, 360
protected, 208
Prueba de programas, 372
Pseudocdigo, 14
public, 18
public (struct), 125
Punteros, 311, 329
Punto Net, 13
Puntos de ruptura, 372
push, 312
Python, 10

Overflow, 36
override, 225

Revisin 0.99zz Pgina 443

Sangrado, 49
sbyte, 93
SDL, 400
Secuencial, acceso, 253
Secuencias de escape, 108
Seek, 259
SeekOrigin, 259
Seleccin directa, 145
Seno, 172
Sentencias compuestas, 48
Serializable, 275
set, 360
Set, 189
SetByIndex, 320
SetCursorPosition, 340
SharpDevelop, 420
short, 93
Si no, 50
Signo y magnitud, 397
Simple precisin, 98
Sin, 172
Sistema (informacin), 348
Sistema (llamadas), 347
Sistema binario, 391
Sistema de numeracin, 105
Sistema decimal, 391
Sleep, 338
SOAP, 283
Sobrecarga, 215
Sobrecarga de operadores, 237, 239
Sort, 316
SortedList, 319
Split, 135
SQL, 289
SQLite, 292
Sqrt, 172
Stack, 312
stackalloc, 333
static, 219
StreamReader, 244
StreamWriter, 242
string, 62, 110
String.Compare, 137
StringBuilder, 138
struct, 125
struct anidados, 127
Subcadena, 131
Subcadenas, 135
Substring, 131
Suma, 34
Suma exclusiva, 356

Referencia (paso de parmetros), 168


RegEx, 362
Registro, 253
Registros, 125
Remove, 133
Repetirmientras, 65
Replace, 133
Reserva de espacio, 333
Resta, 34
Resto de la divisin, 34
Retorno de Main, 177
return, 161
Round, 172

Introduccin a la programacin con C#, por Nacho Cabanes

uint, 93

tabla, 113
Tabla (bases de datos), 289
Tablas bidimensionales, 122
Tablas hash, 320
Tan, 172
Tangente, 172
Tanh, 172
Tao.SDL, 400
TcpCliente, 350
Teclado, 340
Teclado con SDL, 403
Teclas en consola, 341
Temporizacin, 337
TextBox, 424
Texto con SDL, 411
this, 232
Thread, 338
Thread.Sleep, 338
Tipo de datos carcter, 107
Tipos de datos enteros, 92
Title, 340
ToByte, 93
ToDecimal, 100
ToInt16, 93
ToInt32, 43, 93
ToInt64, 93
ToLower, 133
ToSbyte, 93
ToSingle, 100
ToString, 103
ToUInt16, 93
ToUpper, 133
true, 111
Truncate, 271
try, 88

Suma lgica, 356


switch, 60
System, 17
System.Drawing, 434

Y, 52
Year, 337

XML, 283
xor, 356

WaitForExit, 347
while, 63, 65
Windows Forms, 420
Write (BinaryWriter), 269
Write (FileStream), 267
WriteByte, 267
WriteLine, 17
WriteLine (ficheros), 243

Revisin 0.99zz Pgina 444

Valor absoluto, 172


Valor devuelto por una funcin, 160
Variables, 36
Variables globales, 163
Variables locales, 163
vector, 113
Ver resultado de un programa, 33
verdadero, 111
virtual, 225
Visibilidad (POO), 191, 208
Visual Studio, 420
VisualStudio, 200
void, 157

ulong, 93
UML, 185
Unicode, 390
Unidades de disco, 348
Unidades de medida, 385
unsafe, 330
ushort, 93
using, 44

Introduccin a la programacin con C#, por Nacho Cabanes

You might also like