You are on page 1of 389

PROGRAMACIN C#

Diego G. Ruz
Es ingeniero en Sistemas de Informacin, egresado de la Univer
sidad Tecnolgica Nacional Argentina. Su inters por la progra
macin comenz a los 10 aos de edad, cuando tuvo en sus ma
nos su primera computadora, la Commodore 64. A partir de
aquel momento, inici una carrera que lo llevara de computado
ra en computadora y de un lenguaje de programacin a otro.
Actualmente se desempea como programador lder en el depar
tamento de sistemas de la empresa Bioscience, dedicado a la cons
truccin de software para la adquisicin, visualizacin y anlisis
de seales biolgicas. Dicta clases de programacin de videojue
gos en el instituto Image Campus y es colaborador de la revista de
programacin users.code en el rea multimedia. Es, adems, au
tor del libro C++ Programacin orientada a objetos.

D edicatoria
A mi compaera de vida, Ana, quien a pesar de mis defectos, per
manece a mi lado.

A g ra d e cim ien to s
A mi familia, a la que agradezco profundamente su contencin y
afecto.

2 ^ SOBRE LA EDITORIAL
MP Ediciones S.A. es una editorial especializada en temas de tecnologa
(computacin, IT, telecomunicaciones).
Entre nuestros productos encontrar: revistas, libros, fascculos, sitios en Internet y eventos.
Nuestras principales marcas son: USERS, Aprendiendo PC, Dr. Max y TecTimes.

Si desea ms informacin, puede contactarnos de las siguientes maneras:


Sitio web: www.tectimes.com
E-mail: librosiampediciones.com
Correo: Moreno 2062 (C1094ABF), Ciudad de Buenos Aires, Argentina.
Tel.: 54-11-4959-5000/Fax: 54-11-4954-1791

u M .c o d e

Prlogo

PRLOGO
Desde que Microsoft present al mundo su nueva plataforma estratgica de desa
rrollo, .NET, sta no ha parado de crecer y extenderse. Hoy en da, forma parte
de una de las tecnologas ms importantes que un programador debera conocer.
En este libro aprender a programar en C#, el lenguaje ms importante de la platafor
ma .NET, el cual le permitir explotar al mximo sus capacidades.
El lenguaje fue diseado para crear sistemas en el mundo actual, donde la necesidad
de comunicarse con otras aplicaciones y servicios por una red de informacin -co
mo Internet- es moneda corriente, donde conviven bases de datos de distintos fabri
cantes, donde los sistemas son construidos a partir de componentes locales o remo
tos, donde se requieren soluciones integrales para diversos tipos de plataformas.
Con C# podremos crear sistemas de una gran diversidad, simples o complejos,
aplicacior.es de consola, de escritorio o para la Web, para computadoras persona
les o para dispositivos mviles, etc. Tambin ofrece una excelente puerta de en
trada a quienes deseen iniciarse en la programacin orientada a objetos, ya que es
fuerte en los aspectos ms importantes del paradigma y simplifica las tareas me
nos agradables que suelen convivir con otros lenguajes ms antiguos.
Este libro ofrece una introduccin en los aspectos ms importantes del lenguaje
C# y la plataforma .NET. Pretende ser ideal para el principiante, para el no tan
principiante y para los programadores que provengan de otros lenguajes, atrados
por esta grande y maravillosa plataforma de desarrollo. Espero que el lector dis
frute tanto su lectura como yo disfrut en escribirlo.

Ing. Diego G. Ruiz


ruizdiego@gmail.corr.

u s r .c o d e

PROGRAMACIN C#

EL LIBRO DE UN VISTAZO
En la prim era parte de este m anual, d esarro llarem o s los conceptos
fu ndam entales y las caractersticas particulares que hacen a este len
guaje, para luego introducirnos de lleno en la program acin de aplica
ciones de escritorio y para la Web.

multidimensionales: cmo usarlos y los


EL LENGUAJE C# Y LA PLATAFORMA .NET

beneficios que ofrecen.

En este primer captulo estudiaremos


qu nos ofrece este nuevo lenguaje
y por qu habra de interesarnos.

DELEGADOS Y EVENTOS
Los delegados y los eventos son elementos
muy utilizados en la programacin Windows.

FUNDAMENTOS DEL LENGUAJE C#

C# ofrece un mecanismo simple que cumple

Conoceremos los conceptos fundamentales

con este objetivo y que nos servir para

de este lenguaje, que sern tiles tanto para

muchsimos otros fines.

quienes den sus primeros pasos en la


programacin como para quienes vengan de
lenguajes como Visual Basic, C++ o Java.

APLICACIONES CON WINDOWS.FORMS


Finalmente, en este captulo nos
sumergiremos en la creacin de aplicaciones

CLASES Y OBJETOS

de escritorio. Presentaremos los controles

En este captulo estudiaremos

bsicos de la librera, y cules son sus

la anatoma de la estructura de datos

mtodos y propiedades, que nos permitirn

ms importante del lenguaje: la clase.

crear, desde cero, una aplicacin con interfaz


de usuario.

ENCAPSULAMIENTO, HERENCIA Y
POLIMORFISMO

ACCESO A DATOS EXTERNOS

Profundizaremos en los conceptos de la

Veremos cmo acceder y emplear la

programcin orientada a objetos, para luego

informacin almacenada en archivos de texto

conocer las particularidades de C#, como los

y binarios, y tambin en bases de datos

mtodos virtuales y las clases abstractas.

relacinales por medio de AD0.NET.

Captulo 5

Captulo 9

COLECCIONES

MANEJO DE EXCEPCIONES

El array es uno de los recursos ms

C# ofrece un sistema de manejo de

poderosos que ofrece C#. Analizaremos aqu

excepciones muy completo, que nos permitir

diferentes tipos de arrays, de una dimensin y

lidiar con estas situaciones imprevistas

u s r .c o d e

El libro de un vistazo

de un modo muy sencillo y efectivo. En este

: Captulo 13

captulo descubriremos cmo sacar el

INTRODUCCIN A MANAGED DIRECTX

mximo provecho de l.

Realizaremos una breve introduccin a

: Captulo 10

.NET que nos permitirn hacer uso de DirectX.

Managed DirectX, una suma de clases para

CARACTERISTICAS AVANZADAS
DEL LENGUAJE

SU

Conoceremos los aspectos avanzados

DOCUMENTACIN DE CDIGO

con los que cuenta el lenguaje:

Conoceremos qu herramientas nos ofrece

boxing/unboxing, qu son y para qu se

C# para llevar adelante esta ardua pero

utilizan los atributos, qu es Reflection y

importante tarea.

cmo acceder a libreras creadas en otros


lenguajes, entre otros temas.
LA NOTACIN HNGARA

Captulo 11

En este apartado veremos los conceptos

SERVICIOS WEB

fundamentales de la notacin Hngara.

Sin dudas, los servicios web son uno de los

Bsicamente, se trata de una convencin de

aspectos de la plataforma que ms han

nombramiento de variables y funciones muy

crecido en popularidad en los ltimos

utilizada en C++, que tiene una menor

tiempos. Veremos de qu trata esta tecnologa

incidencia en lenguajes como C# y Java.

y cmo podremos utilizarla desde C#.

Apndice C
tulo 12

UML

SOCKETS

Descubriremos los fundamentos del lenguaje

En este captulo, desarrollaremos la

de modelado unificado, un sistema notacional

programacin de sockets, y podremos hacer

destinado al modelado de aplicaciones que se

que nuestra aplicacin se comunique con otra

basen en conceptos de la programacin

por medio de una red de datos.

orientada a objetos.

INFORMACIN COMPLEMENTARIA

A lo largo de este manual encontrar una serie de recuadros que le brindarn informacin com

plementaria: curiosidades, trucos, ideas y consejos sobre los temas tratados.


Cada recuadro est identificado con uno de los siguientes iconos;

u s r .c o d e

W E B J E C J |.M E S': C ;p M

Aqu encontrar diferentes


tutariates en video relacionados
con el libro. Slo deber hacer
un clic en Ver Tutorial

S ?

e.

para bajar el video a su PC.

Una completa guia con


sitios web, para acceder
a ms informacin
y recursos tiles que
ie permitirn profundizar
t

sus conocimientos.

Las mejores aplicaciones


y herramientas accesorias,
ejemplos y listados del libro
para que no tenga que invertir su
tiempo en transcribirlos.
OnWeb. el sitio que le permitir aprovechar al mximo cada uno de
nuestros libros, con contenido exclusivo: la mejor seleccin de software y
los ejemplos analizados en e! texto, tutoriales en video y una completa
guia de sitios de Internet. > Adems, un foro a travs del cual podr
realizar interconsultas con otros lectores y usuarios, debatir con ellos y
estar en contacto con la editorial. Como siempre. MP Ediciones, a la
vanguardia en la divulgacin de la tecnologa

BIENVENIDO LOS SERVICIOS EXCLUSIVOS

DE 0NWEE-.

Ingrese al sitio onweb.tectimes.com. La primera vez que acceda,


deber registrarse con un nombre de usuario y una clave.
Para completar el proceso de registro, se le har una pregunta
referida al libro y se le solicitarn sus datos personales.

0 N W E I . I E C 1 I M E S . C O M

Contenido

CONTENIDO
Espacios de nombres

36

La sentencia using

37

Sobre et autor

Prlogo

El libro de un vistazo

Los comentarios

38

Informacin complementaria

Las variables

39

Introduccin

14

Las palabras reservadas de C#

40

Ejemplos de identificadores

40

Convenciones de nombramiento

41

EL LENGUAJE C#

Tipos de datos fundamentales

42

Y LA PLATAFORMA .NET

Asignar valor a una variable

47

Otro lenguaje nuevo?

16

Constantes

48

.NET

19

Conversiones de tipo de datos

50

19

Operadores

Elframevvork.NET

Control del flujo de ejecucin

E J E i B E

Eipttcadoncwwr.t tefl*uaet
(CIR/

53
55

Sentencias condicionales

55

Sentencia de bucle

66

VtaMl
.1

fWMMlk.Nn

WMwt

El lenguaje C#

20

Caractersticas fundamentales
del lenguaje

21

C# contra Visual Basic 6.0

21

C# contra C++

22

CU contra Java

23
Resumen

El entorno de desarrollo
Visual Studio .NET

24

Nuestra primera aplicacin

79

Actividades

28

Captulo 3

Resumen

33

CLASES Y OBJETOS

Actividades

34

Qu es una clase

82

Cmo declarar una clase

82

conVisualStudio.NET

FUNDAMENTOS DEL LENGUAJE C#


Sintaxis bsica del lenguaje

36

Modificadores de acceso

84

Instanciacin

86

Constantes de una clase

PROGRAMACION C*

Variables estticas

Mtodos virtuales

145

Los mtodos

Interfaces

153

Clases abstractas

154

I[

Resumen

155

Actividades

156

1JO

^ identificador j

COLECCIONES
Arrays

158

Mtodos de la clase Array

164

Arrays como parmetros


de mtodos

166

Valores predeterminados en un array

169

Inicializando elementos de arrays

171

Recorriendo arrays

172

El modificador params

172

Arrays multidimensionales

173

Inicializacin de un array
de dos dimensiones

176

Arrays de arrays

176

Indexadores

179

Indexadores para acceder


a arrays de dos dimensiones
Estructuras

109

Resumen

111

Actividades

112

184

Colecciones

185

lEnumerable y lEnumerator

m t e if a j
innumerable

185

ntertar- lEnumerator

ENCAPSULAMIENTO, HERENCIA
Y POLIMORFISMO
Herencia
Uso de los modificadores de acceso
Las propiedades

j CloscEnumcrabie 1
114

*-----1'etlriumeratorf,

1 ClaseEmimeraooi
Cuf<ent
+MoveUat!;
Resety

----------- O

122
123

Invocar constructores

128

ICollection

188

Invocar destructores

132

IComparable

189

Composicin

133

Composicin frente a herencia

135

Polimorfismo

137

IList
Diccionarios
El diccionario Hashtable

189
19G
191

Sobrecarga de mtodos

137

Resumen

193

Sobrecarga de operadores

141

Actividades

194

Contenido

Convencin de nombramiento
DELEGADOS Y EVENTOS

para controles

Delegados

232

196

Manipulacin de los controles

Qu es un delegado?

199

bsicos

El delegado es una clase

201

Caso de estudio 1

201

Caso de estudio 2

239

204

Caso de estudio 3

241

Caso de estudio 4

246

Eventos
Invocar mltiples mtodos

234
234

25G

Caso de estudio 5
Resumen

253

Actividades

254

ACCESO A DATOS EXTERNOS


Archivos

256

File

void Ktodo2

i
tiro t u * Bxeeptiool*

256

Tipos de streams

256

Manipulando archivos de texto

257

Manipulando archivos binarios

260

Bases de datos

263

SQL

265

Elementos de una base


de datos relacional

La clase System.Timers.Timer

207

Caso de estudio

208

266

------ ]r ---.NETDataProvidct

DUAdJpt-':
| Comando5E1ECT |

Resolucin

209

Coiwctioa

| j | ComandoINSERI j

Resumen

213

Comrnar.d

j ! | Coma* UMWl |

Actividades

214

DataRcadr
1 j CcmanooDEtfTE j
L _ -------- J i
iL

APLICACIONES CON WINDOWS.FORMS


Arquitectura de una aplicacin
Windows
La clase Application

216
221

Un ejemplo sencillo

269

279

Controles

222

Formularios

227

Resumen

281

Crear una aplicacin sencilla

229

Actividades

281

Crear un DataSet mediante cdigo

PROGRAMACION C*

Atributos predefinidos
MANEJO DE EXCEPCIONES

305

Consultar los atributos en tiempo

Tratamiento de errores

284

Encerrar las excepciones

286

Clases de excepciones

287

Generar excepciones

294

de ejecucin
Reflection

306
307

Ejecutar mtodos de tipos


desconocidos

308

Acceso a otras libreras

311

Punteros

312

Resumen

315

Actividades

316

W ix * un

i /

r f :
i

>

kr,:

SERVICIOS WEB

J j .

Qu son los servicios web?

- V ...
J/t* CUMtill

Servicio de bsqueda de Google

' IwwdruMonay.
,

318
318

KiioaoiUnJi

Crear nuestras propias clases


de excepcin

296

Resumen

297

Actividades

298

s.

Captulo 1$

Crear un servicio web

327

CARACTERISTICAS AVANZADAS

Resumen

331

DEL LENGUAJE

Actividades

332

Boxing/Unboxing

300

Atributos

301
SOCKETS
Qu es un socket?

334

Arquitectura de una aplicacin


de sockets

334

Dilogo entre un cliente


y un servidor

334

Sincrnico vs. Asincrnico

335

La clase Socket

335

Resumen

341

Actividades

342

Introduccin

LA NOTACIN HNGARA

INTRODUCCION

La convencin

370

344

Un tipo base

370

344

Un prefijo

370

345

Un calificador

37!
371

A MNAGED DIRECTX
Managed DirectX
Qu necesitamos?
El sistema de coordenadas 3D
Antes de empezar

346

Algunos ejemplos

Inicializar Direct3D

347

Ventajas y desventajas
372

de la convencin

UML
374

Introduccin

374

Diagramas de casos de uso

356

Dibujar objetos

Diagramas de clases

375

Diagramas de objetos

375

Diagramas de secuencia

376

El mtodo ProcsVerts
de la clase Renderer

359

Ejecutar la aplicacin

360

Resumen

361

Actividades

362

* de la e l* *
rbeouewCoiiun vi
peticin! 10
pMitn y - C

* I
rtiacior-di*
, |* " * -c o m p o n

'Apndice A

i
tutC-1: T tilu j

DOCUMENTACION DE CDIGO

nombre M vtOl.brfi
U h k - 12?

364

Cmo documentar cdigo

i w v W t .............. - prcpietok-

367

Los tags disponibles


Otras herramientas para crear
documentacin

........

368

r#

tix&sszffCMM

Diagramas de estados

377

Diagramas de colaboracin

378

Diagramas de actividad

379

Diagramas de componentes

380

Extensiones a UML

381

Servicios al lector
Lenguajes .NET

382

ndice temtico

385

PROGRAMACIN C *

INTRODUCCIN
Este libro se encuentra dirigido, principalmente, al programador novato y de nivel
medio, as como al estudiante o al aficionado autodidacto.
Quienes estn dando sus primeros pasos en el mundo de la programacin no po
drn dejar de sumergirse en los primeros dos captulos, donde se realiza una intro
duccin a la plataforma .N ET y a la sintaxis bsica del lenguaje. Tambin ambos re
sultarn muy tiles para quienes provengan de otros lenguajes de programacin, ya
que se evidencian las diferencias sustanciales que stos poseen respecto a C .
Si acaso a usted le atrae la programacin orientada a objetos y desea conocer sus
conceptos fundamentales y cmo C# la soporta, los captulos 3 y 4 le sern de gran
utilidad.
Si, en cambio, desea crear aplicaciones de escritorio, no puede dejar de visitar el ca
ptulo 7, donde veremos cmo generar este tipo de programas haciendo uso de la
gran diversidad de controles que la plataforma .N ET nos ofrece. Pero claro, ningu
na aplicacin es demasiado til si no puede interactuar con datos externos. En el
captulo 8 veremos de qu trata AD O .NET y cmo nos facilita la tarea de trabajar
con diversas fuentes de datos.
Y esto no termina aqu! C# y la plataforma .NET son tan verstiles, que nos per
mitirn publicar los servicios de una aplicacin en una red de un modo muy senci
llo. En el captulo 11 veremos cmo generar servicios web, y en el captulo 12
aprenderemos a crear aplicaciones de red utilizando sockets.
Desea crear aplicaciones grficas de alto desempeo? Acaso le interesa programar
juegos? Entonces la librera Managed DirectX ser una gran aliada en su misin, y
el captulo 13 ofrece una introduccin a sus principales caractersticas.
Y como si todo esto fuera poco, en los apndices encontrar cmo crear documenta
cin a partir del cdigo escrito en G?, de que trata la notacin de nombramiento Hn
gara, un listado de lenguajes .NET que podr encontrar en la Red -son ms de cin
cuenta!- y, por ltimo, una introduccin al lenguaje unificado de modelado (UMLj.
No es exagerado enunciar que C# y la plataforma .NET son el sueo de todo pro
gramador. Si acaso duda de mi palabra, qu espera para comprobarlo!

Ing. Diego G. Ruiz


ni izciieept^'gmai .coir.

PROGRAMACIN C#

Captulo

El lenguaje C#
y la plataforma
.NET
En este p rim er captulo estudiarem os
qu nos ofrece este nuevo lenguaje
y por qu habra de interesarnos.
R ealizarem os una com paracin
con lenguajes sim ilares y analizarem os
cul es la arquitectura de la plataform a
sobre la que esta construido.

Otro lenguaje nuevo?

16

.NET

19

El framework .NET
El lenguaje CU

19
20

Caracterstica: fundamentales
del lenguaje

21

CS contra Visual Easic 6.0

21

CS contra C++

22

CS contra Java

23

El entorno de desarrolle
Visual SturiiG .NET

24

Nuestra primera aplicacin


con Visual Studio .NET
Resumen
Actividades

2?
32
34

PROGRAMACIN C<

OTRO LENGUAJE NUEVO?


C# irrumpe en el mercado como un lenguaje muy bien diseado y con muchas virtu
des en una industria plagada de soluciones y herramientas de programacin para todos
los gustos. Cules son, entonces, los motivos por los cuales deberamos optar por C#r
C# es un lenguaje moderno y orientado a objetos, con una sintaxis muy similar a
la de C++ y Java. Combina la alta productividad de Visual Basic con el poder y
la flexibilidad de C++.
La misma aplicacin que se ejecuta bajo Windows podra funcionar en un dispositivo
mvil de tipo PD A Con C#/.NET r.o nos atamos a ninguna plataforma en particular.
Se puede crear una gran variedad de aplicaciones en C#: aplicaciones de consola,
aplicaciones para Windows con ventanas y controles, aplicaciones para la Web, etc.
C# gestiona automticamente la memoria, y de este modo evita los problemas de
programacin tan tpicos en lenguajes como C o C++.
Mediante la plataforma .NET desde la cual se ejecuta es posible interactuar con
otros componentes realizados en otros lenguajes .NET de manera muy sencilla.
Tambin es posible interactuar con componentes no gestionados fuera de la pla
taforma .NET. Por ello, puede ser integrado con facilidad en sistemas ya creados.
Desde C# podremos acceder a una librera de clases muy completa y muy bien di
seada, que nos permitir disminuir en gran medida los tiempos de desarrollo.
Pero dnde quedan los dems lenguajes? Qu motiv a Microsoft a desarrollar la
plataforma .NET?
Durante algn tiempo, cuando la programacin en plataforma PC/Windows se po
pulariz, los caminos ms comunes eran, principalmente:
Visual Basic: un lenguaje fcil de aprender pero con muchos defectos. Gran par
te de esas deficiencias es fruto de su afanoso objetivo por ser sencillo para el pro

gramador novato. Es un lenguaje orientado a objetos ligbt, Posee algunas de las


caractersticas ms populares de la POO implememadas, pero muchas de ellas (las
que realmente extraaremos en proyectos complejos) permanecen ausentes, como
la herencia, los mtodos virtuales, la sobrecarga de operadores, etc.
Claro que V B tambin posee muchas virtudes. Realizar una aplicacin Windows
nunca haba sido tan fcil, y si cierras tarcas se encuentran fuera dei alcance del
lenguaje, es posible realizar un componente en, por ejemplo, C++ y utilizarlo des
de V B sin inconvenientes.
Visual C++: es ideal para crear componentes, libreras y drivers, pero la produc
tividad desciende abruptamente cuando se trata de aplicaciones con lormularios
complejos. Es que, para esto, Visual C++ se basa en M FC
k;

[Microsoft ioiimiation

--i-

Otro lenguaje nuevo-?

Classes, un grupo de clases que encapsulan el API de Win32 y agregan algunas


funcionalidades para facilitar la creacin de aplicaciones). Disear formularios
con M FC es una tarea poco grata; muchas de las propiedades de los controles de
esta librera debern ser fijadas en tiempo de ejecucin, lo que aumentar la cantidad de cdigo que deber poseer nuestra aplicacin.
Delphi y C++ Buiider: basados en el lenguaje de programacin Pascal y C++.
respectivamente, y ambos haciendo uso de una librera llamada V C L (Visual
ComponnU Library), permiten la creacin de formularios complejos de una ma

nera bastante sencilla, y poseen la capacidad de fijar casi la totalidad de las pro
piedades necesarias en tiempo de diseo y con base en dos de los lenguajes ms
exitosos de todos los tiempos.
7/
rl ** vm* vtw paJc- Pjr.

C\i' j *

SKI-.
4?

y: 5 ~

H*

'Manr

W r X ,

J.! : *
i <K>er.i

- ; T 'i' * AfST *; j>l R f *5 ^

H
_Co>**r

tl C I At>J * W5ke:

>

>Ino**./.. J

<1

r j:-i : r-
. r.* ;
J'-i*::!* fSU'xri: , .

Jjee'*

V
tu

vt-W.
, ;|1MN(*Jl.aI,Kfl*!*:
, KHL'.IH.T TI'H! IHClOi
> HKOJll WHEIHOtf!
.

,
,
,
,
,

HKMU11 f K.r:HOf
v k rwiv
Hfit'jlT $7'Hf
v r f .r 'ii^ .
HRt-iKT'.T<MWp'Cl
V livjl
uw/.
HflfSaT ST5METH0WA1

r.*ww<r

:*i\
i i *.-v

rv< ,1.:

fw*. i* . :
hHv . v .

''r.iifi riAjr
i
.
"
x. v .
* *' '
' M .
.* iir'.U V
t
i- . i "
:>nxJiM

.(TMftdfcwluflorlvrf/
.CflMMHfcMfaBrf

'f T

\>
Jn1.twjiwlh/lw
/
Figura i . El entorno ele programacin Borland C++ Buiider 6.0.

| 2 | ONWEB.TECTIMES.COM
En el sitio onweb.tectimes.com encontrar contenido adicional vinculado a los temas tratados en
este manual, incluyendo el cdigo fuente de los ejemplos que se desarrollarn en este libro, listo
bajar y probar, as como una completa guia de sitios web recomendados.

17

PROGRAMACIN C*

Pero no todo es color de rosa para estos entornos. Las aplicaciones son cada da ms
complejas y los programadores requieren, cada vez en mayor medida, un buen so
porte a la colaboracin entre componentes. Sera deseable poder emplear desde
Delphi una librera C++ ya existente, de una manera sencilla, sin tener que estar
utilizando herramientas de conversin.
En el caso de C++ Builder, hasta existen inconvenientes para acceder a libreras
creadas en Visual C++ debido a que utilizan formatos de libreras distintos (OM F
en el caso de C++ Builder y COFF en el caso de Visual C++), y esto es malo dado
que Visual C++ es el entorno ms popular (por lejos) para la creacin de libreras
para Windows, y muchsimos recursos que podemos encontrar en la Red fueron
creados con este entorno.
Si deseamos, por ejemplo, crear una aplicacin que utilice DirectX desde C++ Buil
der, tendremos que buscar en la Red las libreras .LIB correspondientes en formato
OM F (existe una herramienta provista por el entorno para la conversin de forma
to COFF a OMF, pero la importacin de libreras complejas, como lo es DirectX,
no es para nada trivial).
Finalmente, en los ltimos aos ha surgido una gran variedad de plataformas m
viles muy poderosas: PDAs, telfonos celulares, Tablet PCs, etc. Estos dispositivos
no son compatibles con binarios creados para microprocesadores Intel x86, ya que
poseen su propia familia de microprocesadores con su propio paquete de herra
mientas para la construccin de aplicaciones nativas.
Ni Delphi ni C++ Builder se encuentran presentes en otras plataformas ms all
de Windows (y Linux, si tomamos en consideracin a Kylix, que es un entorno
de desarrollo creado por Borland, muy similar a Delphi y a C++Builder). Visual
Basic y Visual C.++ se hallan en versiones especiales para algunos dispositivos m
viles, pero el subconjunto de funciones del API de Win32 que estn en dichos
dispositivos hace que la migracin de una aplicacin de una plataforma se con
vierta en una tarea bastante engorrosa.

BORLAND KYLIX

Kylix es un entorno de programacin para sistemas Linux muy similar a Delphi y a C++ Builder.
Con l es posible crear aplicaciones con ventanas y controles (botones, cuadros de texto, cuadros
de lista, etc.) y compilar en Windows y en Linux. Ms info: www.borland.com/kylix.

.NE7

.NET
.NET es un conjunto de tecnologas construidas a partir de una estrategia de M i
crosoft para la cual ha destinado gran parte de su presupuesto de investigacin. Es
ta estrategia surge: a su vez, del nuevo mapa de necesidades y requerimientos que
Microsoft advirti que se suscitaran en el futuro.
.NET son aplicaciones de servidor (SQL Server 2000, Exchange 2000, etc.), es un
entorno de desarrollo (Visual Studio .NET), son componentes clave que se integran
al sistema operativo, son servicios, y es, finalmente, una plataforma de desarrollo
denominada firamework .NET.

E! framework .NET
Es una infraestructura de desarrollo que est compuesta por diversos recursos, en
tre los cuales se destaca el ms importante, que es una mquina virtual conocida co
mo CLR ( Common

Language Runtime),

sobre la cual se ejecutan las aplicaciones.

De este modo, nuestros programas ya no poseern cdigo nativo de ningn microprocesador en particular, sino instrucciones M SIL (Microsoft Intermedate Langua-

ge) que sern traducidas a cdigo nativo en el momento de su ejecucin (por me


dio de un compilador Jiist ln Time).
El framework tambin define una librera base de clases, BC L

(Base Ciass Libranj,

a la cual puede acceder cualquier desde lenguaje desarrollado para la plataforma.


Por encima de la infraestructura se ubicar un conjunto de reglas bsicas que debe
implementar un lenguaje para poder ser parte de la familia .NET. Esta especifica

cin es conocida como CLS ( Common

Language Specificeation).

Finalmente, se encuentra el conjunto de lenguajes que cumplan con la especifica


cin CLS. como el C#, el VB.NET, Managed C++, etc.

.NET FRAMEWORK SDK

El desarrollo del framework .NET no se detiene. Actualmente la versin 2.0 se encuentra en eta
pa beta. Es posible acceder a ms informacin acerca de esta nueva versin en el sitio oficial:
http://msdn.microsoft.com/netframework.

PROGRAMACIN CU

Es posible crear recursos en cualquiera de estos lenguajes que hagan uso de recur
sos escritos en otros; de hecho, es posible crear una clase en C# que herede de una
clase creada en Managed C++.

c#

C++

VB.NET |

JScript

Especificacin comn de lenguaje


(CU?)

Visual
Studio
.NET

Framework.NET

Windows

Figura 2. Arquitectura de la infraestructura de desarrollo.

EL LENGUAJE C#
CJ es un lenguaje que cumple con la especificacin CLS. El cdigo que crearemos
con l ser traducido a instrucciones M SIL para entonces ser traducido, justo an
tes de su ejecucin, a instrucciones nativas que correspondan a la plataforma con
creta sobre la cual estemos trabajando.
Cabe destacar que el compilador J1T

(Just In Time) traduce el cdigo M SIL a c

digo nativo no de manera monoltica, sino por mtodos, mdulos y componentes.


Por io tanto, a grandes rasgos: cdigo que no sea ejecutado no ser compilado.
El cdigo M SIL generado a partir de la compilacin de cdigo C# es idntico al
cdigo M SIL generado a partir de cualquier otro lenguaje CLS. Esto podra abrir
el interrogante de por qu programar en C# en lugar de hacerlo en V B.N ET o
en Managed C++ o, incluso, en Delphi .NET? Esta pregunta podra responder
se con otra: por qu programar en C++ en lugar de hacerlo en C o Pascal, o en
cualquier otro lenguaje compilado, si todos generan el mismo cdigo Intel x86?

El lenguaje C ti

Cada lenguaje posee sus caractersticas que lo tornan ideal para ciertos usos; ade
ms, presenta diversos grados de expresividad que pueden permitir implementar
el mismo algoritmo de maneras diversas, por lo que un modo puede resultar ms
eficiente que otro.

Caractersticas fundamentales del lenguaje


C# es un lenguaje moderno y altamente expresivo que se ajusta al paradigma de pro
gramacin orientada a objetos. Su sintaxis es similar a C++ y Java. Ei lenguaje fue de
sarrollado en gran parte por Anders Hejlsbcrg (creador del mtico compilador Tur
bo Pascal1y uno de los diseadores lder del lenguaje de programacin Delphi).
En C# no existe el concepto de funcin global o variable fuera de una clase u obje
to. Por su buen apego a la POO, es posible sobrecargar mtodos y operadores. So
porta definicin de interfaces. Ninguna clase puede poseer ms de un padre (no se
permite la herencia mltiple), pero s puede suscribir un contrato con diversas in
terfaces. Soporta la definicin de estructuras, pero, a diferencia de C++, aqu no son
tan parecidas a las clases y poseen ciertas restricciones que veremos luego.
Permite adems la declaracin de propiedades, eventos y atributos (que son cons
trucciones declarativas).
Por ltimo, una caracterstica distintiva cada vez ms presente en lenguajes moder
nos es la gestin automtica de memoria y el uso de referencias en lugar de punte
ros. Gracias a esta gestin automtica de memoria ya no tendremos que preocupar
nos por la existencia de memory leaks (zonas de memoria que permanecen reserva
das pero ya no son utilizadas debido a errores de programacin).
A continuacin realizaremos una breve comparacin de C# con los lenguajes ms
populares del momento:

C# contra Visual Basic 6.0


Si usted es un programador Visual Basic y est evaluando moverse a C#, no lo du
de un segundo. Existen muchsimas razones para tomar esta decisin, y aqu expon
dremos algunas de ellas. En primer lugar, uno de los motivos por los cuales Visual
Basic era atractivo era su productividad. S, a pesar de algunos de sus inconvenientes
para crear aplicaciones sencillas, no exista mejor solucin que Visual Basic; ningn

1 No confundir con el autor del lenguaje Pascal, que fue Niklaus Wirth. Anders Hejlsberg fue el
creador de un compilador llamado Turbo Pascar, que fue muy popular en sus tiempos por su
velocidad y bajo costo.

PROGRAMACIN CS

otro leneuaje poda competir en velocidad de desarrollo con l. Pues bien, C# le ba


quitado la corona; la misma aplicacin que usted puede realizar en Visual Basic po
dr crearla en C# en, al menos, el mismo tiempo, e incluso ms rpidamente. Por
otro lado, gracias a las nuevas caractersticas del lenguaje, el diseo de sus aplicacio
nes podr ser ms elegante y simple, y de este modo podr manejar la complejidad
de una manera ms natural.
En segundo lugar, seamos sinceros: los programadores Visual Basic nunca fueron
vistos como programadores reales, aunque muchsimos profesionales sufran de esta
etiqueta de manera injusta. Los sueldos de un programador Visual Basic son mu
cho ms bajos que los de un programador C++ o Java. C#, en cambio, es visto co
mo un lenguaje ms profesional. Claro que sre es un punro un tanto controverti
do, y podramos discutir las razones del porqu de esta situacin, pero, dejando ex
cepciones a un lado, es una realidad de mercado.
Por ltimo, el pasaje de Visual Basic 6.0 a C# hasta podra ser considerado lgico
para quien sea un dominador del VB; es como comprarse un automvil ms lujo
so o mudarse a una casa ms grande: es el paso evolutivo natural.
Probablemente, lo que usted estar preguntndose respecto al pasaje de Visual Ba
sic 6.0 a C# es el natural para qu existe Visual Basic .NET? Bueno, tai vez Vi
sual Basic .N ET nunca debi haber existido: es demasiado distinto de Visual
Basic 6.0 para ser considerado una nueva versin del lenguaje y, a fin de cuentas,
sigue siendo Basic. Tal vez la pregunta que podramos hacernos sera: si es que va
mos a tener que aprender un lenguaje nuevo, por qu no aprender el mejor y ms
popular lenguaje de la plataforma?

C# contra C++
Admito que C++ es mi lenguaje preferido; trabaj durante muchos aos con l c,
incluso, escrib un libro de C++ (C++ Programacin Orientada a Objetos, de esta
misma editorial), pero prob C# y fue como probar ambrosa.

VISUAL BASIC .NET VS. C

En el enlace de referencia es posible encontrar una comparativa entre Visual Basic .NET y C# es
crita por Mario Flix Guerrero.
Enlace: www.microsoft.com/spanish/msdn/comunidad/mtj.net/voices/MTJ_2128.asp,

El lenguaje Cf?

Hoy da, en mi trabajo diario, complemento de manera natural ambos lenguajes;


no fue difcil ingresar en el mundo C# desde C++. Lo que debo admitir es que lue
go de estar das trabajando con C#, volver a C++ es un cambio un tanto abrupto,
y me descubro preguntando una y otra vez por qu no se encontrar disponible tal
o cual caracterstica de C# en C++.
Los detractores de C++ lo acusan de ser un lenguaje hbrido, un C con clases, como
muchas veces es definido. El problema de esta falta de decisin en cuanto al diseo
del lenguaje es que permite que convivan clases con funciones y variables globales,
lo cual podra ser tentador para el programador y podra empobrecer el diseo de
una aplicacin construida de este modo. Claro que, por otro lado, hay quienes gus
tan de ver el vaso medio lleno y sostienen que esta caracterstica de hibridez' es po
sitiva, pues deja al programador la posibilidad de tomar lo mejor de los dos mundos.
C# es, en alguna medida, una evolucin de C++, ya que toma prestada su sintaxis
y mejora muchos de sus aspectos, como el hecho de poseer una librera de clases
unificada y ser un lenguaje orientado a objetos puro (adis hibridez). Esto no quie
re decir que lo reemplace en todos sus usos, claro. C++ seguir teniendo su segmen
to de utilizacin en donde es ideal, pero C# invade da tras da reas donde antes
C++ era nico conquistador.

C# contra Java
Muchos sostienen que C# es una copia de Java. Si tomamos ciertos trozos de cdi
go (convenientemente) escritos en alguno de estos lenguajes, podra ser imposible
determinar si es C# o es Java.
Lo cierto es que parte de la filosofa empleada por ambos lenguajes es la misma. Am
bos se ejecutan sobre una mquina virtual, y esta caracterstica los convierte en lengua
jes potencialmente multiplatabrma; ambos poseen especificaciones de subconjuntos
de recursos de lenguaje para implemenraciones en diversos dispositivos (por ejemplo,
mviles), y ambos tienen una librera de clases con muchas caractersticas en comn.

SIMILITUDES ENTRE C#. C++ Y JAVA

En el enlace de referencia podrn encontrar una breve comparativa entre estos lenguajes. Enla
ce: www.microsoft.com/spanish/MSDN/estudiantes/desarrollo/lenguajes/c-sharp.asp.

PROGRAMACIN Cfl

Sin embargo, C# presenta la ventaja de integrarse mejor con aplicaciones nativas de


la plataforma sobre la cual estemos trabajando. Claro que, si accedemos a recursos
nativos, perder la caracterstica de ser multiplataforma, pero esta caracterstica no
siempre es deseada. Podramos tener la necesidad de invocar mtodos de libreras
nativas creadas en C++ para Windows de una manera sencilla y eficiente.
Luego podramos discutir en muchos puntos cul es mejor que cul; en la Red, los
foros de discusin sobre programacin se encuentran plagados de peleas de este ti
po. La realidad es que hoy da C# es ms fuerte en plataformas basadas en W in
dows. mientras que Java es ms fuerte en una gran diversidad de plataformas me
nos populares (celulares, tarjetas inteligentes, etc.) y es el candidato ideal si hoy de
sea construir una aplicacin que deba ejecutarse sin cambios en Linux y Windows,
aunque esta realidad se encuentre prxima a cambiar.

EL ENTORNO DE DESARROLLO
VISUAL STUDIO .NET
En el desarrollo de este libro trabajaremos con Visual Studio .NET 2003, que es la l
tima versin de produccin del entorno en el momento de escribir estas lneas. Exis
te una versin 2005 Express en estado beta que tambin podra utilizar el lector.
Por otro lado, el libro se basa principalmente en la versin 1.1 del framework, que
tambin es la ltima versin de produccin a la fecha de publicacin de esta obra.
Quienes no posean el entorno Microsoft Visual Studio pueden utilizar Mono en
ambientes Windows. GNU/Linux y Mac Os X.
El entorno Visual Studio .NET 2003 es una excelente herramienta de desarrollo.
Con ella podremos crear soluciones que, a su vez, podrn contener uno o ms pro
yectos de diversos lenguajes en funcin de los paquetes que tengamos instalados; en

VISUAL STUDI 2005 EDtdN EXPRESS

Es posible descargar la versin beta de este entorno desde http://msdn.microsoft.com/vs2005


Seguramente, en el transcurso del ao, el entorno saldr en su versin definitiva y ya no ser po
sible descargar la versin beta de manera gratuita. De todos modos, Microsoft planea ofrecer las
versiones express del entorno de desarrollo a un costo alcanzable por cualquier desarrollador.

El entorno de desarrollo Visual Studio .NET

principio dispondremos de CJ , Visual Basic .NET y C++. Tambin es posible crear


aplicaciones C# utilizando el framework .N ET SDK, que es un conjunto de herra
mientas que nos permiten compilar cdigo fuente C# para crear aplicaciones. V i

sual Studio .NET hace uso del framework .N ET SDK y funciona como front end
para evitar que nosotros tengamos que interactuar con herramientas en comando
de lnea. El framework .NET SDK puede ser descargado desde el siguiente enlace:
http://msdn.microsoft.com/netframework.
Sin embargo. Visual Studio .NET es mucho ms que un simple front
de las tareas que podremos realizar con l son las siguientes:

end. Algunas

Navegar fcilmente por las clases por medio del visor de clases.
Navegar por los archivos de nuesrros proyectos por medio del explorador de so
luciones.
Entender ms rpidamente el cdigo escrito gracias a que el editor colorea las pa
labras reservadas y los tipos de datos conocidos.
Organizar mltiples proyectos y editar fcilmente sus propiedades.
Configurar el entorno para que ejecute herramientas externas (como precompiladores).
Depurar nuestros proyectos fcilmente y consultar valores de objetos de modo in
teractivo, as como realizar depuraciones remotas desde otras computadoras.
Acceder a facilidades de bsqueda y reemplazo por hoja de cdigo fuente activo y
en archivos.
Editar recursos (bitmaps, iconos, archivos binarios, etc.) por medio de herramien
tas integradas, y navegar por ellos por medio del visor de recursos.
Agregar tareas por realizar haciendo uso de la lista de tareas pendientes, que ade
ms inserta automticamente tareas a partir de comentarios prefijados.
Generar documentacin en formato H TM L por medio de una herramienta pro
vista con el entorno. Esta documentacin es generada a partir del cdigo fuente y
comentarios con formatos especficos que escribiremos en l.
Colapsar y expandir trozos de cdigo para mejorar la legibilidad de nuestras fuentes.
Posibilidad de integrar herramientas al entorno por medio de un sistema de plug-ins.

[ j | j QU ES MONO'/
Desde el ao 2001, la empresa Ximian (adquirida luego por Novell) comenz a desarrollar el pro
yecto Mono, que es una plataforma de desarrollo Open Source basada en el framework .NET. Con
Mono es posible escribir aplicaciones en C# (o VB.NET) y ejecutarlas no slo en Windows, sino

tambin en GNU/Linux y Mac Os X. Se puede descargar desde www.mono-project.com.

r.c o d e

PROGRAMACIN Cg

Haciendo uso de entorno de programacin Visual Studio .NET crearemos proyec


tos. Un proyecto contendr, bsicamente, hojas de cdigo fuente en C# (luego ve
remos que tambin podr contener otros recursos).

Figura 3. Organizacin de un proyecte.

Un proyecto posee ciertas propiedades, las cuales indican de qu manera debern


compilarse las fuentes y los recursos que incluye. La idea de ' proyecto' como orga
nizacin de fuentes se encuentra muy extendida, y casi todo entorno de programa
cin la maneja. Usualmente, un proyecto construido tendr como salida una apli
cacin ejecutable (archivo .EXE) o una librera (archivo .DLL). Sin embargo, es posi
ble (y, de hecho, muy comn) que el sistema en el cual estemos trabajando se en
cuentre integrado por ms de un componente; por ejemplo, una aplicacin y una
librera de enlace dinmico que sea utilizada por la aplicacin. En este caso, no es
slo un proyecto el que deberemos crear, sino dos.
Ahora bien, si necesitramos crear dos proyectos siendo uno dependiente del otro,
qu deberamos hacerr Podramos crear un proyecto en una instancia de Visual
Studio y otro proyecto en otra instancia, pero sta no es una muy buena idea, ya

[ Q ] QU ES UNA DLL?
Una DLL (Dynamic Link Library\ es un conjunto de funciones y/o clases que pueden ser accedi
das y utilizadas por otros programas en tiempo de ejecucin. Estas libreras pueden ser creadas
desde C# o desde otros lenguajes.

iK r .r n r ip

El entorno de desarrollo Visual Studic .NFI

que si modificamos la librera y nos olvidamos de reconstruirla, nuestra aplicacin


seguir utilizando una versin vieja de sta.
Afortunadamente, Visual Studio .N ET soporta ms de un proyecto abierto de ma
nera simultnea en el mismo espacio de trabajo. Estos proyectos pueden relacionar
se entre s por medio de dependencias; de modo que si reconstruimos la aplicacin.,
el entorno automticamente reconstruir todos los proyectos dependientes que se
hayan modificado (por ejemplo, la librera).
Visual Studio denomina solucin a esta agrupacin de proyectos (aunque en edi
ciones anteriores del entorno se las llamaba espacios de trabajo). Todo proyecto
debe estar contenido en una solucin; por lo tanto, cuando creamos un proyecto
nuevo. Visual Studio nos crea automticamente una solucin que lo contiene.

i
i
Y

i
i
Y

Figura 4. Organizacin de una solucin.

Luego, cuando construimos la solucin se construyen todos los proyectos (que pue
den estar relacionados directamente o no), es decir que se procesan todos los ele
mentos de cada proyecto para generar los archivos de salida que correspondan.
u s r .c o d e

27

PIRAMACiUN C#

Proceso de
Compilacin
(csc.exe)

archivosl.cs

i-

i
i
i

i
i
i

archivos2.cs

i
i
i

archivos3.cs

.-

programa.exe

ri

nuestro programa

Figura 5. Compilacin de un proyecto.

Nuestra primera aplicacin con Visual Studio

,N E1

Pero veamos cmo crear nuestra primera aplicacin C# con l. En primer lugar, cabe
destacar que el entorno es sumamente configuradle y que la organizacin de los pane
les, as como la pantalla de inicio, puede variar en funcin de cmo la configuremos.
Si es la primera vez que ejecuta la aplicacin o si no ha modificado las opciones
de inicio predeterminadas, debera encontrarse con la pgina de inicio que se
muestra en la siguiente figura:
Start Pag** j

E s a a g iE s g r

Verify that thc followino settincii sre personaliied fsr you


Profijr:
: Vituf C 4+ Dvelowr
1

};fit

'Visu4!C++;

v-'tfiiov- U v

: 'lu.'ii Studi D ful!

s*: ffl. i

i Visual C++

Show Help:
At Startup:

Irteti! iiclr C z m i r t
Show

Gfivironn-iefd

Figura 6. La pgina de inicio.

v '.c o d e

El entorno de desarrollo Visual Studio .NE1

En lo personal, me desagrada bastante dicha pgina, por lo que lo primero que


hago es fijar las opciones como indica precisamente la figura mencionada, es decir:
Profile: Visual C++ Developer
At Startup: Show empty enviroment
Cambiar el perfil permite que se modifique la ubicacin predeterminada de los pa
neles en donde se encuentran las herramientas (como el visor de clases, el explora
dor de soluciones, etc.). En lo personal, me be acostumbrado a tener el panel de vi
sor de clases a la izquierda, como estaba en el viejo y querido Visual C++ 6.0, pero
cada quien podr hacei lo que le plazca, ya que esta configuracin no nos impedi
r modificar ni crear ningn tipo de proyecto u opcin en particular.
Fijar el inicio de aplicacin en

Show empty enviroment (Mostrar un entorno vacoj

tambin es una cuestin de gustos, y lo que especifica es que cada vez que inicie
mos la aplicacin veremos lo que muestra la siguiente figura:

Figura 7. Visual Studio, comenzando con el entorno vaco.

Bueno, ahora s. vayamos a la accin. Teniendo el entorno ya abierto, lo primero


que deberemos hacer ser Crear un nuevo proyecto. Si estamos en la Pgina de
Inicio , deberemos seleccionar la pestaa Projects, y iuego, presionar el botn New
Proyect que se encuentra en el extremo inferior de la pgina. Si estamos en un en
romo vaco, deberemos acceder al ment File, desde all seleccionar New y, finalmen
te, la opcin Project. Hecho esto, deber aparecer la ventana de la Guia Visual 1.
.c o d e

29

PHOGRAMACION C*

Nuevo proyecto

GUA VISUAL 1

New Project

'-i,3&k~ 1

Project Types:

Im p fe te s :

C j | Visual C # Project:
- D

Visual C++Pro)ects

! Setup and Deployment Project:

ASF.NET Web
Service

_ i Othei Project:
[ _ j Visual Stufo SoM ions

ASP.NET
M cbileW ...

Web Control
Library

i j i '

Consol
Application

Windows
Service

Enipty Proiecl

j . A project for creating a command-line applicatioo


: ConsofcAppkcation!

ame:
location:

Project will be created at E:\useis\diego\kbro C5\codl-apS\ConsoleApplicattonl.


T H c re

Canee!

Help

O Tipos de proyectos disponibles


6 Lista de plantillas de proyectos
Nombre del proyecto
O Ubicacin de la carpeta del proyecto

Seleccionaremos siempre que el tipo de proyecto sea Visual

CU Projects, luego es

pecificaremos la plantilla del tipo de proyecto que deseemos crear. Lo que hace la
plantilla del proyecto es fijar opciones predeterminadas al modo de compilacin de
nuestro proyecto, que finalmente especificar los parmetros que se enviarn al
compilador C# cuando construyamos el proyecto para generar un archivo ejecuta
ble (con instrucciones M SIL).
Para comenzar con algo sencillo, seleccionaremos la plantilla
(en ingls. Consol

Application),

Aplicacin de consola

modificaremos el nombre del proyecto y su ubica

cin, si es que no nos gustan las opciones que nos sugiere el entorno, y finalmente
presionaremos el botn OK.
Hecho esto, el entorno crear un proyecto C# que poseer dos archivos del tipo .CS
(por C#, que se pronuncia C Sharp y usualmente se abrevia CS). Los .CS son archi
vos con cdigo fuente C#; no sern distribuidos con nuestra aplicacin, solamente
los utilizaremos para crearla.
Si por medio del explorador de soluciones miramos los nombres de los archivos que
componen nuestro proyecto, veremos estos dos archivos .CS, que se llaman:
30

a s r .c o d e

El entorno de aesarroiio Visual Studi; .NE'I

Assenxlyinfo.cs
Classl.cs

Assemblylnfo: posee informacin de nuestra aplicacin (nombre del produc


to, versin, empresa, etc.). Este recurso compilado es situado dentro de nues

tra aplicacin y se conoce como assembly. Luego explicaremos en detalle qu es


un assembly.

* Ciassl:

archivo de cdigo fuente que posee la nica clase de la aplicacin y el


punto de entrada al programa.

No importa lo que est escrito en dicho archivo, nosotros cambiaremos el progra


ma y escribiremos lo siguiente:
class Clasel
{

static void Main(string[] args)


{

System.Consol.Write("Nuestro primer programa");


}
}

Analicemos el cdigo anterior. En primer lugar vemos la palabra class seguida de un


identificador de clase (en este caso, Clasel); luego existe un bloque de cdigo ence
rrado entre llaves.
Quienes tengan algunos mnimos conocimientos de lenguaje C o C++ sabrn que en
todo programa debe existir una funcin llamada main, que hace de punto de entrada
al programa, es decir, que es la funcin que debe ejecutarse para iniciar la aplicacin.
Habamos mencionado que en C# todo programa debe estar compuesto de clases,
es decir, que no pueden existir funciones globales. Por lo tanto, al menos una clase
deber poseer un mtodo llamado

Main

(esta vez con la M* en mayscula), que

adems deber ser esttico (luego veremos qu significa esto).


Dentro del mtodo Main se encontrar el cdigo que ser ejecutado cuando nues
tro programa sea inicializado. En nuestro caso, dicho cdigo ser solamente:
System.Consol.WriteLine("Nuestro primer programa*);

u s r .c o d e

31

PROGRAMACIN GS

WriteLine

es un mtodo de la clase Consol que escribe un texto en la salida estn

dar. Dicho texto se especifica entre comillas (comillas dobles).


Bien!, ahora podremos compilar nuestro programa ingresando en el men
opcin

Build,

Build Solution.

Si hacemos esto, podremos ver que en el panel llamado Output (salida) se observa el
progreso de la construccin de nuestra aplicacin. Si existe algn error, tambin se
mostrar all como informacin, y podremos hacer doble clic sobre i para que ei
entorno nos lleve automticamente a la lnea donde se encontr la falla.
- Build started: Project: consoleApplicationl, Configuration:
Debug .NET --Preparing resources...
pdating references...
Perfonning main compilation...
Build complete - 0 errors, 0 warnings
Building satellite as3eniblies...
----------- Done ----------Build: 1 succeeded, 0 failed, 0 skipped

Si hemos ripeado todo bien, deberemos ver lo que indica ei cuadro anterior, es de
cir, a notificacin de que la aplicacin ha sido construida satisfactoriamente.
Luego, podremos ingresar nuevamente en el men Build y seleccionar la opcin
Start (comienzo) o Start without debuggina (comienzo sin depurar). Lo bueno de es
ta ltima opcin es que no cierra la ventana donde est nuestro programa cuando
ste termina, sino que nos solicita que ingresemos una tecla para continuar.
i

Figura 8. Nuestro primer programa C#.

. : .c o d e

El entorno de desarrollo Visual Studio .NE'f

Claro que si no tenemos Visual Studio a mano, pero hemos instalado el framework
.NET, podremos realizar la compilacin de modo manual (o para expresarnos mejor: utilizando el compilador desde comando de lnea). Al fin y al cabo, habamos

comentado que Visual Studio, entre muchas otras cosas, es un front

end al compi

lador C# (y otros compiladores y herramientas). El compilador de C# es una apli


cacin llamada csc.exe, que se encuentra en ei directorio de Windows, dentro de la
carpeta Microsoft.NET/Framework, y all, dentro de la versin del framework que ten
gamos instalado (por ejemplo, vl.1.4322).
Teniendo un archivo llamado, por ejemplo,

programa.es,

podremos realizar una

compilacin en comando de lnea escribiendo:


esc programa.es

Esto nos dejar como salida, en el directorio donde nos encontremos y si no hubo
errores en la compilacin, un archivo llamado programa.exe. Si ejecuta la aplica
cin csc.exe con el parmetro /?, se listarn los switchs vlidos del compilador.

RESUMEN
Est bien, nuestra primera aplicacin no ha sido muy excitante, pero al menos hemos dado el
primer paso y eso no es poco. Tambin es cierto que algunas cuestiones han quedado sin mu
cha explicacin: qu es una clase?, qu es un mtodo esttico?, qu es System? No nos de
sesperemos; a medida que avancemos en el libro, iremos tratando todos estos temas de ma
nera detallada. Ya hemos visto el conejo blanco, ahora slo deberemos seguirlo.

.c o d e

33

PKOGRAMAWf

ACTIVIDADES

TEST DE AUTOEVALUACIN

1 Qu caractersticas diferencian al lengua-

3 Qu es la BCL y para que se utiliza?

je C# de C++?
A Qu es elCLR?

Q S EEi

tjrufcnKft m w. o
(*:

qu plataformas se pueden ejecutar

los programas creados en C#?

fnme**yc

5 En

6 Es posible compilar un programa C# sin


hacer uso del Visual Studio .NET?

2 Qu es el cdigo MSIL?

34

u s r .c o d e

PROGRAMACIN C#

Captulo

Fundamentos
de lenguaje CU
En el captulo anterior presentam os
la plataform a y el lenguaje que
tratarem os en esle libre. Ahora
nos sum ergirem os en los conceptos
fundam entales de C#, lo que ser
provechoso tanto para quienes der,
sus prim eros pasos en la program acin
come para quienes vengan de lenguajes

sintaxis bsica del lenguaje

36

La sentencia using

37

Los comentarios

como Visual Basic. C+ + o Java.

tas,lrllblK

Las palabras reservadas de C#


Ejemplos de dentiticadorcs
Convenciones de nombramiento
Tipos de dalos fundamentales
Asignar valoi a una variable
Constantes
Conversiones de tipo de datos

Operadores

SERVICIO DE ATENCION AL LECTOR: leCtOreS@mpedCOneS.COITl

36

Espacios de nombres

38

35

40
40
41
4?
47
46
50

53

Control del flujo de ejecucin


Sentencias condicionales

55
55

Sentencia de bucle
Resumen

66
79

Actividades

80

PROGRAMACIN C#

SINTAXIS BSICA DEL LENGUAJE


En C# un programa es una coleccin de clases, acu no se permitirn funciones ni
variables globales como en el caso de C++. C# es un lenguaje orientado a objetos
que pretende ser fiel a sus conceptos, y por medio del framework .NET ofrece una
librera de clases que nos sern de gran utilidad cuando construyamos aplicaciones.
Esta librera de clases, que mencionamos en el captulo anterior, se llama BC L (Base
ClassLibrary), y se podra decir que es el sueo de todo programador, ya que ofrece una
gran variedad de funcionalidades que iremos estudiando en el desarrollo del libro.
Por el momento, de esta librera diremos que se encuentra organizada por espacios
de nombres (en ingls, namespaces).

ESPACIOS DE NOMBRES
Los espacios de nombres son un recurso que utilizan algunos lenguajes para la or
ganizacin de un gran conjunto de tipos de datos. As como los directorios (o car
petas) permiten organizar archivos de modo que ficheros del mismo nombre con
vivan en directorios distintos, los espacios de nombres realizan una tarea similar, pe
ro de manera lgica, para tipos de datos extendidos como clases y estructuras.
De este modo, dos clases distintas con el mismo nombre podran ser utilizadas en
el mismo proyecto sin que se suscite ningn error.
Los espacios de nombres tambin pueden ser anidados, por lo que puede haber unos
dentro de otros y, de este modo, mejorar la organizacin de las libreras de un proyecto.
Gracias a esta facilidad, los nombres de los tipos de datos que nosotros crearemos
en el futuro podrn ser de lo ms sencillos, sin temor a que ya exista alguna clase o
estructura de nombre igual en otra librera que luego podremos querer utilizar.

U I NOMBRAMIENTO DE FUNCIONES EN LENGUAJE C


El lenguaje C no posee esta facilidad (aunque s el C++), por lo tanto es normal que una librera
deba componer los nombres de las funciones que define, anteponiendo un prefijo -usualmente,
una abreviacin del nombre de la librera- a cada una de ellas para evitar conflictos con otros pa
quetes (por ejemplo, todas las funciones de la librera SDL comienzan con SDLJ.

36

u s ! .c o d e

Espacios de nombres

Veamos cules son los espacios de nombres ms populares que posee la librera BCL:
1 -ESPAaOS.OENCMBRES
Clase base de toda la librera.
[. System,Collecticns
System.Data

j System.Drawing

Clases e Interfaces que definen colecciones de objetos como


listas, colas y diccionarios.

java.util

Acceso a datos multiproveedor.

java.sql

Provee acceso a funcionalidades grficas de GDI+.

java.awt

System. 10

Manejo de entrada y salida a archivos y flujos.

java.io

System.Net

Manejo de comunicacin va red por medio de una gran


variedad de protocolos.

System.Reflection

pueden crear e invocar tipos de modo dinmico.


System.ext

java.net

Provee acceso a informacin de clases cargadas, por lo que se


java.lang.reflect

Ofrece recursos para la manipulacin de texto en distintas


codificaciones.

java.text

System.Threading

Provee recursos para la programacin de aplicaciones multihilo.

java.util.concurrent

System.Security

Provee acceso a funcionalidades de encriptacin y configuracin


de seguridad del CLR.

System.Windov/s.Forms
: System.Xml

java.securjty, javax.crypto

Manejo de ventanas y controles grficos.

javax.swing

Manejo de datos en formato XML.

javax.xml

Tabla 1. Espacios de nombres.

Por supuesto que la lista es an ms grande. Un acceso de referencia ideal es la docu

mentacin que provee Visual Studio .NET o la provista por MSDN {MSDNLibrary).
Ahora, si volvemos a ver el cdigo de nuestro primer programa creado en el captu
lo anterior, entenderemos mejor aquello de System.Console.WriteLine. Consol es
una clase cue pertenece al espacio de nombres System. Si no lo hubisemos ante
puesto al nombre de la clase, el compilador habra arrojado un error, oues no ha
bra encontrado a Consol en el espacio de nombres global.

La sentencia using

Un modo de ahorrarnos trabajo, al tener que anteponer nombres de namespaces a


cada una de las clases que utilicemos, es colocar en la cabecera de nuestro archivo
de cdigo fuente una sentencia using, escribiendo:
using <espacio de nombres*;

Entonces, el compilador buscar cada clase referenciada en el espacio de nombres


global y en los espacios de nombres especificados por sentencias using.
rs r.c o d e

37

PROGRAMACIN C I

Por lo tanto, el cdigo de nuestro primer programa ahora podra ser:

V
Consol.WriteLina("Nuestro primer programa');

}
}

Consol es una clase que no existe en el espacio de nombres global, sino en el es


pacio de nombres System. Gracias a que le hemos indicado al compilador que es
tamos utilizando dicho espacio de nombres, l sabr que las clases que utilicemos
tambin podran estar all.
WriteLine es un mtodo de la clase Consol. Recordemos que para acceder a in
formacin de referencia sobre la BCL podemos utilizar la ayuda que provee Visual
Studio, conde veremos todos los mtodos y propiedades de la clase Consol.

LOS COMENTARIOS
En un principio, nuestro programa ser pequeo, y analizar qu sucede dentro de
l ser sencillo, ya que bastar con echar un ojo al cdigo escrito. Sin embargo, a
medida que ste crece, se vuelve muy conveniente poder introducir notas aclarato
rias sobre qu es lo que pretendemos que el programa haga. As, si escribimos un
algoritmo en particular, podemos agregar un texto que indique qu debe hacer di
cho algoritmo, y de este modo otro programador podr entenderlo rpidamente, o
quiz nosotros mismos, releyendo el cdigo que hayamos escrito tiempo atrs.
Para que el compilador no interprete el texto aclaratorio como intentos fallidos de
instrucciones, debemos indicarle que estamos introduciendo un comentario.
C# acepta dos tipos de comentarios. Uno es el comentario de lnea, que debe co
menzar con los caracteres //, como por ejemplo:
; // Este es un comentario

38

u s r .c o d e

Las variables

El otro es el comentario clsico de! lenguaje C, que comienza con los caracteres f*
y termina de manera inversa, con los caracteres */:

/* Este es un comentario */

'

Este ltimo tipo de comentario puede ser multilnea; el siguiente es ejemplo de esto:

LAS VARIABLES
Las variables son utilizadas para almacenar datos. Sin embargo, para poder utilizar
una variable, en primer lugar deberemos declararla, a diferencia de lo que ocurra
en Visual Basic 6.0 o en algunos lenguajes de scripts.
La declaracin de una variable est compuesta mnimamente por dos elementos:
El tipo de dato.

El identificador.

El tipo especifica el tamao en memoria


asignado para el dato almacenado oor la va

fin de
sentencia

riable y el correcto modo de presentarlo.


El identificador es el nombre que tendr la
variable y que utilizaremos para referenciar-

A
int contador ;

la luego en el programa.
tipo identificador

Figura

1.

Declaracin de una variable.

Para que el compilador los acepte como vlidos, los identificadores debern seguir
ciertas reglas, similares a las existentes en otros lenguajes como C, C++, Visual Ba
sic o Java. Veamos:
Deben comenzar con una letra o un carcter de guin bajo (underscore).
Deben continuar con una letra, un nmero o un carcter de guin bajo.
No deben coincidir con una palabra reservada.
u s r .c o d e

39

PROGRAMACIN CU

Las palabras reservadas de C#


Todo lenguaje establece un conjunto de palabras reservadas que debern ser toma
das como prohibidas para la declaracin de cualquier tipo de dato definido por el
programador. En C# la lista de palabras reservadas es la siguiente:
abstraer
as
base
bool
break
byte
case
catch
char
checked
class
const
continu
decimal
default
delegate
do
doubie
else

' enum

8 long

8 stackalloc

* event
explicit
extern
false

8 namespace
8 new

8 static

finally
Fixed
0 float
for
foreach
goto
* if
8 implicit
8 in
inr
interace
8 internal
8 is
8 lock

8 nuil
8 object
8 operator
8 out
8 overtide
* params
8 private
8 proceded
8 public
8 readonly
8 re
8 return
8 sbyte
8 sealed
8 shori
8sizeof

string
8 struct
8 switch
8 this
throw
8 true
8 try
8 typeof
8 uint
8 ulong
8 unchecked
8 unsafe
* ushort
using
8virtual
8 void
8while

Ejemplos de dentificadores
Algunos dentificadores vlidos son:
MiVariable

contador

Contado_

mi_variable

USO DE MAYSCULAS Y MINSCULAS

Para C# et uso de maysculas y minsculas es importante. Una variable llamada contador es


distinta de otra llamada CONTADOR y de Contador. Sin embargo, a pesar de que crear varia
bles diferentes slo en la utilizacin de minsculas y maysculas es vlido, no es considerado
una buena prctica.

40

u t.c o d e

Las variables

Y algunos ejemplos de identificadores no vlidos:


IVariable: error porque comienza con un nmero.
$Variable: error porque comienza son un signo $.
###Contador###: error porque comienza con un signo #.
default: error porque default es una palabra reservada.
Claro que hay nombres mejores que otros. En un caso real, cuando estemos cons
truyendo nuestras aplicaciones, lo ideal ser que el identificador de una variable sea
seleccionado en funcin de un nombre que describa mejor lo que representa den
tro del programa. No es una buena idea coloar como identificador de una variable
el nombre Variable, aunque el compilador lo acepte.

Convenciones de nombramiento
Existen diversas convenciones de nombramiento para clases, variables, funciones,
etc. La idea detrs de estas convenciones es especificar reglas para la creacin de los
identificadores y que, de este modo, especialmente en grupos de trabajo, los nom
bres asignados sean similares en cuanro a estructura.
Una convencin que Microsoft sola recomendar era la notacin hngara. A gran
des rasgos, en dicha notacin se antepona como prefijo a los nombres de las varia
bles su tipo de dato (codificado en una o dos letras) y una m_ si era una variable
miembro, tina p_ si era un puntero, una g_. si era una variable global, etc.
Hoy da, esta notacin ya no es aconsejada con el mismo iervor, pues los editores
modernos rpidamente nos indican el tipo de dato al cual pertenece una variable, y
de este modo se pierde una de sus grandes ventajas. Sin embargo, a fin de cuentas,
es una cuestin de gustos. Lo importante ser mantener la misma convencin a lo
largo de todo el proyecto.
Este libro adopta la misma notacin que utiliza la librera BCL: notacin camello
para variables, y notacin Pascal para clases, estructuras, enumeradores, funciones,
mtodos, constantes y propiedades.
La notacin camello consiste en crear identificadores concatenando palabras sin ha
cer uso de caracteres especiales (como el underscore o el guin), sino colocando en
mayscula la primera letra de cada palabra, a excepcin de la primera.

unaVariableEntera

. .c o d e

contador

nombrePersona

41

PROGRAMACIN Cs

La notacin Pascal es similar a la camello, slo que la primera letra debe ser colocaa. e n m a y s c u l a .

ImprimirValor

FijarLargo

DameAltura

Quienes se encuentren interesados en ia notacin hngara, en el Apndice B en


contrarn su descripcin detallada.

Tipos de datos fundamentales


Hemos mencionado que una variable debe poseer un tipo. El lenguaje define un
conjunto de tipos de datos primitivos que pueden ser utilizados por nuestras varia
bles, propiedades y mtodos. Tambin podremos crear nuestros propios tipos por
medio de clases y estructuras, como ya veremos luego.
Una variable tiene asociada una posicin de memoria, que es donde realmente se
almacena el dato en cuestin. El identificador es, al fin y al cabo, una manera ami
gable de referirnos a ella. Podramos decir, entonces, que el tipo de dato es una ma
nera de comunicarle al compilador:
Cunto espacio en memoria ocupar la variable.
Qu semntica tendr el dato almacenado.
Un nmero entero podra ocupar en memoria la misma cantidad de espacio que un
nmero de punto flotante. El compilador sabr cmo interpretar la informacin
que all encuentre precisamente por el tipo de dato que posee la variable asociada a
dicha posicin de memoria.
Tambin es conveniente destacar que el compilador distingue entre los tipos de da
tos por valor y los tipos de datos por referencia. Esto tiene relacin con la zona de
memoria que se utiliza para crear la variable en cuestin: el

stack (pila) o el hen

(montculo). Los tipos de datos por valor sern almacenados en el stack, mientra.-.

BUSCANDO INFORMACIN DE NOTACIONES EN LA RED


Quienes deseen investigar acerca de notaciones en la Red, las siguientes palabras clave arrojarn
resultados interesantes: hungarian notation, prefix notation, camel notation. Pascal notation.

Las variables

que los tipos de datos por referencia sern almacenados en el heap (en el stack que
dar una referencia de la ubicacin en dicha zona de memoria).

Nmeros enteros
C# ofrece tres tipos de nmeros enteros:
short: nmero entero corto signado.
int: nmero entero signado.
long: nmero entero largo signado.
Si ambos son enteros, qu diferencia existe entre ellos? La respuesta es sencilla: la
cantidad de memoria que se deber reservar y cun grande es el nmero que cabr
dentro de nuestra variable.
En 2 bytes (short) es posible especificar un nmero con rango (-32768, 32767),
mientras que en 4 bytes (int) es posible especificar un nmero dentro del rango
(-2147483648,2147483647).
Por otro lado, los tipos de datos numricos enteros pueden ser signados o no. Si es
pecificamos un nmero entero corto no signado (ushort), seguimos ocupando 2 by
tes, pero al ser todos positivos, el rango vlido ahora es (0, 65533). Si intentamo:
asignar un nmero negativo a una variable no signada, se producir una excepcin.
Declarando algunas variables enteras:
short a;

// Entero corto signado

ushort b;

/./' Encero corto no signado

int d;
uint e;
long ;
ulong g;

UJ

ti
1!

Entero signado

// Entero no signado
Entero largo signado
Entere largo no signado

Y LOS PUNTEROS?

Quienes vengan de C o C*+ podran preguntar: dnde estn los punteros? C# permite el uso de
punteros igual queC++, pero para esto se deber marcar el bloque o funcin comounsafe (no rn
gurnj, adems de- modificar parmetros de compilacin, En C# su uso oueda relegado a necesi
dades especificas, como intersetuar con recursos no gestionados creados en otros lenguajes.

COOt

PROGRAMACIN CE

Diferencias con C/C++


Los ienguajes de programacin C/C++ permiten especificar tipos de datos no sig
nados como en C#, slo que vara el modo de declararlos. En C/C++ se debe espe
cificar el modificador unsigned delante del tipo de dato por modificar. Por lo tan
to, un entero signado se declarara:
//declaracin C++ o C#

int a;

Mientras que un entero no signado se declarara:


//declaracin C++
unsigned int a;
//declaracin Cjjjf

unit a;

La idea de reemplazar el unsigned int por un simple uint tiene que ver con facilitar
nos la vida a nosotros, los programadores.
Finalmente, existe tambin un tipo de dato llamado byte, en el cual se puede almace
nar, como su nombre lo indica, el valor de un byte. Su rango es (0,255) y es no signa
do, aunque es posible declarar un byte signado por medio del tipo de dato sbyte.

Nmeros no enteros
C# diferencia en tipo a un nmero entero de un nmero con parte fraccionaria: pa
ra estos nmeros de datos existen tres tipos: float, double y decimal.
La diferencia entre ellos es la precisin. Las computadoras se llevan muy bien con los
nmeros enteros, pero para trabajar con nmeros decimales necesitan utilizar un re
curso matemtico llamado coma florante. De esta manera es posible almacenar una
cantidad no fija de decimales, pero con una determinada precisin mxima; esta pre
cisin, en definitiva, se encuentra determinada por el tamao toral que ocupa la va
riable en memoria. Los tres tipos de datos de nmeros no enteros que maneja C# son:

float:

nmero no entero de precisin simple. Las constantes literales deben con


tener el agregado f en la parte decimal para que el compilador pueda tomarlas
como float (por ejemplo, 4 .0 f).

double: nmero no entero de precisin doble (por ejemplo, 4.0).


decimal: nmero no entero de precisin mxima. Las constantes literales deben
contener el agregado M en la parte decimal para poder ser tomadas con decimal
(por ejemplo,' 4.0M).
44

: .c o d e

Las variables

Declarando algunas variables no enteras:


float a;

// Precisin simple

double b;

// Precisin doble

decimal c;

// Precisin mxima

Booleanos

Las variables booleanas pueden albergar dos valores: true (verdadero) o false

[falso).

Declarando una variable del tipo booleana:


bool a ;

Caracteres
Para almacenar un carcter en una variable debemos especificar su tipo en

char.

Ejemplo:
char a;

Este tipo de datos puede albergar un carcter del tipo Unicode, pensado especial
mente para alfabetos orientales que poseen una cantidad de elementos mayor a 256.
Existen ciertos tipos de caracteres especiales que son interpretados por el compi
lador dentro de una cadena de texto. stos son conocidos como caracteres de esca
pe, y en la siguiente tabla pueden apreciarse algunos de ellos:

lnea nueva
. tab horizontal
backspace
retomo de carra
barra invertida

comilia doble

\n
\t
V
w

Tabla 2. Caracteres de escape.

De este modo, si escribimos en pantalla el siguiente texto:


ConBole .Write("\tTextol\nTexto2);

.c o d e

45

PROGRAMACIN Cfl

El primer carcter (\t) ser interpretado como un tab horizontal, y el carcter \n,
como una lnea nueva, por lo que en pantalla podremos observar:
Textol

Texto2
Lista de tipos de datos primitivos
En la siguiente tabla se describen los tipos de datos fundamentales del lenguaje.
UPO DE DATO
FUNDAMENTAL
bool

TAMAO EN BYTES
1

TIPO ESTRUCTURA
System.Boolean

DESCRIPCIN
Booleano. Su valor puede
ser tnie (verdadero) o false (falso)

sbyte

System.SByte

Byte no signado

byte

System.Byte

Byte

; char

System.Qtar

Carcter

short

System.lnll6

Entero corto

ushort

System.UIntl6

Entero corto no signado

int

System.lnt32

Entero

uint

System.Ulnt32

Entero no signado

long

System.lnt64

Entero largo

: ulong

System.Ulnt64

Entero largo no signado

float

System.Singie

Nmero no entero de precisin simple

double

System.Double

Nmero no entero de precisin doble

decimal

16

System.Decimal

Nmero no entero de mxima precisin

Tabla 3. Tipos de datos fundam entales de C#,

Como se puede observar en la tabla anterior, todo tipo de dato primitivo que defi
ne el lenguaje se mapea con una estructura de la librera BCL. Todos los lenguajes
que se construyen para la plataforma .NET debern hacer esta tarea, y de este mo
do la intercomunicacin entre ellos ser mucho ms sencilla debido a que, en defi
nitiva. utilizan ios mismos tipos de datos fundamentales
As es que declarar una variable entera como:
int a;

es exactamente igual a hacerlo del siguiente modo:

4(

COC

Las variables

System.Int32 a;

Notemos que el nombre de la estructura relacionada est compuesto por dos par
tes: el tipo de dato (con la primera letra en mayscula) y la cantidad de bits que
ocupa en memoria. De este modo tambin podemos inferir que un int siempre ocu
par 4 bytes, ms all de la plataforma en la cual estemos trabajando (algo que no
sucede en C o C++, donde la especificacin no ata los tipos de datos a tamaos f
sicos, sino que simplemente exige una relacin entre stos).

Asignar valor a una variable


Las variables pueden albergar valores, que estn relacionados con el tipo de dato de
la propiedad en cuestin.
Ya vimos cmo declarar variables, pero no sabemos an cmo asignarles valor. Pa
ra ello deberemos usar el operador de asignacin, que en C# es el signo igual (*).
Si declaramos una variable y la utilizamos sin antes inicializarla en algn valor, su
contenido ser indeterminado.
int a = 1;

En el caso expuesto hemos fijado el valor 1 a la variable a del tipo nmero entero
en la misma lnea en que declaramos la variable. Esto podra no ser as; los siguien
tes tambin son ejemplos vlidos:
int a;
I I ...

a = 1;

DNDE ESTN LOS STRINGS?


C# utiliza una clase que representa los strings y se llama string (o System.String). Esta implementacin es algo distinta del resto de tos tipos de datos, ya que stos son bsicamente estruc
turas. La razn es que en los strings, la cantidad de memoria que se requerir para la cadena
ser variable, dependiendo de su contenido. Declarando un string: string miVariableString.

l r . c o d e

47

PROGRAMACIN C*

operador de
asignacin
, ,
i
fin de
^
X - sentencia

a 4 ;

TT

variable i expresin

Figura 2 . El proceso de asignacin.

Constantes
Existen tres constantes:
Literales: especificadas por medio de un valor escrito en el cdigo.
int a = 25;
string nombre = "Tito";

En el caso citado,

25

es una constante literal al igual que Tito.

Simblicas: especificadas por medio de identificadorcs asociados a un literal. Son


ms recomendables que el uso de literales en modo directo, ya que en ciertos con
textos stos podran ser vistos como nmeros mgicos o sacados de una galera.
Estas constantes son muy similares a las variables, con la diferencia de que a stas
slo se les podr dar un valor en el momento de su declaracin. Luego, cualquier
intento de modificacin ser tomado como un error por parte del compilador.
Las constantes simblicas se declaran del mismo modo que las variables, aunque
se debe anteponer la sentencia const antes del tipo:
const int unaConstante = 1;

Enumeradores: finalmente, los enumeradores son el tercer tipo de constantes, y


adquieren gran utilidad cuando debemos especificar un grupo de constantes es
trechamente relacionadas.
Supongamos que deseamos que una variable pueda adoptar el valor de un mes es
pecfico del ao. Podramos definir que esta variable fuese numrica entera y

46

i : .c o d e

Las variables

adoptar Ja convencin de que su nmero equivaliera ai nmero del mes en cues


tin. Sin embargo, esta convencin debera estar especificada en algn docu
mento que se encuentre al alcance de todos los programadores; incluso nosotros,
tiempo despus de haber escrito el cdigo, podramos dudar acerca de si el mes
de enero era representado por el 1 o acaso por el 0.
Para evitar este tipo de inconvenientes y, tambin, que algn descuidado especifique
un nmero fuera de rango para el mes (por ejemplo, 13), sin tener que estar colocan
do cdigo que realice esta verificacin, podramos crear el siguiente enumerador:
enum Mes

{
Enero,
Febrero,
Marzo,
Abril,
Mayo,
Junio,
Julio,
Agosto,
Septiembre,
Octubre,
Noviembre,
Diciembre

Luego, podramos declarar una variable como del tipo Mes. Veamos:
Mes m;

Ahora, m slo podr adoptar los valores constantes especificados en el enumerador Mes.
m = Mes.Enero;

Si analizamos cmo declaramos el enumerador, observaremos que ste tiene la


palabra reservada enum antepuesta a un identificador, y luego existe una lista de
constantes separadas por comas dentro del cuerpo declarativo del enumerador
que est delimitado por llaves.
i.code

49

PROGRAMACIN C#

Estas constantes podran poseer un valor literal asignado a ellas por medio del ope
rador de asignacin:
enum Mes
{
Enero = 1,
Febrero = 2,
Marzo = 3 ,
Abril = 4,
Mayo = 5,
Junio a 6,
Julio = 7,
Agosto a 8,
Septiembre a 9,

Octubre a 10,
Noviembre a 11,
Diciembre a 12
}

En realidad, cada constante dentro de un enumerador siempre posee un valor lite


ral numrico asociado a ella, slo que si no lo especificamos, lo har automtica
mente el compilador, empezando por el nmero 0 e incrementando en una unidad.
De hecho, podramos consultar por el valor numrico asociado a una variable de ti
po enumerador por medio de conversiones de tipo, como veremos a continuacin.

Conversiones de tipo de datos


C# es un lenguaje muy estricto en cuanto a conversiones de tipo. Quienes provengan
de otros lenguajes como C o C++ se darn cuenta de esto enseguida, cuando el com
pilador arroje errores donde antes, utilizando otros lenguajes, arrojaba advertencias.
Existen dos tipos de conversiones: implcitas y explcitas.

III

MS ACERCA DE LOS ENUMERADORES

Dos constantes definidas dentro de un enumerador podran poseer el mismo valor numrico.
Esto seria til para definir constantes que sean sinnimos; por ejemplo, tanto "setiembre" como
"septiembre" podran estar relacionados con el valor 9.

Las variables

Las implcitas son las que realiza el compilador sin requerir de nosotros la especifica
cin de ninguna sentencia adicional. Este tipo de conversiones se caracteriza por el he
cho de que nunca se pierde informacin ni precisin. La conversin es siempre vlida.
En el siguiente ejemplo vemos cmo un nmero entero es convertido a un entero
largo. La conversin se da en la segunda lnea y es implcita.
int ni o 10;
long n2 = ni;

El otro ripo de conversin es explcito, y el compilador lo exige cuando podra ocu


rrir prdida de informacin o precisin.
long ni = 10;
int n2 - ni; // error

El cdigo anterior arrojar un error en la segunda lnea, pues el compilador no pue


de realizar dicha conversin de modo implcito.
Para realizar una conversin explcita deberemos utilizar una expresin de aistim .
Esto significa especificar el tipo de dato al cual deseamos llevar la expresin, ubica
do entre parntesis y antes de la expresin en cuestin:
long ni = 10;
int n2 = (int) ni; // realizamos un cast

Ahora, el compilador ya no protestar. Pero qu sucede si el nmero en ni es ms


grande de lo que podra albergar n2? Se pierde informacin! Es por esta razn por
lo que el compilador nos exige la conversin explcita, ya que es una manera de in

dicarle que nosotros sabemos lo que hacemos. Veamos el siguiente ejemplo:


long ni = Int64.MaxValue;
int n2 = (int) ni; // realizamos un cast

Como es de suponer, en n2 no quedar el mismo valor que en ni, simplemente


porque en n2 no hay lugar para albergar la magnitud que posee ni. Sin embargo,
ei compilador no arrojar error alguno. ;Cmo decirle al compilador que desee
mos ser alertados ante semejante circunstancia? Utilizando un bloque checked co
mo se muestra a continuacin:
.coat

PROGRAMACIN CU

long ni a Int64.MaxValue;
checked
{

int n2 = (int) ni; // realizamos un cast


}

Ahora, si la operacin fracasa, el compilador arrojar una excepcin. Esta excepcin


podr ser capturada y tratada como veremos ms adelante.
Y as como existe el bloque checked tambin existe su contrapartida, llamada un-

checked.

Cundo utilizaremos un bloque unchecked? Cuando el compilador no


nos permita realizar una operacin, a pesar de realizar una conversin de tipos ex
plcita como la siguiente:
short ni = 60000}

No hace falta ser un genio para saber que lo escrito en el cdigo anterior fracasar. El
rango de un short es de (-32768, 32767), por lo que 60000 es un nmero demasia
do grande. Tal vez el ejemplo sea trivial, pero si queremos que dicho cdigo sea com
pilado de todos modos, entonces deberemos encerrarlo en un bloque unchecked:
unchecked
{

short ni 60000;
}

La clase Convert
La librera BC L nos ofrece una clase llamada Convert dentro del espacio de nom
bres System, que es muy til en el momento de realizar conversiones. La gran va-

ERRORES DE CONVERSIN
Cuando el compilador no pueda realizar una conversin de tipos de datos, arrojar un error del tipo
"Cannot implicity convert type...". Un doble clic sobre dicho error nos llevar a la lnea desde la cual
proviene el mensaje. Deberemos pensar si hemos cometido algn error o si nos olvidamos de espe
cificar la conversin de modo explcito para sobrescribir el sistema de revisiones del compilador.

52

u s r .c o d e

Las variables

riedad de mtodos estticos que posee Convert nos permite pasar un tipo de dato
primitivo a cualquier otro tipo de dato primitivo.
Por ejemplo, la siguiente operacin no es vlida debido a que intentamos pasar de
un nmero entero a un tipo booleano.
bool a = 1;

Pero si, en cambio, escribimos:


bool a = Convert.ToBoolean(l);

Entonces la variable a, si recibe un nmero entero distinto de 0, ser true, y en ca


so contrario, false.

Operadores
Es posible combinar nmeros y variables en expresiones por medio de operadores
matemticos. Veamos:
int a

= 3+ 4;

int a

= 4;

int b

o a/ 2?

//
//

Almaceno el nmero 7 en a
Almaceno en b el

contenido de la variable

dividido por 2

int a

=10;

int b

= a* 14; //

Almaceno en b el

contenido de la variable

multiplicado por 14

Tambin podemos usar tipos de datos numricos decimales:


float a = 3.4f / 2;

Y podremos combinar tipos de datos en operaciones:


int a = 5;
float b = 4.3f;
float resultado = a * b;

u s r .c o d e

53

PROGRAMACIN CU

Sin embargo, cuando operamos de este modo es conveniente tener mucho cuidado,
ya que el tipo de dato resultante estar en funcin de la operacin que realicemos.
Por ejemplo, la suma de dos nmeros enteros dar como resultado un nmero en
tero, y la divisin de dos nmeros enteros tambin dar como resultado un nme
ro entero; esto ltimo es lo que precisamente puede traer muchos problemas.
Si yo le pregunto cul es el resultado de la operacin 5 dividido 2, usted seguramen
te contestar 2,5! Pero nuestra computadora, en cambio, nos devolver 2, ya que la
operacin fue entera y el resultado fue de enteros. Colocar una variable de tipo flo
tante al resultado no soluciona este inconveniente:
float a o 5 / 2>

// El resultado de la operacin ser 2!

Para solucionar este inconveniente deberemos convertir al menos uno de los operandos en flotante, para que, de este modo, la divisin no sea entre nmeros ente
ros, sino entre un entero y un nmero flotante:
float a = 5.Of / 2;

// Ahora el resultado ser 2.5

Uso de constantes en operaciones


Utilizar constantes en lugar de nmeros literales de manera directa es considerado una
buena prctica, ya que facilita la lectura y comprensin del cdigo fuente. Por ejemplo:
Constantes numricas literales:

superficie = 3.1415 * 16;


Constantes declaradas:

const float pi = 3.1415f;


superficie = pi * (radio*radio);

U U NMEROS MGICOS
Colocar una constante literal escrita sobre el cdigo sin explicacin alguna es una mala prctica
que suele denominarse "nmeros mgicos". Existe un muy buen libro llamado Code Complete,
de Steve McConnell, que cita muchas de las malas prcticas ms populares e indica cmo evi
tarlas. Lectura obligada si se desea ser un buen programador.

54

..c o d e

Control del flujo de ejecucin

El ltimo listado de cdigo es un poco ms legible. Ms all de lo trivial del ejem


plo, en otros casos podra no resultar obvio, en el anlisis de una expresin, que re
presentan determinados nmeros. En cambio, al ver una constante llamada pi r
pidamente entenderemos a qu nos referimos.

CONTROL DEL FLUJO DE EJECUCIN


Si especificamos un programa como un simple conjunto de operaciones sobre variables
e invocaciones a mtodos de clases, su ejecucin ser secuencial desde la primera Enea
hasta la ltima. Este escenario no es muy emocionante, y dista mucho de las necesida
des que poseen los programadores para la creacin de aplicaciones del mundo real.
Para esto el lenguaje C# ofrece un conjunto de sentencias que permiten controlar
el flujo de ejecucin, es decir, qu lnea de cdigo ser ejecutada por el procesador.
De este modo podremos indicarle a nuestro compilador que una determinada se
cuencia de instrucciones no debe ejecutarse slo una vez sino diez, o que una por
cin de cdigo debe ejecutarse slo si una variable es igual a 16 o, quizs, que repi
ta una porcin de cdigo hasta que el usuario presione una tecla determinada.

Sentencias condicionales
La primera sentencia que veremos ser la condicional if. Con esta sentencia podre
mos expresar, por ejemplo, que:

Si (expresin booleana>) entonces hacer sentencia [Si no, hacer sentencia]


La expresin usualmente es una comparacin utilizando los operadores:
OPERADOR

SIGNIFICADO
Igual a

tSBBBHBHRBBHflHBI
<

Menor a

>

M apa

<=

Menor o igual a

>-_ _ _ _ _ _ _ _ _ _ _ _ Mayor o Igual a_ _ _ _ _ _ _ _


Tabla 4. Operadores de comparacin.

u s r .c o d e

55

PROGRAMACIN CK

Veamos un ejemplo:
int a * Consol. In.PeekO;
if (a

'x')
Consol.Write("Has adivinado el carcter secreto*)}

En la primera lnea utilizamos el mtodo Peek para tomar un carcter desde la en


trada de consola. Luego verificamos si este carcter es igual a un carcter arbitrario.
Entonces a == Y es una expresin que se evala por verdadero o falso.
Si la expresin es verdadera, ingresamos en el cuerpo de la sentencia condicional;
el cuerpo siempre ser la sentencia prxima al cierre del parntesis que simboliza
el fin de la expresin booleana. Es posible que nuestra sentencia sea, en realidad,
un grupo de sentencias; en estos casos deberemos especificar un bloque de cdi
go con los caracteres llaves ({}); la llave abierta indica el comienzo de un bloque
de cdigo, mientras que la llave cerrada indica el fin del bloque. Veamos:
int a = Consol.In.Peek();
if (a s= 'x')
{

Consol.Write("Has adivinado el carcter secreto");


Consol.Write("Felicitaciones");
}

Otros lenguajes como Visual Basic utilizan otros criterios para exigir una sentencia
de fin de condicional, como End If o similares. C#, como C y C++, utiliza el con
cepto de bloques en todas sus sentencias. De hecho, las variables declaradas dentro
de bloques sern locales a stos.
Y qu ocurre cuando la expresin booleana especificada en el if se evala por falso?
Bueno, una sentencia condicional if debe poseer una sentencia que es el cdigo que
se ejecuta ante una evaluacin por verdadero de la expresin booleana, y puede o no

U U EL USO DE LAS SANGRIAS


Es muy recomendable el uso de sangras para mejorar la legibilidad de nuestro cdigo. Cuando
escribimos el cdigo del cuerpo de las sentencias if. lo hacemos dejando una sangra de una
determinada cantidad de espacios jusualmente cuatro). En los entornos de desarrollo integrado
y en casi cualquier editor de textos, lo hacemos por medio de la tecla TAB.

56

u s r.c o d e

Control del flujo de ejecucin

poseer una sentencia por ejecutar si la expresin es evaluada por falso (esta sentencia
debe ser precedida por la palabra clave else). Entonces, los escenarios posibles son dos:

U U QU TIPO DE SENTENCIAS PUEDEN ESCRIBIRSE?


El cdigo escrito en et cuerpo de un if no est limitado en ningn sentido. All podremos decla
rar variables, efectuar asignaciones, especificar otras sentencias, invocar funciones, etc.

u s r .c o d e

57

PROGRAMACIN C#

Como se puede apreciar en las Figuras

3 y 4,

el flujo

1 corresponde a una evalua

cin verdadera de la expresin, mientras que el flujo 2 corresponde a una evalua


cin por falso. Veamos el ejemplo de cdigo especificando la sentencia else:
int a Consol.In.Peek();

if (a

; {

'x')

Consola.Hrite('Has adivinado el carcter secreto*);


Consol.Nrite('Felicitaciones");

: }
; else

(
Consol.Write('Tal vez deberas intentarlo de nuevo*);

: }

Ntese que las llaves que colocamos en el cuerpo del else no son obligatorias en es
te caso, pues ste posee slo una lnea.

Y w A A J expresin
i V
r
1 booleana

,,/ A v
r

__

se

sentenda

Figura 5. Sintaxis de if.

expresin booleana

if(carss'a')
sentencia [

Consola.Nrite ('Verdadero*);
else

sentencia [

Consola, Write( 'Falso");

Figura 6. Ejemplo de la sentencia if.

56

u s r .c o d e

Control del flujo de ejecucin

Y qu ocurre si Jas opciones son mltiples? Si, por ejemplo, deseamos solicitar un
nmero del 1 al 3 y realizar diferentes acciones en funcin de la opcin elegida.
Bueno, nada nos impide escribir lo siguiente:
i (num == l)

{
. // opcin 1

}
else

{
if (num s= 2)

{
// opcin 2

}
else

{
if (num =e 3)

{
/./ opcin 3

}
else

{
// ninguna opcin

}
}
}

En el listado anterior hemos anidado sentencias condicionales if. Analicemos cmo


se ejecuta dicho cdigo.

Q Q OPERADOR DE IGUALDAD
Ntese que el operador de comparacin de igualdad es "==" y no

(que es el operador de asig

nacin). Esto, en un principio, podra confundirnos, sobre todo si venimos de otros lenguajes.
Afortunadamente, si nos equivocamos y utilizamos V en lugar de V , el compilador nos lo in
formar, ya que la expresin condicional debe poder ser evaluada por verdadero o por falso.

u s r .c o d e

59

PROGRAMACION Cfl

Supongamos que num es igual a 3.


1. Se evala num == 1. Como 3 es distinto de 1, entonces la expresin se evala por
falso y el flujo de ejecucin ingresa en el cuerpo else de la sentencia.
Dentro del else del primer if se encuentra otro if (esto es algo totalmente vli

2.

do); se evala la expresin num == 2 como falsa, ya que 3 es distinto de 2. Nue


vamente se salta al else del if, en este caso, del segundo.

3.

Dentro del segundo else nos encontramos con otro if con una expresin que
evala num == 3 por verdadero, ya que 3 es igual a 3. Entonces, el flujo de eje

cucin ingresa en el cuerpo que posee el comentario opcin

3.

Pero existe una manera de escribir lo mismo que mejora mucho la legibilidad.
if (a : '1')
1

opcin 1

else if (a

'2')

V
/'/ opcin 2
\
)

else if (a '3')
/
\
// opcin 3
elee

{
;// ninguna opcin

En esta siruacin, la idea es exactamente la misma. De hecho, el compilador no en


contrar diferencia alguna. Unicamente hemos eliminado las llaves de los bloques
else, ya que dentro de stos existe slo una sentencia if (no tiene importancia que
a su vez esta sentencia posea ms de una lnea u otras sentencias dentro), y hemos
modificado el uso de las sangras.

Operadores lgicos
Dentro de los parntesis del if debemos colocar una expresin booleana. Dicha ex
presin puede ser trivial, como, por ejemplo:

60

u s r .c o d e

Control del flujo de ejecucin

bool 3alir = true;


if (salir)
Salir_del_prograraa

En el ejemplo citado, la expresin slo consiste en una variable. Esta expresin, co


mo cualquier otra, ser evaluada por verdadero o falso.
Pero qu sucede si queremos ejecutar ciertas instrucciones slo si a es igual a 1 y b
es igual a 2? Entonces podremos crear una expresin del siguiente modo:
if (a :: 1 U

b *= 2)

Hacer_algo
i

'

' ,

..-i.,: ;

El operador && es el operador lgico AND, por lo que nuestra expresin fue equiva
lente a decir: Si a es igual a 1 Y b es igual a 2, entonces....
Por lo tanto, slo ingresaramos en el cuerpo de la sentencia if cuando la expresin

a == 1 y la expresin b == 2 se evaluaran por verdadero.


Tambin podramos desear realizar una determinada accin cuando a fuera igual a

1 o b fuera igual a 2.
if (a

En ese caso utilizaramos el operador lgico OR (| |):

1 || b = 2)

Hacer_algo

De este modo podramos crear expresiones an ms complejas combinando opera


dores lgicos a nuestro gusto, pero siempre deberemos tener como meta la creacin
de un cdigo lo ms legible posible, ya que, recordemos, ste no ser ledo slo por
una computadora.

ir

&&

Y lgico (conjuncin)

0 lgico (disyuncin)

I_ _ _ _ _ _ _ _ _ _ _ _ Negacin lgica
Tabla 5. Operadores lgicos.

La sentencia switch
La sentencia

switch

nos permite modificar el flujo de ejecucin en funcin de la

evaluacin de una expresin. Es ideal para ciertos casos; por ejemplo, cuando una
u s r .c o d e

61

PROGRAMACIN C#

variable puede tomar un valor de un conjunto de valores conocidos y deseamos ac


tuar en consecuencia. Podra reemplazar el uso de sentencias if anidadas como en
el ejemplo visto anteriormente.
switch

(expresin)

case
case
case

expresin constante

(sentencia)

expresin constante : (sentencia]


expresin constante : (sentencia)

(break;]
[break;]
[break;]

[default: (sentencia) break;]


1

'

Suponiendo que num sea una variable de tipo entera, veamos el siguiente ejemplo:
switch (num)

{
case 1:
Consol.Write("Opcin 1*);
break;
case 2;
Consol.rite("Opcin 2*);
break;
case 3:
Consola.rite("Opcin 3');
break;
default:
Consol.rite("Ninguna opcin");
break;

Como podemos apreciar en el listado anterior, num se coloca como expresin para
evaluar por el switch. Luego, en cada case colocaremos los valores posibles de esta
variable que deseemos tratar. El break impide que el flujo de ejecucin salte de un

case al siguiente, aunque en realidad esta exigencia es heredada del uso en otros len
guajes como C, C++ o Java, ya que, de todos modos, en C# no se permite el salto
silencioso de un case a otro.
Si quisiramos ingresar en el

case 2),
62

case

1, por ejemplo, y saltar de aqu al siguiente (el

deberamos escribir:
u s r .c o d e

Control del flujo de ejecucin

switch (num)

{
case 1:
Consol.Jritfl'Opcin 1")

goto case 2;

case 2:
Consol.Write('Opcin 2');
break;
case 3:
Consol.Write('Opcin 3*);
breakj
default:
Consol.tirite ("Ninguna opcin*);
break;

En el caso de que el tratamiento de una opcin sea igual al de otra, podremos escribir:
: switch (num)

{
case 1:
case 2:
Consol.tirite ('Opcin 1 o 2*)
break;
case 3;
Console.WriteCOpcin 3');
breakj
default:
ConBole.Write'Ninguna opcin*);
break;

}
En el caso de que ningn valor de num coincida con los case que hemos especifi
cado, lo que podemos hacer es colocar un default que funcionara como una es
pecie de else final a toda la sentencia, y slo se ingresar aqu si no se ingresa en
ningn

u s r .c o d e

case. El default no tiene por qu ir al final de la lista de todos los case.

63

PROGRAMACIN C#

n i
wmam

CUNDO UTILIZAR UN SWITCH

La sentencia

switch suele utilizarse cuando una variable slo puede adoptar un nmero estable

cido de valores constantes y para cada valor se debe realizar un tratamiento diferente.

64

u s r .c o d e

Control del flujo de ejecucin

expresin a evaluar
1 1

switch(num)
{
expresin__ r f j |
constante
LjCfig

casel:
Consol.Write( "uno")j
break;

expresin
constante

r
U .

2
cuerpo de
sentencia
switch

Consol.Write(*dosn);
break;
default:
Consol.Write( "tres');
breakj
}

Figura 8. Ejemplo de la sentencia switch, case y default.

Equivalencias entre las sentencias condicionales if y switch


El uso de la sentencia if o switch es, en ciertos casos, una cuestin de gustos, aun
que la verdad es que con un if se podr hacer todo lo que con un switch, pero el ca
so inverso no es cierto. Veamos algunas analogas:
Ejemplo 1:

switch (man)

if (num >= 1 && num < 3)


Console.Writefuno, doB o treB*);

else if (num = = 4 || num == 5)

case 1:

Consola.Write("cuatro o cinco");

case 2:
case 3:
Consol.Write("uno,
dos o tres');
break;

.
.

case 4:
case 5:
Consol.Write{"cuatro

u s r .c o d e

65

PROGRAMACIN C#

Ejemplo 2:
switch (nua)

if (num 1)
Consola.Writa("uno") ;

{
caae 1:

else if (nua 2)

Consol. Write("uno) ;
break;

ConBole.WriteCdos*);
else

caae 2:

Consol.Write ("otro1');

Coneole.Write^doB);
break;
default:
Consol.Write("otro");
break;

Sentencia de bucle
En algunas ocasiones requeriremos que determinada porcin del cdigo escrito sea
repetida una cierta cantidad de veces o hasta que se cumpla una determinada con
dicin. C# cuenta con varias sentencias para cumplir este fin.

La sentencia while
La sentencia while (que significa

mientras)

indica que una sentencia o grupo de

sentencias debe repetirse mientras una expresin asociada sea verdadera.

mientras (expresin booleana>) hacer <sentencia>

m i LA CONDICIN DE TERMINACIN DEL BUCLE


La expresin booteana det bucle mientras" debera ser verdadera en ciertas circunstancias y
luego, en algn momento, tornarse falsa, Si la expresin NUNCA fuese verdadera, jams se in
gresara en el cuerpo del bucle. Si la expresin SIEMPRE fuese verdadera, nuestro programa ja
ms se terminara, ya que nunca saldramos del bucle.

66

u s r .c o d e

Control del flujo de ejecucin

while

expresin
booleana

y *

sentencia

Figura 9. Sintaxis de while.

expresin booleana

while(numlsO)
{
//...
//...

cuerpo de la
sentencia while

//...
}

Figura 10. Ejemplo de la sentencia while.

Supongamos que queremos escribir un programa que, mientras ei usuario no ingre


se un nmero determinado, no termine:
string palabraClave = **;
while (palabraClave 1= "salir*)

{
Consol.WriteLine("Ingrese la palabra clave:*);
palabraClave = Consol.In.ReadLine0;

}
Consol.WriteLine("Correcto*);

Analicemos el cdigo anterior:


En la primera lnea declaramos una variable de tipo cadena y la inicializamos. Esta
variable contendr el texto que se ingrese por teclado.
Inmediatamente despus se evala la expresin encerrada entre parntesis de la sen
tencia while; en este caso podramos traducir la lnea

u s r .c o d e

67

PROGRAMACIN C#

while (palabraClave 1= "aalir)

como: mientras la variable palabraClave sea distinta de "salir"... Si la expresin es


evaluada por verdadero, ingresaremos en el cuerpo del while; de otro modo, salta
remos a la lnea inmediatamente despus del cuerpo de ste.
En este caso una cadena vaca es distinta de la palabra "salir"; por lo tanto, ingresa
mos en el cuerpo del while.
Dentro del while enviamos a la salida estndar el texto "Ingrese

la palabra clave:" y

volvemos a capturar el texto ingresado por teclado.


Terminada la ltima lnea de cdigo del cuerpo del while, se vuelve a evaluar la ex
presin "palabraClave != salir". En este caso, si es verdadero o falso depender de lo
ingresado por el usuario. El cuerpo del while ser ejecutado hasta que la expresin
se evale como falsa.
Ntese que la expresin booleana que se evala en el while puede ser, as como vi
mos con el if, una expresin formada de diversas comparaciones conectadas entre
s por operadores lgicos.
while (a 1= 3 && b 20

//

c < 10)

...

Esto se traduce como mientras

nor de 10....

a sea distinto de 3 Y b sea igual a 20 Y c sea me

La sentencia do
Con el while, el bloque de cdigo por repetir no ser ejecutado nunca si la expre
sin es falsa la primera vez. En ciertas ocasiones nos vendra bien ejecutar dicho c
digo al menos una vez, y luego evaluar la expresin.
Para esto existe otra sentencia llamada do:

hacer <sentencia> mientras (expresin booleana>);


Como podemos apreciar, la sentencia

do es muy similar a la sentencia while,

slo

que cambi el momento en el cual se evala la expresin.

68

u s r .c o d e

Control del flujo de ejecucin

ii
d.

sentencia

while

Figura 11. Sintaxis dowhile.

do
cuerpo de la
sentencia do...while

{
punto y coma

}while(num**l);

expresin booleana

Figura 12. Ejemplo de la sentencia dowhile.

u s r .c o d e

69

PROGRAMACIN Ctt

Veamos un ejemplo:
atring palabraClave;
do

{
Consol.Write("Ingrese la palabra clave\n*);
palabraClave = Consol.In.ReadLine();
} while (palabraClave 1= 'salir*);
Consol.Write("Correcto*);

El programa es muy similar al anterior, aunque esta vez no necesitamos inicializar


la variable a un valor conocido, ya que sta es sobrescrita antes de evaluar la expre
sin por primera vez.
Entonces, el "Ingrese la palabra..." siempre ser ejecutado al menos una vez. En el
programa anterior (del uso del while), si la variable palabraClave fuese inicializada
en "salir", el bloque interno a l nunca sera ejecutado.

La sentencia for
En ciertas ocasiones tendremos la necesidad de ejecutar un bloque de cdigo un n
mero determinado de veces. C# ofrece para estos casos una sentencia llamada for.

para (<sentencia>; expresin booleana>; <sentencia>) sentencia a repetir>


La primera sentencia slo se ejecuta una vez. Luego, la expresin se evala antes de
ingresar en cada bucle, y la segunda sentencia se ejecuta al finalizar cada bucle. Vea
mos un ejemplo:
for (int i*0; i<5; i++)
Consol.WriteLine('.

BUCLES INFINITOS

En todo programa en que se utilicen sentencias de repeticin, existe la probabilidad de que se in

while siempre fue


while nunca acabara y, por lo tanto, nuestro programa tampoco.

grese en bucles infinitos. Esto significa, por ejemplo, que si la expresin de un


se verdadera, el

70

u s r .c o d e

Control del flujo de ejecucin

La primera sentencia es:


int i0

Aqu declaramos e inicializamos una variable que slo ser vlida dentro del cuer
po del for (una vez terminado ste, dicha variable no existir ms, es local a la sen
tencia al bloque del for). Esta sentencia slo se ejecutar la primera vez que ingre
semos en el ciclo.

i<5
Mientras dicha expresin booleana sea vlida, se ejecutar el cdigo especificado en
el cuerpo del for.

i++
Sentencia que se ejecuta en cada ciclo, incrementa en uno el valor de la variable i.
Indefectiblemente dicha variable llegar a 5; por lo tanto, la expresin "i<5" se eva
luar a falsa y el for habr terminado. Por ese motivo, el cuerpo del for, en este ca
so, se ejecutar cinco veces del siguiente modo:
Se ejecuta la sentencia "int i=0" (esta sentencia slo se ejecuta una vez).
Se evala la expresin "i<5". En este caso "0<5" es verdadero, por lo tanto se in
gresa en el cuerpo del for.
bucle 0: se ejecuta Consol.WriteLine().
bucle 0: se ejecuta la sentencia "i++". En este caso i se incrementa en 1 y pasa a
valor 1.
Se evala la expresin "i<5". En este aso
gresa en el cuerpo del for.
bucle 1: se ejecuta Console.WriteLine ().

"1<5"

es verdadero, por lo tanto se in

bucle 1: se ejecuta la sentencia "i++". En este caso i se incrementa en 1 y pasa a


valor 2.
Se evala la expresin "i<5". En este caso "2<5" es verdadero, por lo tanto se in
gresa en el cuerpo del for.
bucle 2: se ejecuta Console.WriteLine

().

bucle 2: se ejecuta la sentencia "i++". Por tanto, i aumenta en 1 y pasa a valor 3.


Se evala la expresin "i<5". En este caso "3<5" es verdadero, por lo tanto se in
gresa en el cuerpo del for.
u s r .c o d e

71

PROGRAMACIN C#

bucle 3: se ejecuta Console.WriteLine

().

bucle 3: se ejecuta la sentencia "i++". En este caso i suma 1 y pasa a valor 4.


Se evala la expresin "i<5". En este caso "4<5" es verdadero, por lo tanto se in
gresa en el cuerpo del for.
bucle 4: se ejecuta Console.WriteLine

().

bucle 4: se ejecuta la sentencia "i++". En este caso, i suma

1 y pasa a valor 5.

Se evala la expresin "i<5". En este caso "5<5" es falso, por lo que se sale del bucle.

Figura 13. Sintaxis de For.

72

u s r .c o d e

Control del flujo de ejecucin

Equivalencias entre el for y el while


Como ocurre entre el if y el switch, donde en ciertos casos el uso de una u otra sen
tencia es una cuestin de gustos, con el for y el while ocurre lo mismo.
Veamos ahora algunos ejemplos de cdigo que controlan el flujo de programa del
mismo modo, a pesar de utilizar distintas sentencias:
Ejemplo 1: en este caso sera ms lgico utilizar el for.
for (int i=0; i<5; i++)

int i=0;

Consol. Wr i te (\..\nB);

while (i<5)
{
Consol.Write("...\nH) ;
i++;
}

Ejemplo 2: en este caso sera mis lgico utilizar el while.


string palabraClave =

String palabraClave *

for (; palabraClave 1= "salir";)

While (palabraClave != "salir")

u s r .c o d e

73

PROGRAMACIN Ctf

{
Conaole.Writet*.*);

Coaflole.WriteC.1');

PalabraClave * Consol. ReadLinet);

palabraClave Console.ReadLineO;

*h'*i

fcf!*

i -i"

'

C'*>
<

vv

La sentencia foreach
Existe una ltima sentencia de repeticin que es muy til para trabajar con colec
ciones de datos.
Si bien todava no hemos introducido el tema de colecciones ni el de arrays, nos
adelantaremos un poco simplemente para poder explicar esta poderosa sentencia
que se encuentra (desgraciadamente) ausente en lenguajes como C o C++.
Una coleccin es un conjunto de elementos, en general, del mismo tipo, aunque
no necesariamente. Utilizando algn tipo de coleccin se puede definir un conjun

to de n elementos, con la posibilidad de acceder a cada uno de ellos por medio de


un subndice. Veamos cmo declararlo haciendo uso de un array clsico:
intU enteros new int [3];

Ahora podramos acceder al primer elemento utilizando el operador de indexacin []:


enteros[0] 100;

Y al segundo elemento:
i
enteros 11] 500;

Y al tercero (y ltimo):
enteros [2] <* 900;

Ntese que el acceso a elementos del array se encuentra basado en cero (y no en


uno, como en otros lenguajes).

74

u s r .c o d e

Control del flujo de ejecucin

Trabajar con arrays puede ser muy cmodo, pero no lo sera tanto si el lenguaje no
ofreciese sentencias adecuadas para manipularlos. La sentencia for es una de ellas.
Supongamos que deseamos inicializar los elementos de un array en un determina
do nmero; un modo de hacerlo sera escribiendo:
int {J enteros = new int (3];
for (int i=0; ixenteros.Length; i+t)
enteros(i] o 0;

Si modificamos el tamao de nuestro array y pasamos de 3 a 300 elementos, la sen


tencia for permanecer inalterada.
Pero la sentencia for no es la nica que ofrece el lenguaje para este tipo de casos.
Existe otra llamada foreach que permite manipular arrays de una manera ms ami
gable, si es que esto es posible.

Por cada (<tipo> <elemento> en <coleccin>) <sentencia>


Veamos cmo iterar por todos los elementos de una coleccin para visualizar su
contenido en pantalla:
foreach (int num in enteros)
Consol.Write("nmero {0}\n", num);

Dentro del parntesis del foreach primero declaramos una variable que oficiar de
elemento activo de la coleccin; sta es seguida de la palabra clave in y, finalmente,
la coleccin por la cual deseamos iterar.
Entonces, en cada iteracin, en lugar de tener que acceder al elemento por subn
dice, directamente hacemos uso de la variable elemento declarada. Slo cabe la
salvedad de que el uso de la variable elemento es slo para lectura, no podremos
practicar una asignacin con ella.

QU ES LA PROPIEDAD LENGTH?

Length es una propiedad de los arrays que nos indica la cantidad de elementos que ste posee.

Ms adelante, cuando profundicemos sobre este tema, analizaremos los mtodos y propiedades
para trabajar con ellos.

u s r.c o d e

75

PROGRAMACIN CU

Figura 15. Sintaxis de foreach.

Variable elemento'

j Variable "coleccin

---1 i---1
-- 1

foreach (int elem in nmeros)

{
//solo lectura de la
j

Cuerpo de la
sentencia foreach

//variable elem

//...
}

Figura 16. Ejemplo de la sentencia foreach.

76

u s r .c o d e

Control del flujo de ejecucin

Tal vez en este momento no puedan apreciarse las ventajas del uso prctico del fo-

reach por sobre la sentencia for.


Cuando analicemos ios distintos tipos de colecciones veremos que resulta ms c
modo acceder a ciertos grupos de elementos de este modo, debido a que no siem
pre es posible acceder a elementos por medio de subndices como es usual hacer
dentro del cuerpo de una sentencia for.

La sentencia break y continu


Hemos visto cmo se utiliza la sentencia break dentro de sentencias swith/case. No
obsrante ello, el break puede ser usado con diversas finalidades. Se utiliza para salir
del bucle en el cual nos encontramos, independientemente de la expresin que se
evala iteracin tras iteracin.
En numerosas oportunidades, su uso no es considerado una buena prctica, pero
deberemos tenerlo en cuenta como una herramienta ms que podremos utilizar en
el futuro, en caso de que nos haga falta. A continuacin, observamos un sencillo
ejemplo del uso del break:
int i = 0;
while (i < 10) -

{
Consol.Wri teLine("punto a");
i++;
if (i . 3)
break;

Cuando "i == 3" se evala como verdadera, salimos del bucle while y seguimos con
la prxima lnea posterior a ! (de la misma manera en que habra ocurrido si la ex
presin "i < 10" hubiese sido falsa).

U U QUE EXISTA NO SIGNIFICA QUE DEBAMOS UTILIZARLO


Siempre se debe dar por terminado un bucle por la evaluacin por falso de su expresin boolea
na. Utilizar la sentencia break suele ser considerado una mala prctica porque altera el f ujo de
ejecucin normal que debera realizar el bucle, lo que empobrece la legibilidad de nuestro pro
grama y aumenta las probabilidades de cometer un error.

u s r .c o d e

77

PROGRAMACIN C#

Figura 17. Modificacin del flujo de ejecucin ante un break.

Tambin puede ser aplicada en sentencias for:


for (int ioO; i<10; i++)

{
Consol.WriteLine("punto a");
i (i > 3)
break;

La sentencia continu, en cambio, nos permite saltearnos lo que resta de una itera
cin dentro de un bucle para seguir con la prxima (sin salir del bucle). Veamos un
ejemplo con un while y con un for:
int i = 0;
while (i < 10)

{
Consol.WriteLine("punto a");
i++?
if (i > 3)
continu;

78

L .'.c o d e

Control del flujo de ejecucin

Console.WriteLine("punto b");

for (int iaO; i<10; i++)

{
Console.WriteLine("punto a");
if (i > 3}
continu;
Console.WriteLine("punto b")j

}
Llegado el momento de ejecutar el continu, las instrucciones que resten de la ite
racin en curso sern salteadas y se dar comienzo a la prxima iteracin.

1 RESUMEN
Por el momento la programacin con C# parece ser bastante similar a C++ o a Java; cuando
comencemos a analizar detenidamente las clases que ofrece la librera BCL junto con las
facilidades del lenguaje, veremos que estamos ante un lenguaje de programacin nico.

u s r .c o d e

79

ACTIVIDADES

TEST DE AUTOEVALUACIN

Dnde se encuentra el error en los si

d)

guientes listados?

int num = 0;
al

if (num == 0)
Consol.Write ("Es valor");

int ni = 10;
double n2 = ni;
float n3 = n2;

Consol.Write("es cero!");
else
Consol.Write("El valor
es distinto de cero*);

bl
2 Para qu se utilizan los espacios de nom

int valor;

bres? Qu funcin cumplen?

if (valor == 0)
Consol.Write("el valor
es cero!");

3 Cmo se puede convertir un string que


posea un nmero en su interior a una va
riable numrica? Es una conversin se
gura en todos los casos?

c)
for (int i=0, i<5, i++)
Consol.Write(".");

80

:.c o d e

PROGRAMACIN C#

Clases
y objetos
En este captulo estudiaremos
la anatom a de la estructura ce datos
m s im portante del lenguaje: la clase.
Veremos corno declarar constantes,
variables y m todos dentro de ella.
Tambin introducirem os otro tipo
de dato muy im portante, la estructura.
Y, finalm ente, explicaremos
qu es el recolector de basura.

Qu es una clase
Cmo declarar una clase
Modificadores de acceso
Instanciacin. Creando objeto?
Constantes de una clase
Variables estticas
Los mtodos

servicio de atencin al lector: lectores@ m pediciones.com

Estructuras
Resumen
Actividades

PROGRAMACIN C#

QU ES UNA CLASE
Una clase es una estructura de datos que utilizaremos para definir nuestros propios
tipos que extendern los primitivos que provee el lenguaje.
La mayora de las veces, las clases se utilizan por medio de sus instancias, las cuales
se denominan objetos. Los objetos del mismo tipo (diferentes instancias de la mis
ma clase) compartirn una estructura comn, pero podrn poseer valores distintos
en sus variables miembro.
Podramos trazar una analoga entre una clase y sus objetos con lo que es un mol
de y los elementos creados a partir de l. Una clase define una serie de variables y
comportamientos por medio de los cuales podremos crear objetos que poseern di
chas variables y comportamientos.
La cantidad de objetos que podremos crear a partir de una clase slo estar limita
da por la cantidad de memoria que posea el sistema.

CMO DECLARAR UNA CUSE


En C# las clases se declaran dentro de archivos de cdigo fuente con extensin CS.
Se utiliza esta terminacin por convencin, y se trata de archivos que contienen
texto y que pueden de ser abiertos por cualquier editor de textos, como por ejem
plo, el Bloc de notas.
A diferencia de lo que podemos ver en C++, aqu no encontraremos un archivo
de declaraciones (.H) y otro de definiciones (.CPP), sino que, por el contrario, to
do el cdigo que est relacionado con una o ms clases deber ser incluido den
tro de un mismo archivo. Lo ms normal es colocar una clase por archivo CS, pe
ro podemos incluir la cantidad que nos parezca conveniente.

[U

CLASES EN LENGUAJE JAVA

i;
En Java, el archivo de cdigo fuente suete terminar en ".java" y, a diferencia de C#, muchos corr'
piladores slo aceptan una clase pblica por archivo.

y : ::
LU A,a

82

'
-> r. A
V'-i|||

u s r .c o d e

Cmo declarar una clase

MiClase,cpp

M i C la s e . e s

La clase MiClase
en lenguaje Java

La clase MiClase
en lenguaje C++

La clase MiClase
en lenguaje C#

Figura 1. Tipos de archivo utilizados para declarar clases en diversos lenguajes.

Entonces, cmo se declara una clase? Veamos:

Figura 2. Declaracin de una clase.

O en cdigo:
class <dentificador>
// cuerpo de la clase

En primer trmino, debemos escribir la palabra reservada class, y luego, un identificador vlido que cumpla con las reglas que habamos mencionado en el captulo
anterior. Este identificador debe ser nico en un espacio de nombres. Algunos identificadores vlidos podran ser:
Clase1
Esta_es_una_clase
_mi_clase
_miClase_

u s r.c o d e

83

PROGRAMACIN CU

Y,i!o recordar que el hecho de que el nombre sea aceptado por el compilador no sig
nifica que ste sea un buen nombre. Mejor sera que el identificador de la clase
fuera seleccionado en funcin de un nombre que describiera mejor lo que represen
ta dentro del programa (por ejemplo,

Cliente, Producto, Cuadrado, etc.).

Modificadores de acceso
Dentro de lo que llamamos cuerpo de la clase se colocarn la declaracin y la de
finicin de todos sus miembros, que sern datos y mtodos.
Las variables miembro de una clase se declaran como variables convencionales (co
mo vimos en el captulo anterior), pero pueden poseer algunos modificadores espe
ciales. Un modificador muy utilizado es el de acceso, que regula la visibilidad que
posee la variable o el mtodo desde otros objetos.
Siempre es posible acceder a las variables de una clase desde los mtodos declarados
en ella, ms all de su modificador de acceso. Para otros mtodos de otras clases, s
tos impondrn limitaciones, que son:

public: si la variable es declarada como pblica, entonces es posible acceder a su


contenido desde cualquier objeto de cualquier tipo.

protected: si la variable es declarada como protegida,.entonces no es posible acce


der a su contenido desde objetos externos, pero s es posible hacerlo desde mto

dos de la clase y clases derivadas.


prvate: si la variable es declarada como privada, entonces slo es posible acceder
a su contenido desde mtodos de la clase, pero no desde mtodos de clases deri
vadas. Por default, si no se especifica otra cosa, una variable es privada.

internal: si la variable es declarada como interna, entonces slo es posible acce

der a su contenido desde mtodos de clases que se encuentren dentro del mis
mo assembly.

protected internal: si la variable es declarada como protegida interna, entonces es


posible acceder a su contenido desde mtodos de clases que se encuentren ubica-

U j C++BUILDER CON PROPIEDADES


El compilador de Borland, C++Builder, ofrece una funcionalidad de propiedades muy similar a
C#. Sin embargo, esta extensin est fuera de la especificacin estndar del lenguaje y requiere
el uso de libreras de Borland, lo que restringe la portabilidad de la aplicacin,

84

u s r .c o d e

Cmo declarar una clase

das dentro del mismo

assembly, mtodos que se encuentren situados en la mis

ma clase y en clases derivadas..


Veamos cmo declarar algunas variables:
clase Foo

M
int a;

// Variable del tipo entero llamada "a"

Ahora la clase Foo posee como uno de sus miembros a una variable del tipo nme
ro entero. Esta variable ser privada, pues no se ha especificado otra cosa.
Veamos cmo incluir los modificadores de acceso:
class Foo

{
public int a;
protected int b;
prvate int c;

t. , . \

- ,.;v

..

..

rT*f - . '

Veamos: ahora nuestra variable a fue declarada del tipo pblica, la variable b como
protegida, y la c como privada (aunque especificar prvate no es necesario, en mu
chas ocasiones se realiza para remarcar su condicin).

Diferencias con C++


En C++ los modificadores de acceso se especifican no por dato o mtodo, sino por
tandas de variables y mtodos. En las clases, por default, sus elementos son priva
dos, pero si escribimos "public:" modificamos el acceso de todo lo declarado poste
riormente a pblico. Ejemplo:
class Foo

{
int a; // variable privada
public:
int b; // variable pblica
int c; // variable pblica

u s r .c o d e

85

PROGRAMACIN CU

int d; // variable pblica


protected:
int e; // variable protegida

int f; // variable protegida


privats:
int g; // Nuevamente, variable privada

Instanciacion
Una vez que hemos definido nuestra clase, para poder utilizarla debemos crear una
instancia de ella (aunque es posible acceder a variables y mtodos estticos sin la ne
cesidad de crear objetos de la clase; ms adelante profundizaremos en este aspecto).
La declaracin de un objeto es muy similar a la de cualquier otra variable. Recorde
mos que una clase es, al fin y al cabo, la definicin de un nuevo tipo. Pues bien,

objeto es una variable que lleva por tipo una clase.

un

Suponiendo que ya hemos definido la clase Foo, ahora podramos crear un objeto
de ella del siguiente modo:
Foo miObjeto;

Pero esto no es suficiente! Si bien ya declaramos que miObjeto ser una variable de
tipo Foo, los objetos requieren ser definidos de manera explcita por medio del ope
rador new.
miObjeto = new Foo();

Ahora s, podremos acceder a todos los elementos del objeto. Tambin podramos
haber declarado y definido el objeto en la misma lnea:
Foo miObjeto = new Food;

miObjeto pero no hiciramos uso del


definido asociado a l y cualquier in

Pero ;qu sucedera si declarramos el objeto


operador newr El objeto poseera el valor no

tento de acceso a sus elementos provocara un error de compilacin, ya que el com


pilador advertira esta situacin.
86

usr.code

Cmo declarar una clase

(
Veamos, ahora, cmo instanciar un par de objetos y acceder a variables de stos. Su
pongamos que nuestra clase Foo posee una variable a y otra b, ambas enteras.
Foo objl = new FooO;
Foo obj2 = new Foo();
objl.a a 10;
obj2.a a 20;
Console.WriteLine("Valor de la variable a del objeto objl: {0}", objl.a);
Console.WriteLine{"Valor de la variable a del objeto obj2: {O}", obj2.a);

Tanto objl como obj2 son instancias de la dase Foo; sin embargo, ambos objetos son
independientes entre s. Poseen la misma estructura, pero el valor dentro de sus va
riables puede ser totalmente diferente.
A continuacin, analicemos de qu manera hemos realizado la asignacin de valo
res a las variables de los objetos.
No podramos haber colocado slo el nombre de la variable, pues el compilador no
podra haber determinado a qu objeto nos estbamos refiriendo. Entonces, la sin
taxis correcta es colocar el nombre del objeto, el operador de seleccin (el punto),
la variable, el operador de asignacin y, finalmente, la expresin.

operador de
seleccin

operador de
' asignacin

miObjeto . a o 4 ;
J

U U

objeto
expresin

J
fin de
'sentencia

propiedad

Figura 3. Cmo utilizar una variable miembro en la asignacin.

Constantes de una clase


As como hablamos de constantes locales que se pueden declarar en un trozo de c
digo, tambin es posible declarar constantes en el cuerpo de una clase. Las constan
tes pueden poseer los mismos modificadores de acceso que las variables.
u s r .c o d e

87

PROGRAMACIN Ctt

C'idoS Foo

{
public coDBt int a 10;

//

...

>
Ahora a ya no es variable, sino constante, para todos los objetos del tipo Foo.
Ntese que hemos inicializado la constante en la misma lnea en que la declaramos.
Esto es algo obligatorio en este tipo de dato.
Pero, adems, tiene una caracterstica adicional: puede ser accedida o consultada sin
requerir instanciacin alguna, es decir, sin la necesidad de crear un objeto de Foo.
Por qu? Porque no tiene sentido almacenar en objetos valores que sern iguales
para todos ellos sin excepcin. Veamos, entonces, cmo acceder a una constante:
int b = Foo.a;

Como podemos apreciar en la lnea de cdigo anterior, creamos una variable tem
poral b y le asignamos el valor de la constante de la clase Foo. Ntese que no crea
mos un objeto de Foo, sino que utilizamos directamente el identificador de la clase
seguido del operador seleccin y la constante.

Variables estticas
Las variables estticas, al igual que las constantes, pueden ser accedidas sin la nece
sidad de instanciar un objeto. Sin embargo, su valor puede ser modificado como
cualquier otra variable. Podramos pensar en ellas como variables de clase, siendo
las variables tradicionales variables de objeto.

P | INICIAUZADORES
Cuando una variable se iniciaiiza en la misma lnea que su declaracin dentro del cuerpo de la
clase, se dice que posee un nicializador. Como vimos anteriormente, las constantes de una cla
se deben poseer un nicializador.

88

u s r .c o d e

Cmo declarar una clase

Este tipo de variables, al igual que las constantes o las variables convencionales, pue
den poseer los mismos modificadores de acceso (public,

prvate, protected, etc.).

Para declarar una variable como esttica, bastar con agregarle el modificador static
como prefijo al tipo de dato.
class Foo

{
int a = 1;
const int b = 1;
static int e l ;

En el listado de cdigo anterior, hemos declarado:


La variable a como un nmero entero. Ntese que hemos inicializado dicha va
riable en 1 en la misma lnea que su declaracin.
La variable b como una constante entera.
Y, finalmente, a c como una variable esttica entera. Tambin la hemos inicializa
do a un valor conocido, aunque esto no es obligatorio.
Veamos cmo hacer uso de este nuevo tipo de variables:
Foo.c = 30;

// Accedo a la variable esttico

Foo objl = new Foo();

// Creo un objeto

= 10;
// Muestro el valor de c

// Accedo a su variable a

objl.a

Consol.WriteLine("El valor de c es; {O}*, Foo.c);


// Muestro el valor de a
Consol.WriteLine("El valor de objl.a es: {0}*, objl.a);

Los mtodos
Las clases slo con variables y constantes no resultan demasiado interesantes. Tam
bin es posible declarar funciones dentro de una clase. Estas funciones (ms cono
cidas como mtodos) contienen el cdigo que ser ejecutado por nuestro programa
cuando stas sean invocadas.
Una funcin miembro o mtodo posee:

u s r .c o d e

89

PROGRAMACION C#

Un tipo de dato: es el devuelto por la funcin cuando sta finaliza.


Un identificador: es el nombre por medio del cual referenciaremos al mtodo
dentro de nuestro programa; lo utilizaremos para invocarlo.

Parmetros: es una lista de variables que recibe el mtodo. Esta lista puede estar
vaca o poseer tantos elementos como queramos.
En la Figura 4 se puede apreciar un diagrama de sintaxis de la funcin. Cabe des

tacar que la funcin debe ser declarada dentro del cuerpo de una clase y puede po
seer modificadores que veremos ms adelante.

Figura 4 . Diagrama de sintaxis de una funcin.

90

u s r .c o d e

Cmo declarar una clase

Veamos cmo declarar un mtodo de la clase Foo:


class Foo

{
public int valor;
// Imprime la variable valor
void ImprimirValor()

{
Console.WriteLine(valor);

}
// Mtodo principal del programa
static void Main(string(] args)

{
Foo obj = new Foo()j
obj.ImprimirValor();

}
}

Veamos: declaramos la variable miembro valor. Luego, declaramos el mtodo ImprimirValor, que simplemente enva a la consola de salida el valor de la variable del objeto.
Para invocar un mtodo en un programa, siendo ste un mtodo convencional de
objeto, deberemos anteponer su nombre y el operador de seleccin de miembros (el
punto); luego se deber colocar entre parntesis todos los parmetros que requiera
la funcin (si la funcin no recibe parmetros, simplemente se abren y se cierran los
parntesis). Tal y como hicimos en el ejemplo anterior dentro de la funcin

Main.

Mtodos estticos
As como las variables estticas pueden ser consideradas como variables de clase,
existen mtodos estticos que pueden ser considerados como mtodos

de clase. Es-

H U MS ACERCA DEL MTODO MAIN


Recordemos que en nuestra aplicacin, una de nuestras clases debe poseer un mtodo esttico
llamado Main, que servir como punto de entrada a la aplicacin; es decir, que contiene el cdi
go que se ejecutar primero en nuestro programa.

u s r .c o d e

91

PROGRAMACIN C#

too

mtodos deben poseer como prefijo al tipo de dato de retorno la palabra reser

vada static. Claro que stos tendrn algunas limitaciones: no podrn acceder a va
riables de objeto (es decir, variables no estticas) o mtodos de objetos (mtodos
convencionales no estticos).
El modo de invocar un mtodo esttico es por medio del identificador de la clase
en lugar del identificador del objeto (as como sucede con las variables estticas).
Muchas clases de la librera BOL definen mtodos estticos. Hemos estado utilizan
do el mtodo esttico WriteLine de la clase Consol. Ahora veamos cmo definir
nuestros propios mtodos estticos.
claaa Foo

{
//

...

public static void ImprimirFechaActualO

{
Consol.Write("La fecha actual es: {0}\nn , DateTime.Now

);

//-------------------------------// Mtodo principal del prograna


static void Mainlstring args)

{
Foo. ImprnirFechaActual ();

}
}

Como se puede apreciar, el mtodo esttico ImprimirFechaActual no hace uso de va


riables no estticas del objeto, en este caso invoca un mtodo esttico de una clase
de la librera BCL que se utiliza para manejar fechas.

III

LA ESTRUCTURA DATETIME

El manejo de fechas sola ser un problema en muchos lenguajes. Especialmente cuando deba
mos interactuar con otros programas o bases de datos, ya que el formato de almacenamiento de
stas era distinto. Pero la librera BCL ofrece una estructura llamada DateTime que simplifica el
manejo y unifica el almacenamiento de este tipo de datos para todas las plataformas.

92

u s r .c o d e

Cmo declarar una clase

Luego, es conveniente notar el modo en que invocamos la funcin dentro de Main: uti
lizamos el nombre de la clase, no tuvimos la necesidad de instanciar ningn objeto.

Retornar valores
Hemos mencionado que los mtodos pueden retornar valores o no. Si no devuel
ven ningn valor, simplemente se especifica que el tipo de dato de retorno sea void.
Veremos cmo declarar y utilizar un mtodo cuando ste devuelve un valor entero:
class Foo

<

public int valor;


public int ValorAlCuadradoO

{
return valor * valor;

}
/ / ------------------// Mtodo principal del programa
atatic void MaintetringU args)
Foo obj = new Foo();
obj .valor o 9;
Consol.WriteLine(,'gl valor del objeto objl al cuadrado
es: {O}", obj.ValorAlCuadradoO);

Como podemos apreciar, el mtodo ValorAlCuadrado retorna un tipo de dato int, y


dentro del cuerpo de la funcin todos los posibles flujos de ejecucin deberan ter
minar con alguna sentencia de retorno, caracterizada por el uso de la palabra reser
vada return y una expresin de un tipo coincidentc con el valor de retorno de la
funcin. De no existir esta sentencia de retorno dentro del cuerpo de la funcin, el
compilador nos avisar por medio de un error en la construccin del programa. En
nuestro ejemplo, se devuelve el valor multiplicado por s mismo.

Utilizar parmetros
La declaracin de parmetros en las funciones se realiza de modo muy sencillo.
Bsicamente, son declaraciones de variables (del modo en el que nos estamos
acostumbrando a realizarlas) separadas por el carcter coma (necesario si es que
hay ms de un parmetro).
u s r .c o d e

93

PROGRAMACIN Ctt

Analicemos el siguiente caso:


clase Foo

{
prvate int valor;
bool FijarValor(int

val)

{
if (_val >= 0 && _val < 10)

{
valor

val;

return trae;

}
elae
return falsa;

}
int DaaeValorO

{
return valor;

/ / -------------------------------// Mtodo principal del programa


static void Main(string[] arga)

{
Foo ob j =new Foo ();
obj, FijarValor (55);
Consol.WriteLine("El valor es {0}", obj.DameValorf));
obj.FijarValor(5);
Consol.WriteLine("El valor es {0}", obj.DameValorO);

}
}

En el ejemplo anterior, lo que deseamos hacer es acceder a una variable privada por me
dio de dos mtodos: uno que fija el valor a la variable y otro que la retorna. Muchas ve
ces esta funcionalidad es deseada para realizar una verificacin del upo de dato fijado a
la variable. Normalmente todas las variables miembro son privadas y se accede a ellas
por medio de mtodos de este tipo o a travs de una funcionalidad especial que posee
el lenguaje C#, que se denomina propiedades y que luego trataremos en detalle.

94

u s r .c o d e

Cmo declarar una clase

Por ahora, nos tomaremos la licencia de no utilizar propiedades y seguir con el m


todo que deben utilizar lenguajes orientados a objetos, como C++, que no dispo
nen de esta caracterstica. En nuestro ejemplo, la regla que imponemos de manera
arbitraria es que la variable valor de la clase Foo debe ser fijada con un rango de (0,
9). De otro modo, la funcin devolver false y el valor no ser modificado.
Analizando el cuerpo de la funcin Main podemos observar que, a pesar de que la
funcin

FijarValor

retorna un valor booleano, ste no es utilizado para nada. Y es

que nadie nos obliga a hacer uso del valor de retorno de una funcin. Lo negativo
de nuestro accionar es que no tendremos certeza si el valor es fijado satisfactoria
mente por el mtodo, pues no nos encontramos de alertas a la informacin que nos
brinda con respecto a esto.
Posteriormente, veamos que el valor de retorno de la funcin
mos directamente como parmetro de la funcin

WriteLine;

DameValor lo utiliza

esto es algo totalmen

te vlido y, al mismo tiempo, muy prctico.

Pasajes de valor por copia


Usualmente los parmetros se transfieren por copia de valores (a excepcin del pa
saje de objetos, como veremos luego). Analicemos el siguiente caso:
class Foo

{
public static void IntentarModificarValor (int iValor)

{
iValor = 10;

}
}

Si utilizamos la clase Foo del siguiente modo:


int num;
num *

99;

Foo. IntentarModificarValor(num

);

Consol.Write(num) ;

podremos observar que en

num,

a pesar de que la funcin

IntentarModificarValor

ha reescrito otra cosa, contina conservando el valor que le hemos pasado.


Esto sucede debido a que el parmetro iValor de la funcin es una copia de la va
riable num; slo son numricamente iguales, pero nada ms. Las dos variables se
encuentran en posiciones de memoria distintas.
u s r .c o d e

95

PROGRAMACIN C#

Figura 5. Pasajes de valor por copia.

96

u s r .c o d e

Cmo declarar una clase

Pasajes de valor por referencia


Pero en ciertos casos no es conveniente que el pasaje de parmetros se realice por
valor. Existe un modificador, que es posible anteponer a la declaracin de parme
tros, que cambia el modo en que stos son transferidos; en lugar de realizar un pa
saje por copia de valores, se realiza un pasaje por referencia.
Veamos cmo realizar este tipo de pasaje de parmetros:
class Foo

{
public static void IntentarModificarValor (ref int iValor)

{
iValor = 10?

}
}

Como podemos observar en el listado anterior, el parmetro entero iValor posee la


palabra clave ref antepuesta a la declaracin del tipo. Luego, en el cuerpo de la fun
cin se utiliza iValor como si fuese una variable convencional.
int num;
num s 99;
Foo. IntentarModificarValor(ref num);
Consol.Write(num);

Analizando el cdigo anterior, podremos notar que anteponemos la palabra ref a la


variable que pasamos como primer parmetro.
Y ahora, el mtodo IntentarModificarValor realmente lo modificar. La Figura 6 ilus
tra lo que ocurre paso por paso en la ejecucin de este programa.

III

QU ES UNA REFERENCIA?

Una referencia es bsicamente una variable que contiene la direccin de memoria de otra varia
ble pero que oculta esta naturaleza. Por lo tanto su manipulacin es prcticamente idntica a la
de cualquier otra variable.

u s r .c o d e

97

PROGRAMACION CS

98

u s r .c o d e

Cmo declarar una clase

Parmetros de salida
Qu sucede si necesitamos que nuestra funcin devuelva ms de un valor? Existen
varias alternativas. Es posible especificar que ciertos parmetros sean parmetros de
salida exclusivamente por medio del modificador out.
Supongamos que estamos creando una clase con funciones matemticas, algo as co
mo la clase Math. Deseamos crear un mtodo que devuelva el seno y el coseno de
un nmero pasado como parmetro.
Siendo sta la situacin, podramos retornar el seno como parmetro y el coseno co
mo valor de la funcin, o al revs, o incluso podramos devolver el resultado de am
bas operaciones en parmetros. Veamos:
class HiClaseDeMatemtica

{
public static void SinCos(double dValor, out doubla dSn, out
double dCo3)

{
dSin = Math.Sin(dValor);
dCos = Math.Cos(dValor);

}
}

Como podemos observar en la lista de parmetros de la funcin SinCos, el segundo


y el tercer parmetro poseen como prefijo la palabra reservada out. Esto significa
que ambos actuarn exclusivamente como parmetros de salida.
double dCoseno, dSeno;
MiClaseDeMatemtica.SinCos(0.78, out dCoBeno, out dSeno);
Console.WriteLine("Coseno: {0}", dCoseno);
Consol.KriteLine("Seno: {O}*, dSeno);

Analicemos el cdigo anterior:


1. Declaramos dCoseno y dSeno como dos variables locales del tipo double. Ntese
que declaramos ambas en la misma lnea, colocando el tipo de dato slo una vez
y separando los dentificadores por una coma. Esto es algo totalmente vlido y
es un modo de tipear menos cuando debemos declarar varias variables del mis

u s r .c o d e

99

PROGRAMACIN C#

mo tipo. No importa que dCoseno y dSeno no sean inicializadas, la funcin

Sin-

Cos deber otorgarles un valor.


Invocamos el mtodo esttico SinCos haciendo uso del nombre de la clase, pues

2.

SinCos es esttico.
3. Anteponemos a las variables dCoseno y dSeno la palabra reservada out.
4. Finalmente, imprimimos los valores retornados en parmetros.
De lo expuesto, hay dos cosas importantes que es conveniente destacar:
La funcin deber otorgar valores a todos los parmetros de salida en cualquier
caso (dicho de otro modo: ningn camino de ejecucin puede terminar la fun
cin sin al menos inicializar los parmetros de salida en algn valor).

SinCos no puede leer parmetros ingresados en ella con modificador


out: son exclusivamente parmetros de salida.

La funcin

El mtodo constructor
Qu ocurre si deseamos realizar cierta accin no bien el objeto es creado? Debe
ramos anunciarles a todos los programadores de nuestro equipo que recuerden in
vocar un mtodo arbitrario luego de crear el objeto en cuestin? Por suerte, no.
Existe un mtodo especial que es invocado cada vez que un objeto nuevo es creado
de forma automtica.
Dicho mtodo se denomina constructor, y su identificador debe ser exactamente el
mismo que el de la clase de la cual forma parte. Veamos un ejemplo:
using System;
class Foo

Foo (}

{
Consola.WriteLine("El mtodo constructor");

n ------------------------// Mtodo principal del programa


static void Main{string[] args)

{
Poo = new Foo();

}
}

100

u s r .c o d e

Cmo declarar una clase

Si ejecutamos el programa anterior, veremos que cuando el objeto es creado, es de

cir, cuando realizamos un new de Foo, inmediatamente el mtodo Foo() es invocado.

Tambin notemos que el mtodo constructor al cual nos estamos refiriendo no

po
see tipo de dato de retorno. Esto es lgico, pues los constructores no se invocan
como mtodos convencionales, sino que son invocados automticamente por el framework cuando se crean los objetos.

Aprovechando las caractersticas de polimorfismo que posee este lenguaje y en los que
profundizaremos ms adelante, es posible crear ms de un constructor, cada uno con
diferente cantidad de parmetros o con distintos tipos como parmetros. De este mo
do es posible crear un objeto al mismo tiempo que se le transfiere un parmetro.
clase Vector2

{
float x = O.Of;
float y a O.Of;
Vector2()

{
Consol.WriteLine("El mtodo constructor sin parmetros");

}
Vector2(float

x, float

y)

{
x =

x;

y * _y;
Consol.WriteLine("El mtodo constructor con dos
parmetros float");

}
void MostrarValor ()

{
Consol.WriteLine(*({0}, {l})", x, y);

}
/ / ------------------// Mtodo principal del programa
static void Main (string (] args)

{
Vector2 vecA = new Vector2();
vecA.MostrarValor();
Vector2 vecB = new Vector2(5.0f, 10.Of);
vecB.MostrarValor();

}
}

u s r .c o d e

101

PROGRAMACIN C#

La dase Vector2 pretende representar vectores de dos dimensiones; para esto po

(x e y) que son del tipo float y que son inicializadas a


O.Of cuando el objeto es creado. Aunque las variables miembro de un objeto (no

see dos variables miembro

las variables locales!) son inicializadas a cero cuando son creadas, no est de ms
recordar que esto es posible. Dentro del cuerpo de la funcin Main creamos dos ob
jetos de los dos modos posibles: invocando el constructor sin parmetros e invocan
do el constructor con dos parmetros.
Luego creamos un mtodo llamado

MostrarValor, que arroja en pantalla el conteni

do del objeto. Este mtodo lo utilizamos para ver en qu valor estn las variables de
cada objeto inmediatamente despus de construir el objeto.

El mtodo constructor de copia


Es posible especificar un constructor de copia para poder crear un objeto que sea
igual a otro en contenido de datos. Veamos cmo crear el constructor de copia de
la clase Vector2 que creamos recientemente:
" t _ j i i i f

' ~ t V i 4 ' t f l i i t i l ' ~ C jgvu . i r

C-

KT

Vector2(Vector2 copiarDesde)

{
x copiarDesde.x;
y = copiarDesde.y;
Console.WriteLine("El mtodo constructor de copia*);

Y veamos cmo utilizarlo:


Vector2 vecA * new Vector2();
vecA.MostrarValorO;
Vector2 vecC =. new Vector2(vecA);
vecC.MostrarValor{);

INVOCACIN DE CONSTRUCTORES
Es posible que un constructor invoque otro constructor. Esto suele realizarse cuando parte de a
tarea de inicializacin es comn a todos los constructores; no tendra ningn sentido duplicar c
digo. Simplemente se llama el constructor correspondiente -desde el otro constructor-, como si
fuese un mtodo convencional.

102

u s r .c o d e

Cmo declarar una clase

El primer vector lo creamos de la manera convencional, pero al crear el segundo en


viamos el primero como parmetro. De este modo se ejecuta el constructor de co
pia de vecC, el cual toma los valores del objeto recibido y se los copia para s. Pero
por qu no podramos escribir lo siguiente?:
Vector2 vecA = new Vector2 0;

vecA.Mo8trarValor ();
Vector2 vecC = new Vector2(vecA);
vecC = vecA; //' Nocoooccc!
.

.v" V .

'

TiV ^ * . ''-.A % ,

. '*

Para entender qu est mal con la ultima lnea, hay que ahondar en el aspecto te
rico de los objetos y cmo los maneja el lenguaje C#.
Al comienzo del Captulo 2 mencionbamos que existen dos tipos de datos distin
tos para el lenguaje: los manejados por valor y los manejados por referencia.
Los tipos de datos primitivos son manejados por valor, mientras que los objetos
(instancias de clases) son manejados por referencias.
Entonces vecA,

vecB y vecC son, en

realidad,referencias. Observemoscmo fondona

realmente el operador de asignacin ejemplificadocon variables enteras y con objetos.

int num 1;

numl - 50;

float num2;

u s r .c o d e

! stack

numl

50

num2

no definido

103

PROGRAMACIN C#

num2 =98.5f;

! stack

numl

50

num2

98.5f

Vector2 vecA;

stack

numl

50

num2

98.5f

vecA

no definido

-------------- L

i
vecA =newVector2();

T-------------

Vector2 vecC =new Vector2();

| stack

numl

50

num2

98.5f

vecA

referencia vecA f

vecC

referencia vecC

1---

i heap

,J1

objeto vecA

r^fetO VdcC

j.

vecC =vecA;

' stack

numl

50

num2

98.5

vccA

referencia vecA

vecC

referencia vecA

Figura 7. Operador de asignacin.

104

u s r .c o d e

Cmo declarar una clase

Detengmonos a analizar lo visto en la figura anterior. En primer lugar podemos


ver cmo las variables que son de tipos de datos primitivos son creadas directamen
te sobre el stack. Aqu no existe referencia alguna, y si queremos copiar una a otra,

el funcionamiento es el esperado.
Luego, podemos apreciar que los objetos, al ser manejados como referencias, poseen
un comportamiento diferente. En primer lugar, el objeto en s es creado en otra zo

na de memoria, llamada heap, y en el stack slo queda una referencia a l (que es la


direccin de memoria en donde se encuentra realmente).

Finalmente, si asignamos el objeto vecA al objeto vecC, lo que haremos ser copiar
la referencia y no el contenido del objeto. Esto podra no ser lo que esperbamos.
Por lo tanto, el modo correcto de copiar un objeto sobre otro ser utilizando un
constructor de copia (los programadores avanzados de otros lenguajes podran pen
sar que tambin sera posible sobrecargar el operador de asignacin, pero en C# es
te operador en particular no es sobrecargable).

Destruccin de objetos

Un objeto se crea cuando solicitamos memoria para l por medio del operador new,
momento en el cual se invoca el mtodo constructor que corresponda.
El objeto poseer un

ciclo de vida.

Despus de haber sido creado, haremos uso de

l y, llegado un momento, dejar de sernos til y desearemos poder destruirlo y re


cuperar la memoria que en un principio habamos solicitado.
C# gestiona la memoria de modo automtico; para esto provee un recolector de ba
sura (garbage collector) que se encarga de eliminar la memoria que en algn mo
mento se solicit y que ya no se utiliza ms (cuando, por ejemplo, se han perdido
todas las referencias a ella).
En la tabla de figuras donde explicbamos cmo funciona el operador de asignacin
con objetos, en un determinado momento la memoria en la cual se encontraba el

III

CUNTA MEMORIA OCUPA NUESTRO PROGRAMA?

El mtodo ms sencillo -aunque no tan preciso- de averiguarlo ser mirando el proceso que
corresponda a nuestra aplicacin desde el Administrador de tareas.

u s r .c o d e

105

PROGRAMACIN C#

objeto vecC queda aislada, es decir que se pierde toda referencia a ella. En un len

guaje como C++ esto generara un mcmory leak, y dicha zona de memoria quedara
reservada hasta que finalmente el programa terminara y el sistema operativo recu
perara toda la memoria que estaba usando.
En cambio, C#, gracias a su recolector de basura, advertir esta situacin y recupe
rar dicha memoria para dejarla nuevamente disponible a nuestro programa. Pero
cuando ocurrir estol
En el lenguaje de programacin C# no existe el operador contrario a new (como s
existe en C++, donde dicho operador se denomina delete). La destruccin de un ob
jeto no es un proceso determinstico, es decir que no podremos controlar exacta

mente el momento en el cual la memoria asignada en el hcap vuelve a ser memoria


disponible para ser utilizada en otros objetos.
Lo que s podemos indicarle al sistema es cundo un objeto deja de sernos til. Pa
ra esto bastar con pisar la referencia que tenamos de un objeto por el valor nuil:
// Construimos el objeto
Vector2 vecA = new Vector2();
// Hacemos uso del objeto
//

...

/ / L e indicamos al sistema que ya no lo precisamos


vecA e nuil;

A partir de ese momento, cuando el recolector de basura advierta esta situacin, to


mar cartas en el asunto. Pero el instante preciso en el que lo har realmente queda
fuera de nuestro alcance.
El recolector de basura se asegura de que:

USO DE LA MEMORIA POR PARTE DE OBJETOS


Cada objeto instanciado ocupar un tugar en memoria, esto ya lo dijimos. Sin embargo, cabe des
tacar que un objeto no poseer todos los datos en su porcin de memoria: las constantes y las
variables estticas, por ejemplo, estarn ubicadas en un lugar nico, relacionadas con su clase.
Ntese que un objeto del tipo Foo poseer una variable a totalmente independiente de las dems.

106

u s r .c o d e

Cmo declarar una clase

Los

objetos sean destruidos. En C++, un lenguaje sin gestin automtica de me-

<

moria, es muy comn olvidarse de destruir los objetos que ya no son utilizados,
lo que genera memory

Los

leaks.
objetos sean destruidos slo una vez. Un error muy comn en C++ es eli-

minar el mismo objeto dos veces, lo que provoca un grave error.

Se destruyan objetos que ya no son utilizados. En C++ muchas veces se des


truyen objetos que son referenciados an en otras reas del programa.

El recolector de basura trabaja cuando:


La memoria

disponible es poca. La bsqueda de objetos no referenciados (inal

canzables) es una tarea que consume recursos, por lo tanto slo debe realizarse
cuando es imperioso.

La aplicacin est finalizando.


El programador lo invoca manualmente. Aunque es posible, no es recomenda
ble (modo de invocar recoleccin de basura: System.GC.Collect()).
El destructor es un mtodo que se invoca cuando el objeto es destruido. All podremos colocar el cdigo necesario para desinicializar el objeto (cerrar archivos abier
tos, conexiones de red, canales abiertos hacia dispositivos de hardware, etc.). Su
declaracin es similar al constructor, slo que posee el carcter ~ como prefijo.
i class Vector2

i i ...
~Vector2()

{
//' Cdigo de desinicializacin
// ...
Consol.WriteLine("Destructor");

'

>
.//

...

Supongamos que tenemos un archivo abierto. Cerrar el archivo en el mtodo des


tructor no estara mal; de este modo nos aseguraramos de que antes de que el re
colector de basura eliminara nuestro objeto, el archivo estara cerrado.
Sin embargo, el mtodo destructor slo puede ser invocado por el recolector de ba
sura (v esto lo hace justo antes de desasignar la memoria del objeto). Como no po
lis .c o d e

107

'

PROGRAMACIN CU

demos establecer cundo el recolector de basura har su trabajo, entonces tampoco


podremos establecer cundo el archivo ser cerrado (o la conexin de red o el canal
hacia el dispositivo de hardware), y esto s podra ser un problema.
Una alternativa propuesta por Microsoft es la del patrn de diseo Disposal. sta
consiste en crear un mtodo especfico que contenga todo el cdigo de desinicializacin. Este mtodo podr ser invocado manualmente por nosotros cuando nos
plazca (a diferencia del destructor). El objeto podr no haber sido retirado de la me
moria, pero al menos las relaciones con otros elementos habrn sido debidamente
cerradas. De lo que debemos asegurarnos es de que:
Dentro de este mtodo llamemos a SupressFinalize. En los siguientes prrafos ve
remos para qu hacemos esto.
El mtodo de desinicializacin se cree de tal manera que pueda ser invocado en
ms de una oportunidad.
Evitemos utilizar recursos desasignados por el mtodo posteriormente.
Veamos cmo hacerlo:
class Vector2

{
//

...

public void Dispose()

{
// Desasigne recursos

...

Console.WriteLine("Dispose");
GC.SupressFinalize(this);

}
}

H U I QU SUCEDE CUANDO UN PROGRAMA AGOTA LA MEMORIA?


C u an d o e l s is te m a co m ie n za a q u e d a rs e s in m e m o ria , v u e lca la s a p lic a c io n e s que no se e n c u e n
tran en uso en la m e m o ria v irtu a l (dentro d e un g ran a rch ivo en n u e stro d isco). F in a lm e n te , c u a n
do la m e m o ria v irtu a l se lle n a , se g e n e ra n ex ce p cio n es y se so licita m e m o r ia a l sis te m a .

108

u s r .c o d e

E s tru c tu ra s

Luego, haciendo uso de alguna instancia de Vector2:

//

C o n s tr u im o s e l

o b je to

Vector2 vecA = new Veetor2();


/ / Hacemos u s o d e l o b j e t o
//

...

/ / D e s a s ig n a m o s r e c u r s o s

vecA.DispoeeO ;

Entonces, ahora invocando este mtodo arbitrario podremos estar seguros de cun

do

los recursos son desasignados (a excepcin de la memoria ocupada por el obje

to, de la cual, como mencionamos anteriormente, no poseemos control).


Y de qu se trata el mtodo SupressFinalize? Este mtodo recibe la referencia this co
mo parmetro (que no es otra cosa que una referencia al objeto que se est ejecutan
do). De esta manera queremos decirle al sistema gracias, pero ya he desasignado

todos los recursos que eran necesarios, por favor, no invoques mi mtodo des
tructor. Cuando llegue el momento, el recolector de basura eliminar nuestro obje
to del hcap sin invocar nuestro destructor previamente, por expreso pedido nuestro.

ESTRUCTURAS
Una estructura es un tipo de dato muy similar a una clase. Es una alternativa livia
na a stas y puede contener prcticamente todos los elementos que puede poseer la
clase, como variables, mtodos, propiedades, constantes, etc.
La diferencia principal que posee la estructura respecro a la clase es que Ja estructu
ra es un tipo de dato manejado por valor, a diferencia de la clase, que es maneja
da por referencia. Esta simple distincin repercute en muchos aspectos de uso que
ya analizaremos; por ahora veamos cmo declarar una de ellas recreando la idea del

Vector2, pero esta vez, desde una estructura:


3truct Vector2

{
float x;
float y;
public Vector3(float _x, float _y)

u E T .co d e

109

PROGRAMACIN CU

{
x c

x;

y _y;

}
void MostrarValorO

{
Consol.WriteLine(*({0}, {l})",

x,

y);

}
}

Como podemos apreciar en el listado anterior, lo nico que parece haber cambiado
es la palabra clave class por struct. Sin embargo, existen otras diferencias ms pro
fundas, como:
No es vlido inicializar las variables en la misma lnea que su declaracin (ntese
que los inicializadores estn ahora ausentes).
No es posible especificar constructores sin parmetros (ntese que hemos elimi
nado dicho constructor).
No es posible especificar destructores para ellas.
No es posible practicar herencia con ellas. Todas las estructuras son derivadas de
la clase Object (como rodo tipo de dato de C#) de manera fija, no es posible espe
cificar que derive de ninguna orra clase, y ninguna clase puede derivar de una es
tructura (en el prximo captulo ya veremos con detenimiento qu es la herencia).
Y ahora veamos diferencias en su utilizacin:
Vector3 vecA;
vecA.x = 10.Of;
vecA.y = 20.Of;
vecA.MoBtrarValor();

Analizando el cdigo anterior, notamos inmediatamente que hemos invocado el


mtodo MostrarValor sin haber solicitado memoria para el objeto . El asunto es que
las variables del tipo estructura no son objetos. El lenguaje maneja estas variables
por valor (como el resto de los tipos de datos primitivos), entonces no requieren que
se solicite memoria explcitamente.
Las estructuras son asignadas en el stack, mientras que. poi el contrario, los objetos
son asignados en el
110

heap.

..c o r ie

E s tru c tu ra s

Cabe destacar que, para poder utilizar una estructura, es necesario previamente asig
narles valor a todas sus propiedades; de otro modo, el compilador arrojar un error.
Tambin es posible hacer uso del operador new con la estructura, en especial si de
seamos invocar algn constructor en particular. Todos los constructores deben pro
veer de valor a todas las variables de la estructura. Si no especificamos constructor,
existe un constructor implcito predeterminado que inicializa todas las variables
(pero es invocado slo si utilizamos el operador new). Por lo tanto, tambin podra
haber sido vlido especificar:
Vector3 vecA = new Vector3{10.0f, 20.Of);
vecA.HostrarValorO;

Utilizar el operador new no significa que la variable vecA sea un objeto ni que la me
moria sea tomada del

en el stack, siempre.

heap. Nuevamente destacamos: las estructuras son asignadas

Por lo tanto, cuando hacemos uso de un tipo de dato de una librera, es importan
te saber si dicho tipo es una clase o una estructura, porque, en caso contrario, po
dremos cometer errores.

RESUMEN

La clase es el tipo de dato fundamental en el cual se basa el lenguaje. Realmente todo en C#


es un objeto. Gracias a este recurso, crear sistemas ser mucho ms sencillo, y a medida que
comencemos a sumar herramientas y conocimientos nuevos, veremos cmo programas que
en principio pareceran complejos de realizar son muy simples y fciles de entender. Como ya
hemos mencionado, C# es uno de los lenguajes ms productivos y eficientes del mercado, y
gran parte de esta fama se debe a su apego a la programacin orientada a objetos. En el
capitulo siguiente estudiaremos los conceptos fundamentales de este paradigma y el papel
que juega la estructura de datos clase en ellos.

u s r .c o d e

111

ACTIVIDADES

TEST DE AUTOEVALUACIN

1 Dnde

se encuentra el error en los si

guientes listados?

m_iValor = iValor;
r e tum true;

a)

}
}

class Foo

{
const int a;
int b;
int c;

2 Es

necesario instanciar una clase para

acceder:
una variable de tipo entero no esttica?

una variable de tipo entero esttica?


un mtodo esttico?
b)

3 Cules son las diferencias principales en

class Foo

tre clases y estructuras?

{
public int miValor;
// Imprime la variable m_ iValor
static void ImprimirValor()

{
Consol.Write(m_iValor);

U Es posible especificar inicializadores en


estructuras?

5 Pueden las estructuras poseer construc


tores? En qu forma?

}
6 Es posible destruir un objeto de manera
explcita?

c)
class Foc

i
prvate int miValor;
bool FijarValor(int iValcr!

if (iValor >= 0 && iValor < 10)

112

.c o d e

Captulo

PROGRAMACION C#

Encapsulamiento.
herencia
y polimorfismo
Aqu veremos los conceptos
fundam entales de la programacin
orientada a objetos y de qu modo

C -tt

cum ple con ellos. Introducirem os


conceptos prim ordiales, como herencia
y composicin. Adem s, aprenderem os
Herencia

qu es el polim orfism o y qu
caractersticas de ste ofrece C#,
como los metoo s virtuales, las interfaces
V IriS t I d S t r : dt.'S tr

actas.

serv ic io de atencion al lecto r :

le c t o r e s @ m p e c lic io n e s .c o ii]

114
Uso de los modificadores
de acceso
122
Las propiedades
123
Invocar constructores
128
Invocar destructores
132
Composicin
133
Composicin Irente a herencia 135
13/
Polimorfismo
37
Sobrecarga de mtodos
Sobrecarga de operadores
Ki
Mtodos virtuales
145
Interfaces
153
154
Clases abstractas
Resumen
155
Actividades
156

PROGRAMACIN CU

HERENCIA
La herencia es un concepto fundamental de la programacin orientada a objetos.
Por medio de esta caracterstica podremos definir nuestras clases a partir de otras,
ms generales, y slo agregar las propiedades y mtodos de la especializacin.
Debido a que nuestro sistema ser una coleccin de clases relacionadas entre s, es
muy importante el modo en que estar conformada su estructura. Un diseo po
bre, por lo general, genera ms problemas que soluciones, ya que los errores se pro
pagan rpidamente, y su expansin y mantenimiento se dificultan.
C#, como un buen lenguaje del paradigma de programacin orientada a objetos,
soporta herencia. Veamos cmo podramos definir dos clases, una derivada de la
otra, con un ejemplo minimalista:

class A

{
}
class B : A

; } -

Hemos declarado la clase A como una clase convencional (as como lo venamos ha
ciendo). La clase B posee, seguido de su identificador, el carcter dos puntos (:) y,
luego, el identificador de la clase de la cual deriva. Qu significa esto? La clase B
heredar los mtodos y las variables pblicas, protegidas e internas de A.
Y de qu modo podra beneficiarnos esta caracterstica? Bueno, si el diseo de
nuestro programa es correcto, entonces escribiremos una cantidad de cdigo me
nor, adems de mejorar la reusabilidad de nuestros componentes y facilitar el man
tenimiento de todo el sistema.

H H TERMINOLOGA DE LA HERENCIA
Si la clase B hereda de la clase A, entonces B es una clase hija o derivada de A, mientras que A
es la clase padre de B. Tambin se suelen emplear los trminos subclase (B es una subclase de
A) y superclase (A es una superclase de B).

114

u s r.c o d e

Herencia

Analicemos un pequeo ejemplo. Supongamos que en nuestro sistema deberemos


representar un automvil y una pala mecnica. Ambas entidades comparten mu
chas caractersticas, pero tambin son diferentes. Un diseo pobre que no utilice he
rencia implementar ambas entidades en clases totalmente independientes, veamos:

Declaracin de la clase Automvil:


clas8 Automvil

{
// --------------// Variables
protected int caballoaDeFuerza;
protected int cantidadPuertas;

// -------------------------// Mtodos
public void Arrancar()

{
System.Consol.WriteLine('Clase Automvil, Mtodo Arrancar");
public void Detener()
System.Consol.WriteLine("Clase Automvil, Mtodo Detener*);
public void AbrirFuerta(int puertaHum)
System.Consol.WriteLine("Clase Automvil, Mtodo AbrirPuerta");
public void CerrarPuerta(int puertaNum)
System.Consol.WriteLine("Clase Automvil, Mtodo CerrarPuerta");

Declaracin de la clase PalaMecanica:


class PalaMecanica

I -------------------------// Variables

uii.c o d e

11

PROGRAMACIN C#

protected int caballosDeFuerza;


protected int pesoMaximoDeLevante;

// -------------// Mtodos
public void Arrancar(]

{
System.Consol,WriteLine{
Clase PalaMecanica, Mtodo Arrancar");

}
public void Detener!)

{
System.Consol.WriteLine("Clase PalaMecanica, Mtodo Detener*);

}
public void LevantarPalaO

{
System.Consol.WriteLine("Clase PalaMecanica,
Mtodo LevantarPala*) ;

}
public void BajarPalaO

{
System.Consol.WriteLine("Clase PalaMecanica, Mtodo BajarPala");

}
}

Como puede verse en los listados anteriores, algunos mtodos y variables son co
munes a ambas clases; pero como no utilizamos herencia, tuvimos que rescribirlos.
En la Figura 1 se puede observar un esquema de las clases descritas, que no poseen
relacin alguna entre s. El diagrama de clases es uno de los diagramas UM L, del
cual se puede apreciar una introduccin en el Apndice D.

Automvil

PalaMecanica

#cabaliosDeFuerza: int
tfcantidadPuertas: ini

#caballosDeFuerza: int
#pesoMaximoDeLevante: int

+Arrancar{): void
+0etener(): void
+AbrirPuerta(): void
+CerrarPuerta(): void

+Arrancar(): void
+Detener(): void
+LevantarPala(): void
+BajarPala ( ) : void

Figura 1. Declaracin de clases sin realizar uso de herencia.

116

u s r .c o d e

Herencia

Si, en cambio, creramos una clase llamada Vehculo que ruvicsc las variables y los
mtodos comunes a ambas clases, luego Automvil y PalaMecanica slo deberan
agregar los mtodos especficos del tipo de vehculo que representan. Entonces, la
cantidad de cdigo escrito sera sensiblemente menor. Tambin, en el caso de exis
tir un error en el mtodo Arrancar, slo deberamos modificar el cdigo de una cla
se y no de dos. En definitiva, estaramos ante un diseo mis elegante. Veamos:

Listado de la clase Vehculo:


class Vehculo

/ / -------------------------// Variables

protected int caballosDeFuerza;

// c

:-----------------

// Mtodos

public void Arrancar()

{
System.Consola.WriteLine{"Clase Vehculo, Mtodo Arrancar");

public void Detener{)

>

'

{
System.Consol.WriteLine1"Clase Vehculo, Mtodo Detener");

}
}

Listado de la clase Automvil:


class Automvil : Vehculo

// -------------------------// Variables

protected int cantidadPuertas;

// --------------// Mtodos

public void AbrirPuerta(int puertaNum)

{
System.Consol.WriteLine!"Clase Automvil, Mtodo AbrirPuerta");

u s r .c o d e

117

PROGRAMACIN CE

public void CerrarPuerta(int puertaflum)

{
System.Consol.WriteLine("Clase Automvil, Mtodo CerrarPuerta*);

}
}

Listado de la clase PalaMecanica:


class PalaMecanica : Vehculo

{
.// --------------// Variables

protected int pesoMaximoDeLevante;

// -------------------------// Mtodos

public void LevantarPalaO

{
System.Consol.WriteLine("Clase PalaMecanica,
Mtodo LevantarPala") ;
"

.} '

-jjV '

' Vv-'l

>'

public void BajarPalaf)

{
System.Consol.WriteLine("Clase PalaMecanica, Mtodo BajarPala");

}
}

Como se puede apreciar en los listados anteriores, ahora las clases Automvil y Pala
por lo tanto todas las variables, mtodos y pro

Mecanica son subclases de Vehculo,

piedades que no sean privadas sern heredadas, y entonces podrn ser accedidas des
de objetos de Automvil o PalaMecanica como si hubiesen sido declaradas all mismo.

IJ H LA CLASE OBJECT
D e c ir que n u e s tra s c la s e s no h ac en uso de h e re n c ia no es d el todo p re ciso . Todo c la s e s e r una

Object ia u n q u e no lo in d iq u e m o s e x p lcita m e n te ). Toda c la s e de la lib re ra


BCLe s s u b c la s e d e Object, q u e se h alia en e l e sp a cio de n o m b res System. S ie m p r e n u e stro s ob
je to s pod rn s e r c o n s id e ra d o s d el tipo O
bject, y e s una ven taja que ya v e re m o s c m o explotar.
s u b c la s e de la c la s e

I1 t

is r .c o d e

Herencia

En la Figura 2 se ilustra la relacin existente entre las clases:

Figura 2. Declaracin de clases haciendo uso de herencia.

Ntese que existe una flecha grande desde las clases Automvil y PalaMecanica hacia
esta relacin expresa generalizacin y es uno de los smbolos caractersti

Vehculo;

cos de este tipo de diagramas.


El uso de las clases descritas no es nada nuevo; el acceso a variables o mtodos pro
pios o heredados es exactamente igual, y quien utiliza la clase en cuestin no podr,
a priori, determinar dnde fue declarado dicho elemento. Por ejemplo:
'T*C
- :

Automvil unAuto = new Automvil 0;


unAuto.Arranear();

En la primera lnea de cdigo instanciamos un objeto del tipo Automvil y en la se


gunda invocamos uno de sus mtodos (Arrancar), que realmente no fue declarado en
la clase Automvil, sino en la clase Vehculo; pero como Automvil es una subclase de
Vehculo y el mtodo Arrancar es pblico, entonces fue heredado, y es totalmente v-

DE NUEVO NEW?
-

iXV

,.. *;...

Ya usamos el operador new para solicitar memoria al sistema. Adems posee otro uso. Al defi
nir un mtodo (no virtual) en una subclase de una clase que contiene el mismo mtodo, debere
mos indicar que deseamos crear una versin nueva de l. No hacerlo no producir un error, si
no una advertencia. Esta regla evita que se sobrescriba un mtodo de una clase padre por error.

(
u s r .c o d e

119

PROGRAMACIN C

ti

lido invocarlo desde cualquier objeto del tipo Automvil como si hubiese estado de
clarado en l. Lo mismo ocurre con objetos del tipo PalaMecanica:
PalaMecanica unaPala = na* PalaMecanlcaO}
unaPala.Arrancar();

Ciertamente, un automvil y una pala mecnica poseen un motor que debe ser en
cendido. La representacin de estas entidades en nuestro sistema podra llevar a que
las implementaciones de los mtodos Arrancar y Detener fueran las mismas, pero tal
vez podra existir el caso en que algunas de ellas o todas deberan ejecutar distintos
trozos de cdigo. En estos casos es perfectamente vlido rescribir los mtodos en las
clases derivadas. Veamos.
La clase Vehculo posee un mtodo llamado Arrancar, que probablemente conten
ga el cdigo necesario para el encendido de cualquier vehculo genrico. La invo
cacin de dicho mtodo (por medio de objetos de subclases) provocara su ejecu
cin. Sin embargo, si definiramos un mtodo Arrancar en la clase Automvil (de
jando intacta la clase Vehculo), entonces existiran dos mtodos Arrancar. Cul
de ellos sera el mtodo invocado? Desde un objeto del tipo Automvil se invoca
ra el mtodo de la clase Automvil, y desde un objeto del tipo Vehculo se invo
cara el mtodo de la clase Vehculo.
clase Vehculo

{
public

void

Arrancar {)

{
SyBtem.Console.WriteLine("Clase Vehculo, Mtodo Arrancar17);

}
}
clasa Automvil : Vehculo

{
public new void Arrancar()

{
System.Console.WriteLine ("Clase Automvil, Mtodo Arrancar'7);

}
}

Automvil unAuto = new Automvil ();


unAuto.Arrancar(); // Se invoca mtodo de clase Automvil

120

usr.code

Herencia

Vehculo unVehiculo = new Vehculo();


unVehiculo.Arrancar{);

// Se invoca mtodo de clase Vehculo

Esta prctica de redefinir mtodos en subclases es muy comn. Aunque realmente


se suele invocar desde la versin del mtodo Arrancar de Automvil al mtodo Arran

car de la clase Vehculo, ya que las tareas realizadas en dicha clase de otro modo que
daran ocultas y no seran ejecutadas (adems de que es lgico que parte del proce
so de encendido de un automvil sea comn al de cualquier vehculo). Para esto de
beramos agregar la siguiente lnea de cdigo:
claas Automvil : Vehculo

{
public new void Arrancar{)

{
base.Arrancar!)

System.Consol.WriteLine("Clase Automvil, Mtodo Arrancar");

La lnea nueva es:


base.Arrancar();

Base

es una palabra reservada que se utiliza cuando se desea indicar al compilador

que deseamos acceder a mtodos, variables o propiedades de la clase padre de aque


lla en la que nos encontramos.
De esta manera, cuando se ejecute dicha lnea de cdigo, la versin del mtodo

Arrancar de la clase Vehculo ser ejecutada.

CUIDADO CON LA RECURSIN INFINITA

En el caso de que no hubiramos utilizado


te

Arrancar,

base, y en lugar de ello hubiramos escrito solamen

entonces se habra producido un bucle infinito de ejecucin del mismo mtodo

ya que en realidad la ejecucin se detendr en el mismo instante en que se desbor


y se produzca un error en tiempo de ejecucin).

(idealmente,
de la pila

u s r .c o d e

121

PROGRAMACIN C#

clase Automvil : Vehculo

{
public void Arramcarf)

{
// ;Se invocar el mismo mtodo una y otra vez hasta
producir un error!
Arrancar () ;
System.Consol.WriteLinef
Clase Automvil, Mtodo Arrancar");

}
}

Uso de los modificadores de acceso


Las variables, por ser protegidas, no podrn ser accedidas desde fuera de la clase de
rivada. Es decir que la siguiente lnea de cdigo provocara un error de compilacin:
Automvil unAuto = new Automvil();
unAuto,cantidadPuertas =10;

As como la lnea:
Automvil unAuto = new Automvil();
unAuto,caballosDeFuerza

420;

El error en cuestin dir que cantidadPuertas o caballosDeFuerza es inaccesible de


bido a su nivel de proteccin. Esto nada tiene que ver con la herencia, sino con los
modificadores de acceso empleados en la declaracin de las variables de las clases;
las dos lneas de cdigo anteriormente escritas no habran causado ningn error si
hubieran sido declaradas como pblicas.

[ I QU ES UN ASSEMBLY?
Un sistema siempre debe estar compuesto por uno o ms assemblies. Un assembly puede ser
un archivo ejecutable o una librera de enlace dinmico, que puede poseer cdigo ejecutable y/o
recursos (como bitmaps, iconos o cualquier tipo de dato). Cada assembly posee un manifest que
describe su contenido e informa de otras propiedades como su nombre, versin, etc.

122

u s r .c o d e

Herencia

La variable caballosDeFuerza podr ser accedida desde cualquier mtodo de la clase


Vehculo independientemente de su modificador de acceso, por haber sido declara
da dentro de esta clase. Tambin podr ser accedida desde los mtodos de la clase

Automvil y PalaMecanica

debido a que fue declarada como protegida (esto no ha

bra sido as si hubiese sido declarada como privada). El cuadro que se encuentra a
continuacin aclara un poco esta situacin:

prvate

no

no

no

no

protected

no

no

public_ _ _ _ _ _ _ _ _ _ _ _ _ s_ _ _ _ _ _ _ _ _ _ _ _ s_ _ _ _ _ _ _ _ _ _ _ _ s_ _ _ _ _ _ _ _ _ _ _ s_ _ _ _ _ _ _ _ _ _ _ _ si
Tabla 1. Modificadores de acceso.

Analizando en detalle la tabla anterior, podemos inferir cundo es conveniente uti


lizar cada modificador de acceso y por qu no podemos acceder externamente a las
variables declaradas.
Declarar variables de clases como pblicas no es una prctica aconsejable cuando:
no todo el rango del ripo de dato de la variable debera ser aceptado;
se deba disparar algn evento antes de la asignacin o despus de ella;
la variable debe ser leda pero no escrita, o viceversa.
Por esta razn, en estas ocasiones se debern utilizar propiedades que, a vista del
consumidor , son iguales y poseen diversos beneficios que procedemos a analizar.

Las propiedades
En lenguajes como el C++, si deseamos permitir que se modifique una propiedad
de modo externo a la clase, poseemos dos alternativas:
Declarar la variable como pblica. Entonces, desde cualquier parte del progra
ma se podr leer y escribir dicha variable sin inconvenientes. El problema de esta
solucin es que no podremos especificar una variable como de slo lectura o slo
escritura; si sta es pblica, siempre podr ser leda y escrita sin excepcin. Por
otro lado, no podremos reaccionar ante la lectura o escritura de alguna variable
en particular, ya sea para modificar otros valores en cascada, comprobar rangos o
validez de la informacin especificada, etc.
u s r .c o d e

123

PROGRAMACIN C#

Declarar un mtodo de acceso a la variable. Esta solucin es la ms empleada en


lenguajes como C++. Por lo general se especifica un mtodo que posee como identificador la concatenacin de la palabra Fijar (o, en ingls, Set) con el identificador

de la variable. En el caso de la lectura, de la variable Leer (o, en ingls,

Get).

Por ejemplo, si deseamos fijar el valor de la variable cantidad, entonces creamos un


mtodo llamado FijarCantidad, y si deseamos leerla, creamos un mtodo llamado

LeerCantidad (claro que esto de anteponer Fijar y Leer es simplemente una conven
cin arbitraria). Veamos:
clase Foo

{
protected int cantidad;
public void FijarCantidad(int valor)

{
cantidad = valor;

}
public int LeerCantidad()

{
return cantidad;

}
}

Luego, si es necesario, en la definicin de los mtodos de lectura y escritura de la


variable podremos agregar revisiones de rangos y otras acciones relacionadas que
puedan dispararse a partir de la lectura o la escritura de la variable en cuestin.
El nico problema que posee esta solucin es un empobrecimiento en la legibilidad
de nuestro cdigo, ya que es ms bonito especificar:
objeto.variable = valor;

que
objeto.mtodo(valor);

Sobre todo, cuando debemos acceder a variables de objetos que se encuentran den
tro de otros objetos, con lo que en el primer caso quedar:
124

u s r .c o d e

Herencia

objeto.objeto.objeto.variable = valor;

y en el segundo caso:
objeto.mtodoO.mtodoO.mtodo(valer);

Las propiedades, ausentes en C++, pero presentes en lenguajes de programacin


ms modernos como C#, nos brindan la posibilidad de tomar lo mejor de los dos
mundos: la posibilidad de disparar cdigo relacionado con la lectura o escritura de
una variable sin perder el estilo de codificacin.
class Foo

{
protected int cantidad;
public int Cantidad

1
get
r e t u m cantidad;

}
set

{
cantidad = valu;

1
}
}

Analicemos el cdigo anterior. Por un lado nos encontramos con la declaracin de


la variable (como protegida, en este caso, para que pueda ser accedida desde subcla
ses, pero 110 externamente). Por el otro, existe la declaracin de una propiedad que
posee un modificador de acceso y un tipo de dato como si fuese una variable o un
mtodo convencional, pero inmediatamente despus de su identificador posee un
bloque declarativo dentro del cual existe un get (leer) y un set (Jijar), que, a su vez,
poseen bloques donde colocaremos cdigo.
El hecho de que el identificador utilizado sea similar a la variable a la cual accede
(slo cambia que la primera letra est en mayscula) es una convencin arbitraria
nuestra; podramos haber especificado un identificador totalmente diferente.
u s r .c o d e

125

PROGRAMACIN C

tipo de dato
modificador
de acceso

public

identificador

int

Cantidad

{
get
<

Mtodo de
acceso get

!
I
v-V-
.- |
;

set
Mtodo de
acceso set

{
}
>

Figura 3. Ejemplo de declaracin de una propiedad.

Ya podemos intuir que el cdigo que colocaremos dentro del

get ser el que antes

especificamos dentro del LeerCantidad. As como el cdigo que colocaremos dentro


del

set

ser el que antes especificamos dentro del

FijarCantidad

(en este ltimo ca

so, debido a que no existe declaracin de parmetro alguno, deberemos utilizar la


palabra reservada valu, que oficiar de parmetro de entrada).
Entonces, si deseamos invocar el mtodo get, podremos escribir:
int valor = unObjetoFoo.Cantidad;

AL MENOS UNO A LA VEZ

Cabe destacar que podremos especificar el get y el set o slo uno de ellos (si es que deseamos
que nuestra variable sea de slo lectura o de slo escritura), pero al menos uno debe estar de
clarado, o se producir un error de compilacin.

126

u s r .c o d e

Herencia

Y si deseamos invocar el mtodo set


unObjetoFoo.Cantidad = 10;

Es decir, mantenemos la simpleza de lectura y escritura de variables, pero con el poder


que nos otorga la ejecucin de cdigo arbitrario dentro de estos mtodos especiales.
El siguiente diagrama expone cmo debe declararse una propiedad. Cabe destacar
que sta podra poseer ms modificadores (como static si la variable fuese esttica),
que ms adelante analizaremos.

Figura 4. Declaracin de una propiedad.

u s r .c o d e

127

PROGRAMACIN Ctt

INVOCAR CONSTRUCTORES
Sabemos que cuando construimos un nuevo objeto se ejecuta el cdigo del mtodo
constructor. Dicho constructor puede existir de manera explcita (cuando lo defini
mos) o de manera implcita (cuando no lo definimos).
Pero qu es lo que sucede cuando nuestra clase est definida a partir de otra? Qu
constructor se invoca? Para responder estas preguntas, pasemos a analizar con
detenimiento el siguiente ejemplo:
Poseemos tres clases:

A, B y C, cada una de ellas definida a partir de la otra, segn

detalla el siguiente diagrama:

Figura 5. Nuestro diagrama de clases.

Si creamos una instancia de la clase C, entonces, en primer trmino se pasar a eje


cutar el constructor de la clase padre (que, en realidad, siempre tendra que ser

Object). Luego se ejecutar el constructor de la clase A, despus el constructor de


la clase B y, finalmente, el constructor de la clase C.
Esto podremos verificarlo con el siguiente ejemplo:
class k

128

A()

u s r.c o d e

Invocar constructores

{
Consol.WriteLine("Constructor A");

}
}
class B : A

{
B()

{
Consola.WriteLine("Constructor B*);

}
}
class C : B

{
C()

{
Consol.WriteLine("Constructor C");

}
static void Main(string[} args)

C obj e new C();

}
}

La salida en pantalla ser:


Constructor A
Constructor B
Constructor C

Esto que observamos es lgico, debido a que el objeto C, en el momento de ser cons
truido, debera tener la posibilidad de contar con todas las variables y propiedades
de sus superclases debidamente inicializadas (esto, en un gran nmero de ocasiones,
podra significar abrir archivos o canales hacia otros dispositivos de hardware), y as
realizar su propia inicializacin.
Y que ocurrira si deseramos invocar un constructor con parmetro en alguna cla
se padre? Veamos el siguiente ejemplo:

u s r .c o d e

129

PROGRAMACIN CS

Clasa B : A

{
B()

{
Consola.Writeiinot
Coiistruetor B"!;

}
B(int num)

{
Console.WriteLine("Constructor B con parmetro
entero; 0}*, num);

}
}

Ahora nuestra clase B cuenca con dos constructores; lino de ellos recibe un parme
tro que es una variable del tipo entero.
"Pero en el caso de que volvamos a ejecutar nuestro programa, el constructor de la
clase C seguir ejecutando el constructor sin parmetros de B. Cmo hacemos pa
ra cambiar este comportamiento?
claas C : B

{
CO

: baseII)

{
Consol.SritaLinePConatructor C!;

}
// ...
}

Haciendo uso de la palabra reservada base! Tengamos especial atencin en que he


mos colocado un carcter dos puntos () tras cerrar los parntesis en la declaracin
del constructor de la clase C, luego escribimos base (que hace referencia a la clase
padre inmediata desde la cual estamos), y entre parntesis especificamos los par
metros que hagan falta.
Este parmetro, en el ejemplo anterior, fue un nmero arbitrario, pero tambin po
dra ser una variable recibida por parmetro en un constructor de la clase C (Figura 6).

130

u s r .c o d e

invocar constructores

Tambin cambiamos el modo de construir un objeto del tipo C, para que se invo
que el constructor con parmetro entero y no el constructor sin parmetros.
u s r .c o d e

131

PROGRAMACIN C#

INVOCAR DESTRUCTORES
En el momento en que un objeto es destruido, los destructores tambin son invoca
dos en un orden preestablecido, que, como es de esperar, es inverso al ordenamien
to que siguen los constructores.
class A

{
A ()

{
Con8ole.KriteLi.ne('Constructor A*);

}
-A()

{
Consol.KriteLine("Destructor A");

}
; }
class B : A

{
BO

{
Consol.WriteLine("Constructor B");

}
-BO

{
Consol.WriteLine("Destructor B*);

}
}
class C : B

1 3

DESTRUCCION DE OBJETOS

Recordemos que la destruccin real de un objeto es realizada por el framework, y deberamos


dejar esta tarea en sus manos y no presuponer cundo un objeto es destruido.

132

u s r .c o d e

Com posicin

C()
{
Consol.WriteLine('Constructor C*)j

-C{)

{
Consola.WriteLine("Destructor C");

}
static void Main (string [} args)
{
C obj a new C();
}

Si ejecutamos el ejemplo anterior, veremos en pantalla:


Constructor A
Constructor B
Constructor C
Destructor C
Destructor B
Destructor A

Antes de ser destruido por el framework, el objeto C invoca su mtodo destructor y


le permite a ste realizar un proceso inverso a la inicializacin (cerrar archivos, ca
nales, etc.). Luego, se invoca el destructor de la clase padre de C, y el proceso se re
pite hasta llegar a la clase raz, que siempre ser System.Object.

COMPOSICIN
Una clase puede tener como miembro cualquier tipo de variable, sin importar que
sea de algn tipo fundamental o definido por el usuario; esto tambin incluye otros
objetos definidos previamente.
Por tal motivo, en un sistema ser bastante frecuente que los objetos se encuentren
compuestos por otros objetos. Veamos un ejemplo trivial.

u s r .c o d e

133

PROGRAMACIN C#

class A

| {
public void ml{)

{
Consol.WriteLina("Clase A, mtodo Foo);

}
// . . .
}
class B

{
public A objA a new A();

//

'

...
'*

En el ejemplo mostrado anteriormente, todo objeto de la clase B se encontrar con


formado por un objeto de la clase A.
Veamos cmo representar esta nueva relacin en un diagrama de clases:

Figura 6. La relacin de composicin.

Como se puede apreciar en el diagrama, la relacin de composicin se marca por


medio de una lnea terminada en diamante lleno.
A travs de la utilizacin de un objeto de la clase B, podremos tener acceso al obje
to A por medio de la variable objA (que hicimos pblica) y, de esta manera, acceder
luego poder a sus variables, propiedades y mtodos pblicos.
B unObjB = new B();
// Invoco el mtodo mi por nedio del objeto objA del tipo A
unObjB. obj A. mi ();

De este modo, si el objeto del tipo A contuviera, a su vez, otros objetos, podramos
acceder a ellos simplemente anteponiendo el operador de seleccin de miembros,
siempre y cuando stos fueran pblicos.
1 34

u s r .c o d e

Com posicin frente a herencia

COMPOSICIN FRENTE A HERENCIA


La composicin y la herencia tienen bastante en comn, y en muchas ocasiones re
sulta difcil discernir cul de ellas utilizar en un caso determinado. Veamos cules
son sus similitudes. Si tenemos la siguiente clase:
claes A

{
public int vari;
public int var2;
public int var3;

en memoria, al crear un objeto del tipo A tendremos lo siguiente:


objA

vari
var2
var3

Ahora, si creamos una clase B, subclase de A, y agregamos un par de variables, ten


dremos lo siguiente:
class B ; A

{
public int var;
public int var5;

Cuando instanciemos un objeto del tipo B, el mapa de memoria para ste ser:
objB

vari
var2
var3
var4
var5

Es decir que el objeto del tipo

B poseer las variables de todas las clases superiores

(en este caso, slo una, sin contar la clase Object, que, de todos modos, no posee va
riables) ms las definidas por l.
u s r .c o d e

135

PROGRAMACIN C*

Por lo tanto, un objeto del tipo B podr acceder a elementos de B y a elementos (he
redados) de A. Podramos haber obtenido un resultado similar utilizando composi
cin. Veamos:
La clase A permanecera sin cambio alguno. Sin embargo, la clase B ya no sera una
subclase de A, sino que poseer otra variable ms, que sera un objeto del tipo A:
class B
{
public A objA = new A();
public int var4;
public int var5;
}

objB

objA

vari
var2
var3

var4
var5
El mapa de memoria es muy similar; el objeto, en definitiva, ocupar el mismo es
pacio en memoria. Cul es la diferencia, entonces?
Usualmente elegimos utilizar herencia cuando deseamos incorporar a nuestra clase las
variables, propiedades y mtodos del objeto seleccionado, o cuando deseamos especia
lizar una clase determinada agregando caractersticas de una entidad especfica que es
tamos modelando, tomando como base una clase del mismo tipo, pero ms general.
En cambio, decidimos utilizar la composicin cuando deseamos ocultar, encapsular, el objeto seleccionado bajo la nueva interfaz.
Por lo tanto, ms all de algunas similitudes tcnicas, conceptualmente la herencia
y la composicin se encuentran bien diferenciadas.

l i l i INIC1ALIZAR OBJETOS MIEMBRO


Cabe destacar que no es estrictamente necesaria la creacin del objeto objA en la misma l
nea que su declaracin linicializadorl; esta operacin podra realizarse luego. Sin embargo, es
una prctica conveniente en muchos casos, ya que evitar que por error se haga uso del obje
to objA sin antes haberlo creado.

136

u s r .c o d e

Polim orfismo

POLIMORFISMO
El polimorfismo es la habilidad que poseen los objetos para reaccionar de modo di
ferente ante los mismos mensajes. Un objeto del tipo Puerta, al igual que un obje
to del tipo Ventana, podr recibir el mensaje Abrir; sin embargo, cada uno de ellos
reaccionar de modo diferente.
En C#, el polimorfismo se encuentra ntimamente relacionado con el mecanismo
de sobrecarga y con los mtodos virtuales. Veamos.

Sobrecarga de mtodos
En lenguajes como el C, es comn encontrar libreras que poseen grupos de funcio
nes que realizan la misma tarca, pero con distintos tipos de datos en los parmetros.
De esta manera, si la tarea consiste en mostrar en pantalla el dato pasado como pa
rmetro, nos podremos encontrar con casos como el siguiente:
void Imprimirlnt(int num);
void ImprmirChar(char car);
void ImprimirFloat(float num);

El lenguaje C # provee un mecanismo mucho ms conveniente para obtener el


mismo propsito. Es posible crear mtodos de clases que posean el mismo nom
bre y difieran en la cantidad y/o en el tipo de parmetros. Esto no es algo real
mente novedoso para nosotros, pues ya hemos observado el mecanismo en accin
definiendo mltiples constructores.
De este modo, el ejemplo anterior podra ser rescrito como:
clasa Con
static void Imprimir(int num);
static void Imprimir(char car);
static void Imprimir(float num);

Lo cual es mucho ms sensato. De esta forma, el programador no tendr que recor


dar el sufijo que conforma el identificador de la funcin apropiada. Todas las fun
ciones se llaman de la misma manera. A esta caracterstica del lenguaje se la ha de
nominado sobrecarga de mtodos.
u s r .c o d e

137

PROGRAMACIN C#

Cuando el programador utilice alguna de estas funciones, el compilador selecciona


r el mtodo adecuado en funcin de los tipos de datos y la cantidad de parmetros
que utilicemos, invocando la versin del mtodo que corresponda.

Tipo de dato devuelto por el mtodo


No es posible crear dos funciones con el mismo identificador que slo difieran en
el tipo de dato devuelto, debido a que el compilador no podr distinguir cundo se
desea llamar a una o a otra:
class Foo

{
// Error: Los mtodos slo difieren en el tipo
// de datos retomado.static Lool Fooiint num);
static bool Foo (Int num);
static cbar Foo(int num);

Veamos un ejemplo un poco ms interesante. Crearemos una clase que manipule un


vector de dos dimensiones, completando la clase que habamos empezado a construir en
el Captulo 3. Empezaremos donde antes habamos terminado. Una clase con dos varia
bles de tipo float privadas que representan los dos componentes de nuestro vector.
Ahora, la definicin de dos constructores: uno sin parmetros y otro con parmetros,
para poder fijar el valor del vector al momento de construirlo, lo cual es muy cmodo.
clasB Vector2

{
public float X o O.Of;
public float Y = O.Of;
Vector2()

{
}
Vector2(float

_x,

float _y)

{
X = _x;
Y = _y;

}
}

138

u s r .c o d e

Polimorfismo

Debido a que todo el rango de florantes es aceptado por nuestro vector para sus
componentes y a que no debemos disparar ninguna accin relacionada con la lec
tura o escritura de stos, entonces las variables miembro las especificaremos con
modificador de acceso public.
Agregaremos ahora algunos mtodos tiles para la manipulacin de vectores:
public double ProductoPunto(Vector2 vec2)

{
return X*vec2.X + Y*vec2.Y;

}
public double ProductoPunto(float _x, float

y)

{
return X*_x + Y*_y;

El mtodo ProductoPunto devuelve el producto punto del vector almacenado en el


objeto y el pasado como parmetro.
El mtodo se encuentra sobrecargado y permite pasar el vector con el cual realizar
el producto punto como un objeto del tipo Vector2 o mediante los elementos de s
te en tipo de dato float.
De la misma manera, podramos definir un mtodo que nos permitiera sumar y res
tar dos vectores. Veamos:
public void Sumar(Vector2 vec2)

{
X = X + vec2.X;
Y = Y + vec2.Y;

}
public void Sumar(float

x, float _y)

Q Q PARMETROS OPCIONALES
C# no soporta la declaracin de parmetros opcionales, asi como lo hacen C++ o Visual Basic
Para conseguir el mismo objetivo, habr que crear dos mtodos distintos sobrecargados con di
ferencia en cantidad de parmetros.

u s r .c o d e

139

PROGRAMACIN C#

X * X + Jt;
Y => Y y;

}
static public Vector2 Sumar(Vector2 vacl, Vector2 vec2)

{
return new Vector2(vecl.X + vec2.X, vecl.Y + vec2.Y)j

:>

La primera versin dei mtodo suma un vector pasado como parmetro al vector
del objeto y almacena el resultado sobre s mismo. La segunda versin hace lo mis
mo, pero recibe los parmetros como elementos.
En ltimo lugar, la tercera versin del mtodo es esttica y no requiere la existencia
de un objeto, simplemente suma dos vectores y devuelve el resultado de la opera
cin como valor de la funcin.

Mtodos estticos y no estticos en la sobrecarga


No es posible que dos mtodos sobrecargados slo difieran en el modificador
static. Por ejemplo:
public void Foo (int num)

' '
// ...

'

}
otatic public void Foo (int num)

{
//

...

El compilador tomar el cdigo anterior como un error.

[ J | ORDEN DE LOS PARMETROS


Los mtodos sobrecargados tampoco podrn diferenciarse exclusivamente en el orden de los pa
rmetros (si es que stos son del mismo tipo), ya que el compilador no podr diferenciar en qu
caso invocar qu mtodo.

140

u s r .c o d e

Polim orfismo

Sobrecarga de operadores
Sera mucho ms prctico poder hacer la suma de dos vectores utilizando el opera
dor de suma (+), en particular la ltima versin del mtodo Sumar. De otro modo,
as como estamos ahora, deberamos escribir:
vec3 = Vector2.Sumar(vecl, vec2);

Cuando sera ms elegante poder escribir:


vec3 = vecl + vec2j

Pero cmo podra saber el lenguaje cmo debe manipular dos vectores de dos di
mensiones en una suma? O, eventualmente, cmo podra saber cmo sumar dos
objetos definidos arbitrariamente por nosotros? C# permite sobrecargar operado
res, es decir, redefinir el significado de un conjunto de operadores cuando se uti
lizan con ciertos objetos.
Esta sobrecarga devendr en uu mtodo convencional pero declarado de un modo
especial, por lo que termina siendo, al fin y al cabo, una modificacin a la esttica
de nuestro cdigo.
Veamos cmo sobrecargar el operador +:
static public Vector2 operator+ (Vector2 vecl, Vector2 vec2)

{
return new Vector2(vecl.X + vec2.X, vecl.Y + vec2.Y);

Como se puede apreciar en el listado anterior, la declaracin del operador es muy


similar a la de un mtodo convencional, slo que el identificador de ste se encuen
tra formado por la palabra operator y el operador que se desea sobrecargar.

( 3 OPERADORES SOBRECARGABLES
No todos los operadores pueden ser sobrecargados! En este mismo captulo podremos encon
trar una lista de los operadores que podremos sobrecargar en el lenguaje C#.

u s r .c o d e

141

PROGRAMACIN C#

El mrodo que define la sobrecarga de un operador debe ser pblico y esttico.

Ahora, el siguienre cdigo es vlido:


Vector2 vec3 = vecl + vec2;

Sin embargo, de rodos los operadores con los que cuenta C#, no todos son sobre
cargares. En la siguiente tabla podemos apreciar qu operadores pueden ser sobre
cargados y el tipo al cual pertenecen:

1 42

u s r .c o d e

Polimorfismo

OPERADORES

DESCRIPCIN

Indica valor positivo

I TIPODEOPERADOR
Unarios

Negacin aritmtica

Binarios

Negacin lgica

Negacin bitwise

&

Y bitwise

I
++

0 bitwise
Incremento

Decremento

true

Verdadero

false

Falso

Suma
Resta

ii*.
,y;.-

-*

* TV le '':* > r

Mtfltipbcatin

Divisin

telo

&

Y bitwise

0 bitwise

0 exciusarobitvrise

Desplazamiento 3izquierda

Igualdad

Desplazamientoa derecha

g ->

Relacinales

1-

Desigualdad

<

Menor

>

Mayor

Menor o igual

>

Mayor o Igual

Tabla 2. Tabla de operadores sobrecargares.

Sobrecarga de operadores unarios


Veamos el siguiente ejemplo:
class Vector2

static public Vector2 operator- (Vector2 vecl, Vector2 vec2)

<

return new Vector2(vecl.X - vec2.X, vecl.Y - vec2.Y);

'

}
}

u s r .c o d e

1 43

PROGRAMACIN C#

Sobrecarga de operadores bnanos


En el siguiente ejemplo sobrecargaremos los operadores true y false (si se sobrecar
ga uno de ellos, en compilador nos obliga a sobrecargar los dos). Este operador se
invoca cuando se evala una expresin con el objeto en cuestin:
cla88 Vectr2

n ...
tatic public bool operator true(Vector2 vec)
return {vec.X 1= 0 && vec.Y 1= 0);
static public bool operator false(Vector2 vac)
return I(vec.X l 0 && vec.Y 1= 0);

Sobrecarga de operadores relacinales


En el siguiente ejemplo, especificaremos cundo dos vectores deben ser considera
dos iguales y cundo, distintos (al igual que con los operadores true y false, aqu
tambin el operador == y el != deben ser sobrecargados en pares).
clasa Vector2

{
// ...
static public bool operator == (Vector2 vecl, Vector2 vec2)
return (vecl.X == vec2.X && vecl.Y == vec2.Y);
static public bool operator I* (Vector2 vecl, Vector2 vec2)
return (vecl.X != vec2.X || vecl.Y != vec2.Y);

Los siguientes operadores no son sobrecargables:

144

u s r .c o d e

Polim orfismo

TIPO DE OPERADOR

OPERADORES

Primario

Cast
Seleccin

new

Asignacin de memoria

typeof

Tipo

sizeof

Tamao

checked

Verificado

unchecked

No verificado
ComparacnY

Condicional

Asignacin

II

Comparacin0

?;

Condicml

Asignacin

+*

Suma y asignacin

Resta y asignacin

Divisin y asignacin

*-

Y bitwise y asignacin

A.

0 exclusivo y asignacin

Desplazamiento a izquierda y asignacin

I ,*V *
>
u
is

Seleccin
; Indexamientode array

Resto y asignacin

ir

Raooal

Multiplicacin y asignacin

Desplazamiento a derecha y asignacin


0 bitwise
Operador de veriffcaciodetipo

Seleccin de miembro
Indexadon

Tabla 3. Tabla de operadores no sobrecargadles.

Mtodos virtuales
Una de las caractersticas ms importantes que ofrece el lenguaje en cuanto a poli
morfismo tiene que ver con los mtodos virtuales.

D U INDEXADORES
El operador [] (indexacin de array) no puede ser sobrecargado directamente. Sin embargo, C#
dispone de un recurso denominado indexadores, que nos permite realizar una tarea equivalente
que ya veremos en el Captulo 5.

usr.code

145

PROGRAMACIN C#

La motivacin principal de la creacin de este tipo de mtodos es la de poder se


parar la interfaz de una entidad con su implementacin especfica, lo que nos per
mite aumentar en gran medida la reusabilidad de nuestro cdigo y crear diseos
mucho ms elegantes. Veamos, por medio de un ejemplo, cul es el beneficio de
este tipo de mtodos.
Supongamos que estamos programando un juego de ajedrez. En dicho juego desea
mos crear distintas inteligencias que estn codificadas de modo diferente, pero que
posean la misma interfaz, ya que, al fin y al cabo, estn jugando al mismo juego.
Tendremos una clase Jugador, donde deberamos implementar una cierta lgica de
juego. Tengamos en cuenta que deseamos implementar varias estrategias. En cuan
to a mtodos, la clase poseer slo uno, que ser RealizarMovida, donde entrar en
accin la lgica para evaluar el juego y realizar una movida.
La declaracin de la clase podra ser la siguiente:
class Jugador

{
public void RealizarMovida{)

{
Consol.WriteLine("Clase: Jugador, Mtodo: RealizarMovida);

Luego tendremos la clase Juego, que poseer dos variables y un mtodo:

Jugador jugadorl: objeto que representar el primer jugador.


Jugador jugador2: objeto que representar el segundo jugador.
EmpezarPartida: mtodo que comenzar la partida. En nuestro ejemplo minimalis
ta, simplemente invocar el mtodo RealizarMovida de jugadorl y de jugador2.
Declaracin de la clase Juego:
class Juego

{
Jugador jugadorl;
Jugador jugador2;
public void EmpezarPartida(Jugador jugl, Jugador jug2)

146

u s r .c o d e

Polimorfismo

{
jugadorl = jugl;
-

jugador2 = jug2;
jugadorl.RealizarMovida();
jugador2.RealizarMovida();

}
}

Nuestro modelo de clases terminar all, debido a que simplemente queremos mos
trar una funcionalidad especfica.
No existir tablero ni fichas, sino que, por el contrario, slo mostraremos en pan
talla algunos mensajes para analizar de qu manera se comporta el compilador al ser
sometido ante distintos modelos.
Nuestro sencillo diagrama esttico de clases podra ser:

Juego

Jugador

+RegistrarJugador()
+EmpezarPartida()

+RealirarMovida()

Figura 8. Diagrama de clases.

Ahora bien, cmo haremos uso de nuestras clases? En un primer ejemplo, lo hare
mos instanciando la clase Jugador en dos ocasiones:
class Foo

-voftr

{
static void Main (string U gs)
.

*.

-vi -<

Jugador jugl * new Botl();


Jugador jug2 = new Bot2();
Juego j = new Juego ();
j.RmpezarPartidajugl, jug2);

}
}

Ejecutar nuestro programa en este momento producir en pantalla la siguiente salida:

u s r .c o d e

147

PROGRAMACIN C#

Consol.WriteLine("Clase: Jugador, Mtodo: RealizarMovida")/


Consol,WriteLine("Clase: Jugador, Mtodo: RealizarMovida");

duego

jugadorl:Jugador

jugador2Jugador

EmpezarPartida
RealizarMovida

RealizarMovida

1
----

f r

Figura 9. Diagrama de secuencias.

El diagrama de secuencias anterior nos permite ver en forma grfica cmo se deben
realizar las llamadas. Un diagrama de secuencias se encuentra compuesto por dis
tintos elementos:
Objetos: son representados por los rectngulos no llenos en el borde superior del
diagrama. Dentro de ellos se debe colocar su nombre seguido de unos dos puntos y
el nombre de la clase. En caso de querer indicar que lo especificado es para cualquier
objeto del tipo, se colocan simplemente unos dos puntos y el nombre de la clase.
Mensajes: son las lneas horizontales que cruzan el diagrama. Representan invo
caciones a funciones o mtodos, y las hay de distintos tipos (simple, sincrnica y
asincrnica).

Q Q EL MTODO TOSTRING DE LA CLASE OBJECT


Existe un mtodo virtual en la clase Object que normalmente sobrecargaremos en nuestras cla
ses. Dicho mtodo es ejecutado por el framework cuando se desea obtener una representacin
en string de un objeto determinado. Si no sobrecargamos el mtodo, el comportamiento prede
terminado ser mostrar el nombre de nuestra clase en pantalla.

146

u s r.c o d e

Polim orfismo

* Tiempo: las lneas verticales representan el tiempo. Es decir que lo que se coloque
ms arriba se producir antes que lo que se coloque ms abajo. Los rectngulos co
locados sobre estas lneas de tiempo representan un flujo de ejecucin determinado.
En el Apndice D se puede encontrar ms informacin respecto a este diagrama y
los otros diagramas del lenguaje de modelado unificado.
Sin embargo, nosotros queramos hacer distintas inteligencias; cul sera entonces
la estrategia por seguir? Podramos colocar una propiedad tipo en la clase y luego,
en funcin de su valor, dividir el flujo de ejecucin representando distintas lgicas:
if (tipo

1)

{
// lgica del jugador tipo

}
lee if (tipo

2)

{
// lgica del jugador tipo B

}
alee if (tipo <= 3)

{
// lgica del jugador tipo C

I 1
Pero esto sera demasiado tedioso! Adems, la cantidad de cdigo en la clase crece
ra mucho, y si no tenemos el cuidado suficiente podremos, intentando modificar
el comportamiento de un tipo de jugador, modificar el equivocado alterando lo que
ya funcionaba correctamente.
Entonces, usted se podr preguntar: por qu no utilizamos el mecanismo herencia?
Excelente idea! Veamos: podramos crear distintas subclases de Jugador que implementaran el comportamiento de cada tipo; podran ser Botl y Bot2.
Entonces, agregaremos a nuestro programa:
class Botl : Jugador
,

{
public void RealizarMovidaO

{
Console.WriteLine("Clase: Botl, Mtodo: RealizarMovida");

u s r .c o d e

149

PROGRAMACIN C#

}
}
class Bot2 : Jugador

{
public void RealizarMovidaO

{
Consol.WriteLine{"Clase: Bot2, Mtodo: RealizarMovida");

}
}

Ahora, nuestro diagrama quedar conformado del siguiente modo:

Juego

Jugador

+RegistrarJugador()

+RealizarMovida()

+EmpezarPartida()

JugadorBotl

JugadorBot2

+ReallzarMovida()

+RealizarMovida()

F igura 1 0 . Nuestro nuevo diagrama de clases.

Nos estamos acercando a nuestra solucin, ahora deseamos que en la partida inter
vengan los jugadores Botl y Bot2, para lo cual modificaremos el mtodo Main:
claas Foo

{
static vid Main(atring(] args)

{
Botl jugl = new BotlOj
Bot2 jug2 = new Bot2();
Juego j = new Juego ();
j,EmpezarPartida(jugl, jug2);

}
}

150

u s r .c o d e

Polim orfismo

La idea sera que ahora la instancia de la clase Juego invocase los mtodos de los ob
jetos del tipo

Botl y Bot2.

Sin embargo, en pantalla veremos nuevamente:

Console.WriteLine("ClaBe: Jugador, Mtodo: RealizarMovida");


Console.WriteLine("Clase: Jugador, Mtodo: RealizarMovida");

Esto no era lo que esperbamos! Analicemos un poco qu es lo que ha ocurrido:


El mtodo EmpezarPartida recibe dos objetos del tipo Jugador; nosotros estamos en
viando un objeto del tipo Botl y otro del tipo Bot2. El compilador no arroja error
alguno, ya que

Botl

es subclase de Jugador, al igual que Bot2, por lo que es total

mente vlido, ya que al ser subclases de Jugador tambin pueden ser considerados
de dicho tipo (podramos establecer una analoga definiendo que si un gato es una
particularizacin de un animal, entonces un gato ES un animal). Lo que aqu hici

mos sin querer fue lo que se denomina upcasting.


Luego, el mtodo

EmpezarPartida

invoc el mtodo

RealizarMovida

de un objeto,

que si bien es del tipo Botl, fue asignado a un parmetro del tipo Jugador; por lo
tanto, cuando se realiza la invocacin, se ejecuta la versin del Jugador.
Para modificar este comportamiento, deberamos declarar al mtodo

RealizarMovi

da como virtual; para realizar esto nos alcanzar con anteponer dicha palabra como
un modificador ms:
class Jugador

{
public virtual void RealizarMovidaO

{
Console.WriteLine("Clase: Jugador, Mtodo: RealizarMovida*);

}
}

[JJ

ENTENDIENDO LA SOBRECARGA DE MTODOS

Es importante realizar pruebas de distintos ejemplos para entender bien cmo funcionan los mto
dos virtuales y poder anticipar con total seguridad cul ser el comportamiento de nuestro progra
ma en cada caso. Por suerte, el excelente depurador que incluye el entorno Visual Studio .NET nos
facilitar mucho la tarea, y3 que podremos seguir paso a paso la ejecucin de nuestro programa.

u s r .c o d e

151

PROGRAMACIN C#

Luego, cuando sobrecarguemos dicho mtodo en las subclases correspondientes,


deberemos agregar otro modificador llamado

override:

claas Botl : Jugador

{
public override void RealizarMovidaO

Consol.WriteLine("Clase: Botl, Mtodo: RealizarMovida");

}
}
class Bot2 : Jugador

{
public override void RealizarMovidaO

{
Consol.WriteLine("Clase: Bot2, Mtodo: RealizarMovida*);

}
}

Si ejecutamos el programa nuevamente, ahora obtendremos la siguiente salida:


Consol.WriteLine("Clase: Botl, Mtodo: RealizarMovida");
Consol.WriteLine("Clase: Bot2, Mtodo: RealizarMovida");

Este mecanismo, que en apariencia es sencillo, brinda al lenguaje una caracterstica


sobresaliente que, si la empleamos correctamente, otorgar a nuestros modelos ele
gancia y sencillez, dos de las cualidades ms buscadas e importantes en un sistema.
Notemos en nuestro ejemplo que la clase Juego est, finalmente, invocando un m
todo de una clase

(Botl, Bot2)

que ni siquiera conoce directamente. El da de ma-

I f f l EL MODIFICADOR OVERRIDE
Otros lenguajes orientados a objetos, como el C++, no especifican que deba declarase un modi
ficador override cuando se est sobrecargando un mtodo virtual. Por suerte, C# ha incorpora
do esta caracterstica, que evita posibles errores y malas interpretaciones.

152

u s r .c o d e

Polim orfismo

aa podremos crear nuevas subclases de Jugador y hacer que Juego las invoque sin
modificar una sola lnea de esta ltima clase.
Vayamos ahora un paso ms adelante. Podramos establecer que todas las implementaciones de algn jugador debieran ser subclases de Jugador, y de esta subclase
dejar nicamente el esqueleto, ya que, al fin val cabo, imponiendo esta regla no ca
be la posibilidad de que exista una instancia Jugador, sino que existirn instancias
de sus subclases.
Dejar el esqueleto implicara colocar slo las declaraciones de ios mtodos; ningn
sentido tendra colocar sus definiciones, ya que nunca sern ejecutadas. Obrando de
esta manera estaramos creando lo que se conoce como interfaz (en ingls, interfac).

Interfaces
Como mencionamos en el prrafo anterior, una interfaz es una estructura de daros
que nicamente posee declaraciones, pero que no realiza implementacin de ningn
mtodo. Un contrato que es expresado para que posteriormente lo implemente quien
se subscriba a l.
Para convertir nuestra clase Jugador en una interfaz deberemos escribir:
interface Jugador

{
void RealizarMovidaO;

Ntese que:
Cambiamos la palabra reservada class por interface.
Eliminamos el modificador public (ya que todos los mtodos declarados dentro de
una interfaz siempre son pblicos).

MS ACERCA DE LAS INTERFACES

Una interfaz puede declarar propiedades Ideclarando el get y/o el set pero sin imptementarlos). Una interfaz NO puede poseer variables ni constantes, ni heredar de ninguna clase, pero
S de otras interfaces. Finalmente, una clase que herede de una interfaz debe implementar TO
DOS los mtodos declarados por ella.

u s r .c o d e

153

PROGRAMACION C#

* Eliminamos el modificador virtual (todos los mtodos en una interfaz se compor


tan como virtuales).
Eliminamos

RealizarMovida

(una interfaz slo posee declaraciones).

Figura 1 1 . Nuestro diagrama de clases final.

Existe una convencin arbitraria respecto a la creacin de identificadores de las in


terfaces. Esta convencin consiste en anteponer una I al nombre deseado (por lo
que nuestra llamante interfaz debera llamarse Jugador).
Posteriormente, en las clases Botl y Bot2 hemos eliminado el override. Sin embar
go, hubo tambin un cambio conceptual importante: las clases Botl y Bot2 ya no
heredan de una clase, sino de una interfaz.
Es importante mencionar que el lenguaje C# NO soporta herencia mltiple, esto
significa que una clase nicamente puede heredar de una y slo una clase. Sin em
bargo, s puede suscribir contratos con muchas interfaces.
El poder de una interfaz bien empleada es enorme. Cada clase que suscriba un con
trato con alguna interfaz podr luego ser tipificada con el tipo de dicha interfaz (al
go as como lo que ocurri con

Botl,

que fue pasada como Jugador).

Clases abstractas
Es muy posible, en el caso anterior, especificar Jugador como una clase especial, de
nominada clase abstracta. Las clases abstractas poseen la caracterstica particular de
no poder ser instanciadas. Estas son creadas con el propsito de ser utilizadas
posteriormente por medio de la herencia.
Y cul es la diferencia respecto a las interfaces? Las clases abstractas pueden definir
mtodos o declararlos como abstractos, para luego ser implementados por subcla

154

u s r.c o d e

Polim orfismo

ses. Ademas, pueden poseer variables y constantes; es decir que se asemejan mucho
ms a una clase convencional que las interfaces.
Veamos cmo podramos haber declarado Jugador como una clase abstracta;
abatract class Jugador

{
abatract public void RealizarMovida();

Como se puede apreciar, colocamos la palabra reservada abstract antes de class y an


tes de la declaracin del mtodo que se comportar como un mtodo virtual con
vencional (por lo que habr que colocar override antes de sobrecargarlo en las sub
clases, como habamos hecho en un principio).

RESUMEN

En este captulo hemos analizado conceptos en apariencia simples pero muy profundos.
U tilizar correctam ente el polimorfismo y la herencia ser determ inante en la creacin de
sistemas complejos. Las propiedades nos brindan la posibilidad de reforzar el encapsulamiento; la herencia nos permite crear programas con mucho menos cantidad de cdigo y ms
fciles de m antener; tos mtodos virtuales, interfaces y las clases abstractas nos ayudan a ex
plotar el polimorfismo hasta el lm ite. Todo esto, sumado a la gran arquitectura con la cual fue
creada la librera BCL. Nunca antes otro lenguaje de programacin orientado a objetos haba
contado con un nmero similar de recursos. Programar en C# es realmente un placer.

u s r .c o d e

155

R 3 ACTIVIDAD

TEST DE AUTOEVALUACIN

Es posible definir una clase que no sea


subclase de ninguna otra?

3 Cundo es conveniente brindar acceso


irrestricto a una variable miembro y cun
do conviene regular su acceso por medio
de una propiedad?

U Para qu se utilizan los mtodos virtuales?

5 Cules son las diferencias entre una in


terfaz y una clase abstracta?

6 Puede una interfaz heredar de una clase?


2 Una variable privada puede ser accedida
desde (puede existir cero, una o varias op
ciones correctas):
a. La clase desde la cual fue declarada.
b.Una subclase de la clase desde la cual
fue declarada.
c. Externamente, desde un objeto de la cla
se desde la cual fue declarada.

156

u s r .c o d e

PROGRAMACIN CS

Captulo

Colecciones
El array es uno de los recursos ms
poderosos que ofrece C#. Analizaremos
aqu diferentes tipos de arrays, de una
dimensin y multidimensionales, cmo
usarlos y los beneficios que ofrecen.
Veremos qu son los indexadores, que es
una coleccin y cules son las interfaces
ms importantes de colecciones que

Arrays
Mtodos de la clase Array
Arrays como parmetros
de mtodos
Valores predeterminados
en un array
Inicializando elementos
de arrays

158
163
166
169
171

posee el framework .NET (lEnurnerable,


ICollection, Comparable, IList).
Por ltimo, explicaremos qu es un
diccionario y el uso de la clase Hashtable.

E modificador params
Arrays multidimensionales
Inicializacin de un array
de dos dimensiones
Arrays de arrays
Indexadores
Indexadores para acceder
a arrays de dos dimensiones
Colecciones
lEnurnerable y lEnumerator
ICollection
IComparable
IList...
Diccionarios
El diccionario Hashtable
Resumen

s e r v ic io de atencin ai . lec t o r :

le cto res@ m pe dicon es.co m

Actividades

172

173
176
176
179
184
185
185
188
189
189
190
191
193
194

PROGRAMACIN C#

ARRAYS
Hasta este momento hemos aprendido la manera de crear variables que contengan
en su interior un valor determinado relacionado con el tipo de dato de las mismas.
En el caso de que quisiramos almacenar, por citar un ejemplo, el nombre de un
alumno, podramos especificar:
string nombre;

Y si quisiramos especificar cinco de las notas que el alumno obtuvo en un deter


minado curso? Si nos aferrramos slo a lo que hemos aprendido hasta el momen
to, deberamos escribir:
float notal;
float nota2;
float nota3;
float nota4;
float nata5;

Esto no es para nada prctico, debido a que todo clculo relacionado con el con
junto de datos (como, por ejemplo, el promedio de las notas) nos obligar a escri
bir el nombre de cada una de las variables.
| float promedio = (notal + nota2 + nota3 + nota4

+ nota5) / 5;

Y si el da de maana la cantidad de notas fuera diez en lugar de cinco, entonces de


beramos modificar nuestro programa del siguiente modo:
float promedio = (notal + nota2 + notaS + nota4

+ nota5 + notafi +

nota7 + nota8 + nota9 + notalO) / 5;

Afortunadamente, en este tipo de casos, el lenguaje C# admite diversas maneras de


lidiar con conjuntos de datos.
Un mtodo clsico para hacerlo es por medio de arrays, que es el tipo de coleccin
ms simple que nos ofrece este lenguaje de programacin.
Un array es un conjunto de elementos de un cierto tipo, a los cuales es posible ac
ceder por medio de un ndice. Son especialmente tiles en aquellas situaciones don-

158

u s r.c o d e

Arrays

de debemos guardar no un dato, sino un conjunto de datos de un mismo tipo. Un


array posee un tipo y un identificador (hasta este punto, como cualquier variable).
Lo que en sintaxis de declaracin diferencia a un array de una variable convencio
nal es el sufijo de corchetes ([]) que sigue al tipo de dato de ste.
Veamos cmo declarar un array de nmeros flotantes:

Con lo escrito, hemos declarado el array, pero an no podremos utilizarlo. Para ello
deberemos solicitar memoria para la cantidad de elementos que poseer, y esto lo
hacemos utilizando el operador new:

Ntese que luego del operador new especificamos el tipo de dato, y esta vez entre
los corchetes indicamos cul ser la cantidad de elementos de nuestro array.
Tambin podramos haber especificado todo en una sola lnea:
float [] notas = new float [5];

...

.,

A continuacin, en las Figuras 1 y 2, se pueden obsevar los diagramas de declara


cin y definicin de arrays:

LOS LMITES DE UN ARRAY

.jjgaaMgaBBBHfiHBSBHMaaBMMB

........

...

. -

.............

.. . . .

r*

::

I *' .-' iffi

/ > *

En C#, los lmites de un array son verificados (algo que no se hace en C o en C++). Si intentamos
acceder a un elemento no vlido (por ejemplo, mayor al nmero total de elementos), el frame-

' ......
work arrojar una excepcin en tiempo de ejecucin

u s r .c o d e

i;

ir -V

' '

''

'

159

PROGRAMACIN CU

Cuando declaramos un array de n elementos, el primer elemento se accede por


medio del subndice 0, mientras que el ltimo se accede por el subndice n -1.

160

u s r .c o d e

Entonces, en un array de tres elementos, el primer elemento se acceder por el su


bndice 0, el segundo por el subndice 1 y el tercero por el subndice 2.
Ahora podremos acceder a cada elemento del array por medio de un subndice (Fi
gura 3), por lo que podramos escribir:

Si calculamos el promedio del modo en que lo hicimos en el listado anterior, no es


taremos haciendo un buen uso de los arrays.
El poder de este recurso se explota mejor utilizando sentencias de bucle.

Con los diagramas de flujo podremos expresar, sin obligacin de ligarnos al lengua
je de programacin, cmo ser el flujo de ejecucin de nuestro programa.

PARA QU SIRVE UN DIAGRAMA DE FLUJO?

:x'* "

* ;

Los diagramas de flujo se utilizan para disear algoritmos esquemticamente, antes de llevar
los al cdigo. De este modo, nos concentramos slo en el problema, y no en una sintaxis parti
cular del lenguaje de turno, porque un diagrama de flujo no est relacionado especficamente
con ningn lenguaje de programacin.

u s r .c o d e

161

PROGRAMACIN C#

Existen diversos tipos de recuadros para expresar diferentes tipos de sentencias:

Salida a pantalla

c m
Entrada por teclado

Asignacin, Llamada a funcin...

Sentencia condiciona

condicin

no

si

La condicin es una expresin


que se evala por verdadero o falso.
Bucle condiciona
La condicin es una expresin
que se evala por verdadero o falso.
Bucle contador
I es la variable del bucle
n es el valor Inicial que toma la variable
m es el valor final que toma la variable
Comienzo del programa

Fin del programa

0
nombrejuncin

Cabecera de funcin

parmetros

Figura 5. Diagramas de flujo.

m i EN C# LOS ARRAYS SON OBJETOS


D e dnde s a li la p rop ied ad

Length?

C ad a objeto d e c la ra d o e s d e sce n d ie n te de la c la s e

L o s a r r a y s d e riv an im p lc ita m e n te de la c la s e

Anay (qu e

d e s c ie n d e de la c la s e

b rind a m to d o s y p ro p ie d a d e s para su m a n ip u la ci n . U n a d e e lla s e s

Object.

Object], lo cu a l

Length, q ue tie n e

co m o

fu n ci n d e vo lv er e l to ta l de e le m e n to s q u e p o se e el arre g lo .

162

u s r.c o d e

Arrays

Y ahora, si vamos a cdigo C#:

Analicemos en detalle el listado anterior:


1. Declaramos una variable donde acumularemos la sumatoria de las notas.
2. Especificamos una sentencia de bucle for, desde 0 hasta la cantidad mxima de
elementos menos uno (cuando i sea igual a la cantidad mxima de elementos, no
se ingresar en el cuerpo del bucle).
3. En el cuerpo del bucle acumulamos las notas en una variable. El operador += (su
ma y asignacin) suma el valor de la constante o variable a derecha con la varia
ble a izquierda, y luego lo asigna a la variable a izquierda.
Existen otros operadores que nos facilitan la escritura de cdigo, as como ste.
Veamos algunos de los ms comunes:

Tabla 1. Listado de operadores ms comunes.

4. Realizamos el clculo del promedio haciendo uso de la sumatoria calculada en la


variable sumaDeNotas y la cantidad total de elementos del array.
Ahora, en el caso de que la cantidad de notas fuera diez en lugar de cinco, el lista
do anterior permanecera sin modificacin alguna. De esta manera, podemos em
pezar a avizorar cules son las ventajas de este recurso.
Qu sucedera en el caso de que la cantidad de notas fuese mil en lugar de cinco o
diez? No habra otro modo prctico de manipularlas sin hacer uso de arrays.

u s r .c o d e

163

PROGRAMACIN CU

Mtodos de la clase Array


Como hemos mencionado, codo array deriva implcitamente de la clase Array. Vea
mos cules son los mtodos y las propiedades que podremos utilizan

BinarySearcb

Bsqueda binaria de un elemento en el array ordenado.

Clear. IH 1

sv -

rripi. un ssav tsflp feto aer parte

Copia la cantidad de elementos especificada de un array a otro,

Copy

'

, "

fo

Cooy
GetBtumerator

No

Devuelve un Enumrate; para el array. Dicho objeto, como eremos ms adelante,

fio
. vetit-r.gcr.
GetVaue

,,

NcNo

Devuelve un elemento en el ndice especificado por parmetro.


V:. :
"'

fever
SetValue
i Sor! ,

No
S

Fija un elemento del array en el ndice especificado por parmetro.


i

I
Tabla 2. Mtodos utilizados en la clase Array.

Tabla 3. Propiedades de la clase Array.

Veamos cmo utilizar algunos de estos mtodos y propiedades;


Crearemos un array de diez elementos con valores de elementos arbitrarios; luego
ordenaremos su contenido y buscaremos un valor en particular. El resultado de la
bsqueda ser mostrado en pantalla.

UN ARRAY EN MEMORIA
gjjj

E l espacio en m em oria que ocu p a un a rra y corresp ond e a l espacio que ocupa un elem ento d el ti
po de dato a i cu a l pertene.ee, m ultiplicado por e l tam ao d el array. S i cada elem ento ocu p a 4 bytes, un at a y ce 10 ele m e n to s o cu p ar 40. byts. Los elem entos.d e un a rra y son colocados,adya
centem ente en la m em oria, para a cc e d e r a ellos fcil .y rp id am en te por m eda de un subndice.

164

u s r .c o d e

Arrays

. inct] nums * new int [10];


numeC] = 3;
nunsl] ; 1;
nune[2] 8

'

.
->
>
-
.

nuns i3] = 5;
nuas!4) =

9;

nums [5] = 2
nums [6] = 0;
nums[7] * 6;

mas 18) = 12;


mima [91 = 10;
/ Ordeno el array
Array.Sort(nums);

/ / Kealizc una bsqueda sabr el lsrsp, de un


// elemento arbitrario
int elemento = Array.BinarySearch(nums, 2);
i (elemento ;>= 0)
Consol.KriteLine! "Elemento encontrado en ndice: {o},
elemento);
else
Console.WriteLine"Elemento no encontrado");

Del listado anterior es interesante notar:


La invocacin al mtodo Sort la realizamos por medio de la clase Array y no por
medio del objeto array nums, debido a que es un mtodo esttico. Lo mismo su
cede con BinarySearch.
El mtodo BinarySearch recibe como primer parmetro el array por ordenar, y co
mo segundo parmetro, el elemento por buscar (aunque este mtodo se encuen
tra sobrecargado y existen otras variantes). Devuelve el ndice del elemento encon
trado, y en caso contrario, un valor negativo.
Ahora veremos otro ejemplo. Crearemos nn array de nmeros arbitrarios. Copiare
mos el contenido de dicho array en otro e invertiremos su contenido. Finalmente
mostraremos el contenido de ambos arrays en pantalla.
int[] nums = new int [5];
nums[0 = 3 ;

nuKSti) - 1;

u s r .c o d e

165

PROGRAMACIN C#

nums [2] s 8;
Duna [3] = 5;
nums[4] 9;
int [3 nums2 new int (53;

// Copio el contenido de un array a otro


nums.CcpyTo(nums2, 0);

// Invierto uno de los arrays


Array,Reverse(nums2);
Console.WriteLine("Array notas"};
for (int i=0; icnuma.Length; i++)
Consol.WriteLine("elemento {0}: {l}, i, numsti]);
Console.WriteLine("Array notas2"};
for (int i=Q; i<nums2.Length; i++)
Console.WriteLine("elemento {O}: {!}", i, nums2[ij);

Del listado anterior es interesante notar:


La invocacin del mtodo CopyTo la realizamos haciendo uso del array nums, de
bido a que ste no es esttico (el mtodo Copy s lo es). El primer parmetro que
espera CopyTo es el array destino, y el segundo parmetro, el ndice a partir del cual
comenzar la copia.
El mtodo Reverse es esttico, por lo tanto lo invocamos por medio de la clase Array.
Cabe destacar, como ya mencionamos, que muchos de los mtodos de la clase Array
(as como muchos mtodos de las clases de la librera

BCL) se encuentran sobrecar

gados, por lo que no existe un solo modo de utilizarlos. En este caso hicimos uso
de la versin de los mtodos que mejor se adaptaba a nuestras necesidades.

Arrays como parmetros de mtodos


Los arrays son tipos de datos referenciados, al igual que las clases. Cuando pase
mos un array como parmetro, no estaremos pasando una copia de ste, sino una
referencia a l, lo que permite a una funcin modificar directamente su contenido.
Veamos un ejemplo de un mtodo que recibe un array como parmetro:
void ModiicarArray(int[] nums}

{
n u m s [0 3

= 50;

166

u s r .c o d e

A rra y s

Ntese que el parmetro es del tipo int[] y que no especifica el tamao del arreglo,
es decir que el mtodo podr recibir arrays de enteros de cualquier tamao. En to
do caso sera conveniente verificar, antes de a leer o escribir un elemento, si el ndi
ce se encuentra dentro del rango vlido (por medio del uso de la propiedad Length).
Veamos el programa completo:
clasa Foo

'

{
public static void ModificarArray{int[3 arr)

'

{
arr[0] * 50;

}
static void Main (string [] args)

(IIP
^

int f} nuns * new int [5];

nums[03 * 3;
nums[13 = 1;

nums[2f a 8;

'

: V :'

nums[33 s 5;
nums[4] = 9;
Console.WriteLine("Array notas");
for (int i=0; icnums. Length; i++)
Console.WriteLine("elemento {O}; {l}*, i numsij);

Foo.ModificarArray(nums);
Console.WriteLine("Array notas modificado");
for (int i=0; icnums.Length; i++)
Console.WriteLine("elemento {0}: {l}",
i, nums[i]) ;int[] nums2 = new int[53;

}
}

La lnea de mayor inters para nosotros es aqulla en la que invocamos el mtodo


esttico ModificarArray (es esttico pero podra no serlo). Lo importante es ver que
para pasar el array como parmetro simplemente escribimos su nombre sin hacer
uso de los corchetes y sin ningn modificador. Si, en el caso contrario, deseamos
pasar en forma de parmetro

u s r .c o d e

un elem ento

del array, deberemos escribir:

167

PROGRAMACIN CU

Poo.ModificarElemento(ref nums[0]);

El mtodo ModificarElemento no recibe un array, sino el elemento de un array, por


lo que el tipo de dato debe ser igual al tipo de dato del array (en nuestro caso, sim
plemente un entero):
void ModificarElemento(re int num)

'

num = 33;

En realidad, el mtodo

ModificarElemento

recibe un nmero entero que puede ser

elemento de un array o una variable convencional. Es importante entender que los


elementos de un array pueden ser vistos como variables convencionales del tipo que
corresponde al arreglo.
El hecho de utilizar ref como modificador del parmetro es para especificar que dicho
parmetro debe ser pasado como referencia. Si bien los arrays son tipos de datos refe
renciados, cuando se pasan elementos de ellos se envan copias y no referencias.
Tambin podemos crear otro mtodo que reciba un nmero entero sin que ste sea
referencia, y luego enviarle el elemento de un array:
public static void MostrarValortint num)

{
Consol.WriteLine(*valor variable: {0}", num);

Y ahora el listado completo, en la pgina siguiente:

[ [ [ I ARRAY QUE CONTIENE DIFERENTES TIPOS DE DATOS


Par3 crear un array que pueda contener objetos de diverso tipo, deberemos crear un array de ob
jetos de tipo Object. Como todo tipo de dato es descendiente de Object, podremos agregarte n
meros, strings, booleanos o cualquier objeto creado por nosotros.

168

u s r .c o d e

_________________________________________________________________________________________________ A rr a y n

class Foo
public static void ModificarElemento(re int num)

{
num = 33;

}
public static void MostrarValorfint num)

{
Consola. WriteLine ('
valor variable; {o}", num);

}
static void Main(8tring[3 args)

{
int [] nums new int [5];

4
nums[0)

3;

numsll] = 1;
nums[2] 8;
num8[3] = 5;
nums [4] =-9;
Foo.Modificarlemento(ref nums [0]);
Foo.MostrarValor (nuais [0]) ;
Consol.WriteLine("Array notas*);
for (int i0; icnums.Length; i++)
Consol.WriteLine(*elemento {0}: {l}", i, numstij)
int variableConvencional * 10;
Foo.ModificarElemento(re variableConvencional);
Foo.MostrarValor(variableConvencional);

Dediqese especial atencin, en el listado anterior, a que enviar

array de enteros supone, en cuanto a resultado, exactamente lo

una variable del tipo que corresponda al array.

un elemento de un
mismo que enviar

Valores predeterminados en un array


Los arrays de tipos de datos que el compilador maneja por valor son inicializados
automticamente cuando son definidos;

usr.code

169

PROGRAMACIN C#

En el ejemplo anterior, el array comenzar relleno con ceros.


Pero si el array es de un tipo referenciado (array de objetos), entonces los elemen
tos son inicializados en nuil, y para poder hacer uso de cada uno de ellos deberemos
inicializarlos individualmente por medio del operador new. Veamos un ejemplo de
esto ltimo para que quede ms claro.
Si tenemos la clase Foo definida del siguiente modo:
d a s 8 Foo

Poo()

{
Console.WriteLine("Constructor") ;

}
}

Podramos crear un array de objetos de sta escribiendo:


Fool) arrayDaFoo * new Foo[5];

Sin embargo, esto no producir la invocacin de los constructores de los objetos de

Foo. El array tendr cinco elementos con valor nuil, que son referencias a objetos del
tipo Foo que an no han sido inicializadas.
Para poder utilizar los elementos deberemos inicializarlos en forma individual. Po
dramos realizar esta tarea inmediatamente despus de la declaracin del array o a
medida que lo requiramos (hay que tener en cuenta que inicializar un objeto impli
ca ejecutar cdigo de constructores; realizar esto una gran cantidad de veces podra
influir en la performance de nuestra aplicacin).
for (int i=0; i<arrayDeFoo.Length; i++)
arrayDeFoo(i) new Foo();

Ahora s, se ha ejecutado el constructor de cada uno de los elementos del array, tras
lo cual podremos acceder a sus variables, mtodos y propiedades. En la Figura 6 se
puede apreciar otro ejemplo de lo mencionado:
170

u s r .c o d e

Foo[]arrayDeFoo =new
Foo[5];

arrayDeFoo[2] =new Foo();


nuil

[0]

nuil

[0]

[1]

nuil

(11

nuil

[2]

nuil

[2]

referencia a objeto
tipo Foo

[3]

nuil

[3]

nuil

14]

nuil

[4)

nuil

objeto tipo Foo

Figura 6. Inicializacin de arrays.

Inicializando elementos de arrays


Es posible dar valores arbitrarios a los elementos de un array de un modo ms abre
viado que el que hemos empleado hasta el momento.
Para ello, en lugar de hacer:
int t nume * new int [5];

'

nums[0] t 3
numatl] a 1;
nums[2] * 8;
nums[3]

9;

= 5;

numaf] =

podremos hacer simplemente:


int(] nums = new int(5] {3, 1, 8, 5, 9};

U IJ EL TAMAO DE LOS ARRAYS


Los arrays que estamos analizando en estas pginas no pueden ser redimensionados, es decir que
si le asignamos un tamao especfico, dicho tamao ser fijo hasta que el array sea destruido. C#
cuenta con una implementacin de arrays redimensionables en la clase AnayList de la librera BCL.

usr.code

171

PROGRAMACIN C#

O mejor an:
int[]

nm$

= (3, 1, 8, 5, 9};

Recorriendo arrays
Hasta el momento, hemos recorrido arrays por medio de la sentencia for. Tambin
podramos haberlo hecho utilizando la sentencia while para recorrer un array, tal co
mo se detalla a continuacin:
int [] nuxos new int 15];
int i=0;
while (i<nums.Length)

{
Consol.WriteLinefmims [i]);

i++I
}

Sin embargo, la sentencia que mejor se adeca a los arrays tal vez sea el foreach (au
sente en los lenguajes C y C++). En el Captulo 2 ya habamos introducido esta sen
tencia; aqu veremos nuevamente cmo recorrer un array haciendo uso de ella:
intfi nuraa = {10, 20, 30, 40, 50}
foreach {int i in nwns)

{
Consol,WriteLine(i);

Como podemos apreciar, en la sentencia foreach declaramos una variable que oficiar
de elemento en cada iteracin. Luego utilizamos dicha variable para mostrar en panta
lla el contenido del array (tengamos en cuenta que con dicha variable podremos leer el
contenido del array, pero no podremos modificar el contenido de los elementos).

El modificador params
Es posible especificar un modificador al parmetro de una funcin llamado params,
que nos permitir pasar arrays o un conjunto de elementos que el compilador tra
ducir a arrays de manera dinmica. Para ello deberemos escribir:
172

u s r .c o d e

Arrays multidimensionales

void Listar (pararos int I] nums)

for (int ieO;.i<nums.Langth; i++)


Console.WriteLine(nuas(i]);

Veamos ahora cmo invocar el mtodo Listar, por medio de un array convencional:
int ] nums

{3, 1, 8, 5, 9};

foo.Listar(nums

);

O un array creado dinmicamente a partir de un conjunto de elementos:


foo.Listar(1, 2, 5, 10, 99);

ARRAYS MULTIDIMENSIONALES
C# soporta la definicin de arrays de mltiples dimensiones. Hasta el momento, to
dos nuestros arrays eran de una dimensin, pero es posible definir arrays de dos di
mensiones (ideales para representar tablas, cuadros de dos entradas, matrices, etc.)
o de las dimensiones que nos parezcan.
Veamos cmo declarar un array de dos dimensiones:
int[,] tabla a nev int (3, 3];

Como podemos apreciar en el listado anterior, luego del tipo de dato del array en
tre los corchetes, existe una coma. Tambin, en lugar de haber un solo nmero en
la indicacin del tamao del array, figuran dos, correspondientes a la cantidad de
elementos por cada dimensin.
Es muy prctico imaginar un array de dos dimensiones como una tabla, siendo la
primera dimensin la cantidad de filas, y la segunda dimensin, la cantidad de co
lumnas (o al revs, segn la convencin que se desee emplear).

u s r .c o d e

173

PROGRAMACIN Ctt

Figura 7. Dos maneras distintas de pensar un array de dos dimensiones.

Para poder acceder a los elementos de un array de dos dimensiones, se deber hacer
uso de la siguiente sintaxis:
tabla[0, 0] = 10;

En esta oportunidad, hemos decidido asignar el nmero 10 al primer elemento del


array (fila 0, columna 0).
En el siguiente diagrama se puede observar cmo seguimos trabajando con otros
elementos del array:

Figura 8. Accediendo a otros elementos del array.

174

u s r .c o d e

Arrays multidimensionales

Es bueno tener presente que la cantidad de dimensiones de un array slo facilita la


sintaxis para el acceso a elementos. Toda implementacin en arrays multidimensio
nales puede realizarse en arrays de una dimensin.
El siguiente diagrama nos sirve para graficar el ejemplo:

Veamos ahora esta equivalencia en cdigo. Si tuviramos que representar una tabla
con un array de dos dimensiones, procederamos del siguiente modo:
int cantidadFilas = 3;
int cantidadColusmas = 3;
intt,] tabla = new int[cantidadFilae, cantidadColusmas];
for (int i=0; i<cantidadPilas * cantidadColusmas; i++)
tabla [i / cantidadColusmas, i % cantidadColusmas] = i;
for (int fila=0; filaccantidadFilas; fila++)
for (int col=0; col<cantidadColusmas; col++)
Consol.WriteLine(tabla(fila, col]);

Si, en oposicin al caso anterior, nos encontrramos en la obligacin de representar


una tabla con un array de una dimensin, entonces:

u s r .c o d e

175

PROGRAMACIN CS

int cantidadPilas 3;
int cantidadColumnas = 3;
int I) tabla = new int [cantidadPlas * cantidadColumnaa];.
for (int i=0; iccantidadFilaa * cantidadCol-uanaa; i++)
tabla [i] s i;
for (int fila=0; filaccantidadFilas; fila++)
for (int col=0 colccantidadColumnas; col++)
Consol.WriteLine(tabla[fila*cantidadColumnas+col]);

Como podemos apreciar en el listado anterior, llevamos a cabo la conversin de una


a dos dimensiones con una simple cuenta.

Inicializacin de un array de dos dimensiones


Es posible inicializar un array en el momento de definirlo, as como lo habamos
hecho con el array de una dimensin.
Para esto deberemos escribir:
int( ,] tabla = {{0 ,1 ,2 },{3 ,4 ,5 },{6 ,7 ,8 }};

En este caso, el compilador entiende, en funcin de cmo dispusimos las constan


tes (tres grupos de tres nmeros), que la matriz ser de 3 x 3.

ARRAYS DE ARRAYS
Adems de los arrays multidimensionales que analizamos en los prrafos anteriores
y que son conocidos con el nombre de arrays
posibilidad de declarar arrays

rectangulares, tambin tenemos la


de arrays (ms frecuentemente conocidos con la de

nominacin de jagged arrays).


Para declarar un array de array deberemos escribir:

in t[][]

arrayDeArrays;

Notemos que, ahora, dentro del corchete no hay nada, pero existe otro juego de
ellos tras el primero. Esto quiere decir que poseeremos un array en el cual cada uno
de sus elementos ser, a la vez, otro array.
1 76

u s r .c o d e

Arrays de arrays

Ahora definamos el array de nivel ms alto, el que contendr al resto de los arrays:
arrayDeArrays = new int [S] [];

Aqu obtendremos un array de cinco arrays. Los arrays que se encuentran dentro
del primero an no fueron definidos, por lo que lo que tendramos en memoria se
corresponde con el siguiente diagrama:

Array de arrays

[0]

<no def>

[1]

<no def>

[21

<no def>

[3]

<no def>

[4]

<no def>

Figura 1 0 . Todava no hemos definido los arrays de segundo nivel.

Definamos, entonces, los arrays que se encuentran dentro del primer array. Estos no
tendrn por qu poseer el mismo tamao:
arrayDeArrays[0] new int [3];
arrayDeArrays[11 = new int[21;
arrayDeArrays[21 = new int[5J;
arrayDeArrays[31 = new int[4];
arrayDeArrays [43 = new int [2];

U U USO DE LOS JAGGED ARRAYS

D ebido a que los jag g e d a r r a y s no tie n e n p o r qu s e r r e c ta n g u la re s (e s d e cir que cad a e le m e n to


d el p rim e r a r r a y no tie n e p o r qu p o s c o r un a r r a y d e l m ism o ta m a o que e l e le m e n to a n te rio r),
su e le n s e r m s p r c tic o s y h a c e r un m e jo r uso de r e c u rs o s p ara ca s o s e sp ec fico s.

u s r .c o d e

177

PROGRAMACIN C#

Tambin cambia ligeramente el modo en que accedemos a sus elementos:

nnr

ELEMENTOS NULOS
,

-" ;

E s p o sib le q u e a lg u n o s e le m e n to s d e n u e stro ja g g e d a r r a y p o se an un v a lo r nulo, e s d e c ir que no


co n te n g a n ningn otro array . A n te e s ta p o sib ilid ad , slo d e b e re m o s te n e r en cu e n ta que n u e stro
p ro g ra m a v e rifiq u e la valid ez d e l e le m e n to - q u e no se a n u lo - a n te s de a c c e d e r a l.

178

u s r.c o d e

Indexadores

arrayDeArraya10][0] 1;
arrayDeArraya[0][1] =

2>

| arrayDeArraya[0] [2] 3?
arrayDeArraya[1][0] 1;
arrayDeArraya(I](1] a 2;
arrayDeArrays 12][0] 1;
arrayDeArrays12][1] * 2 ;
arrayDeArraya[2] f2] * 3;
arrayDeArraya[2][1] = 4;
arrayDeArraya[2][2] = 5;
arrayDeArraya[3] [0] = 1;
arrayDeArraya13][1] = 2;
arrayDeArraya(3][2] = 3;
arrayDeArrays13)[1] 4;
arrayDeArraya4][0] = 1 ;
arrayDeArraya14][1] - 2;

INDEXADORES
En ocasiones puede ser beneficioso permitir acceder a una coleccin dentro de un
objeto que hayamos creado como si ste fuese un array, es decir, utilizando el ope
rador de indexacin [].
C# permite realizar esto no por medio de la sobrecarga del operador [], como ocu
rre en C++, sino a travs de una caracterstica denominada indexador.

Un indexador se asemeja en gran medida a una propiedad, pero no posee nombre,


sino que, por el contrario, es invocado cuando se utiliza el operador de indexacin
([]) junto con el identificador del objeto en cuestin.

{]

USO DE INDEXADORES

L o s ind exad o res p u e d en s e r e l r e c u rs o id e a l p ara d o ta r a nue stro s ob jetos de un f c il e intuitivo


m to d o de a c c e s o a e le m e n to s co n te n id o s e n e llo s.

u sr.code

179

PROGRAMACIN C#

Supongamos que hemos implementado una clase llamada Cadena, que facilita el uso
y la manipulacin de strings (en C#, esto sera realmente innecesario, porque cuen
ta con un excelente soporte de strings). Nuestra clase Cadena poseer como variable
privada un array de caracteres donde se almacenar el texto correspondiente:
class Cadena

prvate char[] texto;

Ahora bien, si deseramos leer y fijar el contenido de la cadena deberamos escribir:


public string Texto

1 {
gat

{
string str
foreach(int c in texto)
str += (char) c;
r e t u m str;

}
set

{
texto a new char[valu.Length];
for (int i0; ievalu.Length; i++)
texto [i] = valu [i];

}
}

Analicemos lo escrito en el mtodo de acceso get de la propiedad Texto:


1. Creamos una variable local de tipo string.
2. Accedimos a cada elemento del array de caracteres y lo copiamos sobre el string.
3. Devolvimos el string como valor de retorno del mtodo.
En el mtodo de acceso set:
1.

180

Creamos un array del tamao adecuado para contener el string fijado (en la pa
labra reservada valu). Ntese que la segunda vez que se fije un valor al texto, se
u s r .c o d e

Indexadores

crear orro array; el primero ser destruido por el recolector de basura cuando al
framework le parezca adecuado (podramos haber verificado si realmente era ne
cesario crear otro array; o crear uno un poco ms grande de lo necesario para no
solicitar memoria una y otra vez, pero deseamos mantener el ejemplo sencillo).
2.

Trasladamos cada carcter del string a un elemento de nuestro array.

Siguiendo con nuestro ejemplo, ahora deseamos permitir que el usuario de nuestro
objeto de tipo Cadena pueda acceder a cada letra del string (elemento de nuestro array)
como si nuestro objeto entero fuese un array. Para esto crearemos un indexador:
public char this int ndex]
l

{
get

{
i (index < texto.Lngth)
return textolindex];
else
return '\0';

}
set

{
if (index < texto.Length)

texto[index] valu;

h
A primera vista, nuestro indexador es muy similar a una propiedad, pero si obser
vamos bien, notaremos que el identificador es diferente. La palabra reservada this
hace referencia al propio objeto en el cual estamos. Luego, entre corchetes, declara
mos una variable que ser la que podremos usar dentro de los mtodos de acceso
get y set, y la que contendr el nmero que entre corchetes especifique el ndice.

H T l USO DE INDEXADORES EN LA BCL


Muchas de las clases que manejan conjuntos de datos en la librera BCL utilizan indexadores.
Por ejemplo, la clase String implementa indexadores para el acceso a los caracteres de la cade
na de texto (slo en modo lectura).

u s r .c o d e

181

PROGRAMACIN C#

Figura 12. Diagrama de declaracin de un indexador.

[ I USO ESPECIAL DE INDEXADORES


Un indexador no tiene por qu esperar slo nmeros enteros; es un recurso muy verstil que po
dra recibir cualquier tipo de dato.

182

u s r .c o d e

Indexadores

Teniendo todo esto en cuenta, comprender el cdigo escrito en los mtodos de ac


ceso get y set resultar bastante sencillo.

En el mtodo get:
1. Verificamos si el ndice especificado se encuentra ubicado dentro del rango vli

2.

do de nuestro array.

Si es as, accedemos al elemento especificado usando la variable privada texto.

3. Si no es as, devolvemos un carcter nulo.

En el mtodo set:
1. Verificamos si el ndice especificado se encuentra ubicado dentro del rango vli
do de nuestro array.
2. En caso de comprobar que sea as, modificamos su contenido con el carcter re
cibido en la palabra reservada valu.
Finalmente, sobrecargamos el mtodo ToString para especificar qu string debe de
volverse como representacin del objeto cuando se lo requiera.
Ahora, veamos un programa sencillo que hace uso de nuestra clase Cadena:
Cadena cad * new Cadena ();

iS i S f i

cad.Texto a "el lenguaje C#*;


// El objeto como string
Consol.WriteLine(cad);
// Dejo una lnea libre
Consol. Writeliine () ;
/ / E l objeto como array de caracteres
for (int i*0j iccad.largo; i++)
Consol.Write(cad [i])j
// Dejo una linea libre
Consola. WriteLineO;
// Modifico parte del contenido del texto
cad10] = *E';
cad (3)

L';

/ / E l objeto como array de caracteres


for (int i=0; i<cad.Largo; i++)
Consol.Write(cad[il

u s r .c o d e

183

PROGRAMACIN Cff

En el listado anterior, hacemos uso del indexador definido en la clase con la finali
dad de leer los caracteres del array que se encuentra encapsulado en su interior, as
como para modificar su contenido.

Indexadores para acceder a arrays de dos dimensiones


Es posible especificar indexadores para acceder a arrays de ms de una dimensin.
Veamos un ejemplo supersencillo para entender bien esto. Queremos permitir que
el siguiente cdigo sea vlido:
Foo = new Foo{);
f [3, 4] = 10;
Consola.WriteLine(f[3, 4]);

Para esto, debemos especificar un indexador que acepte dos ndices:


public int thifl[int idxl, int idx2]

{
get

Consola.WriteLine("mtodo get. Indice 1: {C}, Indice 2:


{1}, idxl, idx2);
return 0j

set

{
Consola.WriteLine("mtodo set. Indice 1: {0}, Indica 2: {l}
Valor: {2}, idxl, idx2, valu);

}
}

INDEXADORES CON ELEMENTOS MLTIPLES

El hecho de que el indexador permila recibir ms de un tipo de dato no significa que debamos
utilizarlo solamente para el acceso a arrays multidimensionales. lanpoco es necesario que to
dos los elementos que reciba el indexador sean del mismo tipo. Come hemos mencionado antes,
es un recurso muy flexible.

1 84

u s r .c o d e

Colecciones

Como se puede apreciar, ahora enere los corchetes de la primera lnea de la declara
cin del indexador existen dos variables declaradas, y no slo una. Estas variables
representan los dos ndices que se le pasarn al objeto.
Tambin conviene destacar que nuestro indexador recibe y entrega nmeros ente
ros, y no caracteres. En realidad, podra recibir y entregar cualquier tipo de dato.

COLECCIONES
Una coleccin es un objeto que contiene un grupo de objetos afines. Mediante una
coleccin es posible actuar sobre la totalidad de un subconjunto de objetos.
C# posee diversas interfaces de colecciones que nuestras clases podrn implementar
y, de este modo, otorgar mayor facilidad de uso.

lEnumerable y lEnumerator
Por ejemplo, vimos que es posible recorrer un array mediante la sentencia de bucle
Cmo hacer para que un objeto definido por nosotros tambin pueda ser

foreach.

recorrido de igual modo? Para esto deberemos implementar la interfaz lEnumerable.


Como toda interfaz,

lEnumerable declara una serie de mtodos que quien suscriba

un contrato con ella deber implementar (todos y cada uno de ellos).


En este caso particular, es slo un mtodo con el siguiente prototipo:
lEnumerator GetSnumsrator() ;

IEnumarator es otra interfaz que bien podr implementar la misma clase que implementa Enumerable, o alguna otra clase afn.

lEnumerator declara la siguiente propiedad:


object Current {get;}

Esta propiedad ser utilizada cuando se desee acceder al elemento actual apuntado
por el enumerador. Y tambin declara los siguientes mtodos:
bool MoveNextO;

u s r .c o d e

185

PROGRAMACIN C#

MoveNext traslada el cursor al siguiente elemento.

Reset devuelve el cursor al inicio de la coleccin.


void ResetO ;

Figura 13 muestra el diagrama de clases que implementaremos a continuacin:

La

interfaz
Enumerable

" 1
ClaseEnumerable

interfaz
lEnumerator

1
------ -

+GetEnumerator()

1
O

t
ClaseEnumerador
+Current
+MoveNext()
+Reset()

Figura 13. Nuestro diagrama de clases.

Una vez que hemos implementado nuestro pequeo programa, ser posible instanciar la clase ClaseEnumerable y recorrerla por medio de una sentencia foreach, tal co
mo se muestra a continuacin:
ClaseEnumerablfi objEnum a new ClaseBnumerableO;
foreach (int i in objUnun)
Consol.WriteLine(i);

Observemos, en el listado que se encuentra a continuacin, la manera en que debe


remos implementar estas clases y qu cdigo deberemos ingresar en cada uno de los
mtodos sobrecargados:

nnr

QU ES UN ENUMERADOR?

Conceptualmente, un enumerador es un objeto que apunta a un elemento de una coleccin. Es un


cursor que nos permite recorrer una lista pasando de un elemento a otro mediante un mtodo.
Los enumeradores suelen ser muy tiles, ya qe permiten recorrer una coleccin de un mismo
modo, ms all de cmo estn mptementados (sobre arrays, tistas enlazadas, archivos, etc.).

186

u s r .c o d e

Colecciones

La ciase ClaseEnumerable:
KkdVT-

|{

A1

aSfiy*4

'"fUSfi?

rw'M

clasa ClaseBnumerable : IBnumerable

// Lista de enteros que recorreremos


prvate intU lista = {0, i, 2, 3, 4, 5};
// Mtodo GetEnumerator
public lEnumerator GetEnumerator()

{
r e t u m new ClaseEnumerador(this);

}
// Indexator para facilitar el acceso
// a elementos del array encapsulado
public int thietint idx]

{
get

{
r e t u m lista [idx];

}
}
// Propiedad Length que a su vez invoque la propiedad
// Length del array encapsulado
public int Length

{
get

{
return lista.Length;

La clase ClaseEnumerador:
clasa ClaseEnumerador : lEnumerator

7/ Referencia al objeto por recorrer

u s r .c o d e

187

PROGRAMACIN C#

prvate ClaseEnusaerable objBnum nuil;


// 1emento actual
prvate int elementoActual = -1;

ii

Constructor de la clase, recibe como parmetro

// una referencia al objeto que debe recorrer


public ClaseEnumerador(ClaseEnumerable obj)

{
objEnum = obj;

}
// Propiedad Current que retorna elemento actual
public object Current

{
get

{
return objEnumlelementoActual];

}
}
// Mtodo MoveNext
public bool MoveNexti)

{
if (elementoActual < objEnuo.Length-1)

{
elsmentoActual+t;
return true;

}
else
return false;

}
// Mtodo Reset
public void Reset)

{
eleaentoActual -1>

}
}

ICollection
Existe otra interfaz de colecciones que se denomina ICollection. Esta interfaz decla
ra las propiedades que enumeramos a continuacin:
188

u s r .c o d e

Colecciones

int Count {get;}: devuelve la cantidad total de elementos que posee la coleccin.
bool IsSynchronized {get;}: indica si el acceso al objeto es seguro por medio de di
ferentes threads concurrentes.

object SyncRoot {get;}: esta propiedad devuelve un objeto que permita sincronizar
el acceso a la coleccin.
La interfaz declara, adems, el siguiente mtodo:
void CopyTo(Array array, int ndex);

El mtodo CopyTo copiar los elementos de la coleccin instancia al array recibido


como parmetro desde el elemento indicado por index.
Si nuestra clase implementa ICollection, entonces los objetos de sta podrn copiar
elementos de una a otra haciendo uso del mtodo CopyTo.

IComparable
Si nuestra clase implementa la interfaz IComparable, entonces podr ser ordenada
por medio del mtodo Sort, ya que es posible determinar si un elemento es menor,
igual o mayor a otro.
La interfaz slo declara el siguiente mtodo:

El mtodo

CompareTo

recibe un objeto como parmetro. Se espera que el mtodo

devuelva -1 si la instancia es menor al objeto, 0 si los dos objetos son iguales y 1 si


el objeto es mayor a la instancia.
Tngase en cuenta que el objeto debera ser, en realidad, del tipo de la clase que es
tamos comparando. Para acceder a los elementos de sta deberemos llevar a cabo un
upeasting, esto significa convertir el objeto recibido del tipo object al tipo de la cla
se en la cual estamos implementando.

IList
Si nuestra clase implementa la interfaz IList, entonces sus elementos podrn ser ac
cedidos individualmente por medio de un ndice.

u s r .c o d e

189

PROGRAMACIN C*

La interfaz declara las siguientes propiedades:


bool IsFixedSize {get;}: esta propiedad nos indica si la lista es de un tamao fijo o
si puede crecer dinmicamente.

bool IsReadOnly {get;}: indica si la lista es de slo lectura.


object this[int ndex]] {get; set;}: este indexador nos brinda la posibilidad de leer
y modificar los elementos de la lista.
Por otro lado, la interfaz declara los siguientes mtodos:

int Add(object valu);: agrega elementos a la lista.


void Clear();: limpia la lista.
bool Contains(object valu);: indica si un elemento se encuentra contenido en la
lista o no.
int

IndexOf(object valu);: devuelve el ndice al elemento pasado como parmetro,

y -1 si ste no se encuentra dentro de ella.


void Insert(int index, object valu);: este mtodo se encarga de insertar un elemen
to en una posicin determinada.

void Remove(object valu);:

elimina un elemento de la lista.

void RemoveAt(int index);: elimina un elemento de la lista especificando su posi

cin dentro de sta.

DICCIONARIOS
Un diccionario es una coleccin que asocia un valor a una clave. Podra ser consi
derado como un array que utiliza ndices no numricos para acceder a los elemen
tos. Esto es muy til en innumerables ocasiones; un ejemplo podra ser querer ob
tener la referencia a un objeto a partir de su nombre:
Sprite nave SpriteManager[,'nave enemiga jefe");

MS INFORMACIN!

Este libro no pretende reemplazar la completsima ayuda que ofrece el sitio MSDN (http://m sdn.

microsoft.com) o la que viene incluida con el entorno de desarrollo integrado Microsoft Visual
Studio .NET. Dicho recurso es ideal para obtener informacin de referencia respecto a clases,
estructuras e interfaces.

1 90

u s r .c o d e

D ic c io n a r io s

O, por ejemplo, acceder a la cantidad de das que posee un mes a partir de su nombre:
int diaaMarto Mes['Harto" ) ;

Un diccionario deber relacionar la informacin de la clave con la de los valores.

Adems, deber hacerlo de un modo eficiente para su consulta. Aunque esto no

es

parte de la definicin formal de lo que es un diccionario, usualmente ser as, ya


que de otro modo sera muy poco prctico.
Un diccionario en C# podr poseer como tipo de valor de la clavecualquier

de dato, a la vez que tambin podr ser de cualquier

tipo
tipo el valor retornado. Es

decir que podremos:


Acceder a un string por medio de un string.
Acceder a un nmero entero por medio de un nmero objeto X.
Acceder a un objeto X por medio de un objeto Y, etc.

El diccionario Hashtable
La librera BCL provee una clase llamada Hashtable, que ofrece un diccionario opti
mizado para encontrar rpidamente un valor a partir de una clave.
La idea general en una tabla de tipo hash es la de acceder directamente aun elemen
to en una tabla sin tener que buscarlo recorriendo sta. Y cmo se logra esto? Por
medio de una funcin hash, que toma la clave como entrada y provee un ndice nu
mrico como salida, que es donde se almacena el valor en la lista.
Una funcin hash trivial podra ser sumar los cdigos ASC II del string por almace
nar en mdulo

(siendo

la cantidad total de elementos de la tabla). Claro que

dos strings distintos podran producir el mismo ndice, lo cual implicara una coli
sin. De todos modos, si la funcin hash se encuentra bien pensada, la cantidad de
colisiones debera mantenerse en un nmero bajo.

UJJ LA INTERFAZ IDICTIONARY


La clase Hashtable posee la interfaz IDictionary que conviene utilizar si deseamos implementar
un diccionario en una clase nuestra. Las propiedades y los mtodos que define son menos de una
decena, y nos permitir integrar mucho mejor nuestra clase a la librera BCL.

u s r .c o d e

191

PROGRAMACIN C#

Cuando se produce una colisin, es decir, cuando dos entradas distintas a la fun
cin de hash producen la misma salida, no se debe devolver ningn error; la cla
se que implemente el algoritmo deber tomar las acciones necesarias para poder
almacenar el valor en la tabla.
Muchas veces, de cada elemento de la tabla se relaciona otra lista que contiene los
elementos en colisin; claro que la bsqueda para estos elementos incurrir en
ms pasos, pero nunca debera ser tan costoso como buscar por la tabla entera.
Cuando la cantidad de colisiones es elevada, podemos estar ante dos escenarios:
1. La funcin de hash es mala para el conjunto de datos entrantes.
2. El tamao de la tabla es muy pequeo.
Respecto a esto ltimo, cabe destacar que el tamao de la tabla de hash no debera ser
un nmero suficientemente bajo para albergar a todos los elementos, sino que se sue
le recomendar que sea el nmero primo mayor al doble de la cantidad de elemento?,
mximos que podra poseer la tabla (s, se desperdiciar espacio en virtud de velocidad
de acceso a los elementos). De todos modos, esta recomendacin se encuentra ntima
mente relacionada con la funcin hash que utilice la implementacin del algoritmo.
192

u s r .c o d e

D ic c io n a r io s

Haciendo uso de la clase Hashtable


La clase Hashtable posee diversos mtodos; implementa las interfaces ICollection,
enumerable y IDictionary. Por eso, algunos mtodos de esta clase ya los conocemos.
Hashtable ht = new Hashtable (31);
ht.Add("Enero", 31);
ht.Add('Febrero", 28);
ht.Add('Marzo", 31);
ht.Add{"Abril", 30);
ht.Add("Junio", 30);
ht.Add('Julio", 31);
ht.Add("Agosto", 31);
ht.Add("Septiembre", 30);
ht.Add("Octubre, 31);
ht.Add("Noviembre", 30);
ht.Add("Diciembre", 31);
Consol.WriteLine("Marzo posee {0} das", ht['Marzo"));
Consol.WriteLine("Septiembre posee {0} das", h t ["Septiembre"));
Consol.WriteLine("Diciembre posee {0} das", ht["Diciembre"));

Analicemos el cdigo anterior:


El constructor se encuentra sobrecargado una decena de veces. En este caso he
mos empleado aquel que recibe el tamao total de la tabla como parmetro.
El mtodo nos permite ingresar en el Hashtable una clave (primer parmetro) y
un valor (segundo parmetro). Cada parmetro puede ser de cualquier tipo, ya
que son el tipo object y todos los tipos de datos descienden de l.
Para obtener el valor a partir de una clave se usa un indexador implementado en
la clase. Colocamos la clave entre corchetes y obtenemos el valor como retorno.

J J

resumI

No existe programa fuera de lo trivial que no haga uso de colecciones de algn tipo. Desde los
clsicos arrays potenciados por la librera BCL hasta la gran variedad de tipos de colecciones
que nos ofrece sta. El problema ahora no es cmo implementar determinado tipo de colec
cin por nosotros mismos, sino qu clase ya implementada elegir ante tantas opciones que
nos ofrece esta plataforma. Un problema muy lindo, por cierto.

u s r .c o d e

193

ACTIVIDADES

TEST DE AUTOEVALUACIN
1 Cul es el ndice del primer elemento de
un array?

EJERCICIOS PRCTICOS
Crear un programa que permita:
a] Ingresar el nombre y el telfono de una
o ms personas (almacenar estos da

2 Qu sucede si intentamos acceder al ele

tos en un objeto de tipo Hashtable).

mento n+1 de un array de n elementos?

bl Consultar el telfono de una persona


por medio del nombre.

3 Por qu motivo un array posee mtodos y


propiedades?

El programa comienza solicitando el nom


bre de la primera persona, luego solicita el
telfono, y as continuamente, hasta que
ingresa como nombre un texto vaco. Lue
go el programa esperar por el nombre de
la persona, tras lo cual escribir en panta
lla su telfono o la palabra "no se encuen
tra en registros" si ste no est en la tabla
(cuando ingresa como nombre de consulta
un texto vaco, el programa debe finalizar!.

4 Puede una clase implementar simultnemanente las interfaces (Enumerable e ICo


llection de modo?

194

u s r .c o d e

PROGRAMACION C#

Captulo

Delegados
y eventos
Los delegados y los eventos son muy
utilizados en la program acin Windows.
El usuario puede interactuar con ellos
generando ocurrencias sobre los

controles de las ventanas, y el modo ms


prctico de m anejarlos es con funciones
especficas que tratan dichas ocurrencias
(eventos). C# ofrece un m ecanism o
sim ple que cum ple con este objetivo y que
nos servir para muchsim os otros fines.

servicio de atencin a l lector: le cto res@ m pe dicio ne s.coin

Delegados

198

Qu es un delegado?
El delegado es una clase
Eventos
Invocar mltiples mtodos

1S9
201
201
204

La clase System.Timers.Timer
Caso de estudio
Resolucin

207
208
209

Resumen

213

Actividades

214

(
(

PROGRAMACIN Cfl

DELEGADOS
En ocasiones es necesario algn mecanismo que le permita al programador especi
ficar una funcin o un mtodo que ser invocado si ocurre un determinado suceso.
Un ejemplo clsico es la implementacin de un tim er. Un timer es una especie de
reloj despertador, slo que, en lugar de especificarle una hora absoluta, le indicamos
una cantidad de tiempo que debe transcurrir para que nos alerte.
Luego, para saber desde una clase que utilice el timer cundo ha transcurrido el tiem
po especificado, qu podramos hacer? Podramos estar consultando constante
mente el objeto timer, preguntando si el contador ya ha llegado al nmero propues
to? Sera muy poco eficiente!, adems de poco preciso. Lo ideal sera que el objeto
timer nos llamara a nosotros. Es decir que invertiramos los papeles por un momen
to: en lugar de ser nosotros quienes invocramos los mtodos de los objetos instanciados, dicho objeto sera quien llamara a algn mtodo de una de nuestras clases.
Pero entonces cmo podra el objeto timer informarnos de la ocurrencia del suce
so: ya-transcurri-el-tiempo-especificado!?
De nada servir coloar el cdigo que necesitemos utilizar dentro de nuestra clase
que implementa el timer, porque de este modo ser muy poco reutilizable. Lo que
aqu necesitamos es una solucin general y elegante.
Histriamente los lenguajes ofrecieron diversas maneras de lidiar con esta situa
cin. En lenguaje C, por ejemplo, es posible especifiar una funcin callback que
ser invoada cuando sea preciso.

callback es, en realidad, una funcin convencional que posee un prototipo especifi
cado (coincide en tipo de dato retornado y en antidad y tipo de parmetros). Lue
go, un puntero a esta funcin es pasado como parmetro a la librera que lo requie
ra. Cuando suceda el evento en cuestin, la funcin

callback ser invocada.

U J l QU ES UN PUNTERO?
Un puntero es una variable que posee como valor una direccin de memoria. Un puntero a una
funcin es una variable que contiene la direccin de memoria donde esta funcin se encuentra
definida. Los punteros son populares en lenguajes como C y C+*. C # permite emplearlos en con
textos no seguros, pero casi no se utilizan. Ya veremos un poco ms en el Capitulo 10.

196

u s r .c o d e

Delegados

puntero a foo()

1
Y
void fooO

librera

{
}

Figura 1. Una funcin callback del lenguaje C.

El lenguaje C++, adems de heredar el mecanismo callback del lenguaje C, permi


te utilizar un mecanismo que ya conocemos. Este ingenio no es ni ms ni menos
que la aplicacin de los mtodos virtuales. Recordemos que los mtodos virtuales
fueron ideados con el fin de separar la declaracin de una interfaz con su implementacin. Bueno, ste es uno de los casos en los cuales es necesario que una funcin
sea declarada en un sitio (por ejemplo, una librera) pero sea implementada en otro
(por ejemplo, nuestro sistema que hace uso de la librera).
El nico problema de los mtodos virtuales es que requieren estar dentro de una
subclase de la clase en la cual se declara el mtodo en cuestin. En muchas ocasio
nes esto es un problema e incide directamente en el diseo de nuestro sistema.
Veamos nuestro ejemplo del timer implementado con mtodos virtuales:
class Timar

t
gpjy

public void StartO

{
// Evitamos lidiar con el conteo del tiempo,
// simplemente invocamos el mtodo Tick
TickO;

}
protected virtual void TickO

W
i

)
)

u s r .c o d e

197

PROGRAMACIN C#

class Clasal s Tintar

{
protectad overrida void Tick O
{
Consola.WriteLinel
Bjecucifa de Tick de Clase 1*) j
static void MainstringU args)

{
Claael obj new C laselO;
obj.Start();

}
}

Podramos suponer que la clase Timer forma parte de alguna librera, y que ni si
quiera podramos acceder a su cdigo fuente ni modificarla en ningn aspecto.
Sin embargo, declara un mtodo virtual que es invocado cada vez que se cumple
el intervalo de tiempo especificado (aunque en nuestro ejemplo no se realice un
conteo, para mantener el cdigo breve y sencillo). Entonces, para poder colgar
cdigo de este mtodo, debemos sobrecargarlo en una subclase de Timer, como ya
hemos hecho en captulos anteriores.
El sistema funciona a la perfeccin; en el momento en que invocamos el mtodo

Start,

ste invoca el mtodo

Tick y, como hemos sobrecargado, se ejecutar la ver

sin de la clase Clase 1 y no la de Timer.


Como hemos mencionado anteriormente, este mtodo suele emplearse en lengua
jes orientados a objetos como C++, e incluso en C#. Pero este ltimo va un paso
ms all; por qu no unir la idea general de las funciones callback con la practicidad de los mtodos virtuales? Sera bueno poder especificar el mtodo que ser in
vocado en cualquier clase de nuestro sistema (sin que sta deba ser descendiente de
ninguna clase en particular), e implementar all el cdigo requerido. Dicho de otro

lU

FUNCIONES CALLBACK EN C++ Y C#

El lenguaje C++, como sucesor del lenguaje C -que de algn modo lo es-, permite utilizar el me
canismo de funciones callback. En C#, en cambio, esto es imposible, pues aqu toda funcin de
be estar definida dentro de una clase, algo que no exige C++ (lenguaje que muchas veces es cri
ticado por esta caracterstica y es tildado de hbrido).

198

u s r .c o d e

Delegados

modo, queremos hacer algo parecido al ejemplo que acabamos de analizar, pero sin
que Clasel deba ser subclase de Timer. Y aqu entran en accin los delegados.

Qu es un delegado?
Los delegados son clases especiales, y sus objetos son bsicamente contenedores de
referencias a mtodos de otros objetos.
De esta manera, pueden ser utilizados para almacenar una referencia al mtodo que
deseamos invocar, como si fuese una funcin callback convencional pero con una
flexibilidad mucho mayor, ya que el mtodo puede encontrarse en cualquier clase;
y podramos indicar que cuando ocurra el suceso no se invoque un solo mtodo, si
no todos los que deseemos (multicast).

____________________

Figura 2 . Diagrama de sintaxis para la declaracin de un delegado.

usr.code

199

PROGRAMACIN C#

Ahora veamos un ejemplo sencillo en el cual utilizamos un delegado:

j public delegate void TickHandler();

claes Claael

{
public Claael ()

{
TickHandler obj = (TickHandler)
Delegate.CreateDelegate(typeo(TickHandler),
thia, "EsteEsElMetodoTick*);
objO; // Aqu se invcca el mtodo EateEsBlLaetodoTickO

}
public void EateEeElMetodoTickO

Consol.WriteLine("Ejecucin de EsteEsElMetodoTick de Claael);

}
static void Main(stringU arga)

{
Clasel obj new ClaselO;

I .

Como se puede apreciar en el listado anterior, primero declaramos el delegado. Lue


go, creamos un objeto del tipo del delegado que hemos declarado (el delegado es,
al fin y alcabo, una clase) por medio de un mtodo esttico de la clase Delegate. La
versin del mtodoqueutilizamos recibir

tres parmetros:

1. El tipo de la clase Delegate que hemos declarado.


2. El objeto en el cual reside el mtodo para invocar.
3. El nombre, en string, del mtodo para invocar (del cual luego se obtendr la re
ferencia que corresponda).

DELEGADOS POPULARES

El mecanismo de delegados y eventos es realmente til. Es muy utilizado por la librera BUL pa
ra diversos fines. Uno de ellos, tal vez el ms popular, es el de los eventos de los controles de tos
formularios, que comenzaremos a analizar en los siguientes captulos.

200

u s r.c o d e

Eventos

Una vez creado el delegado, podremos utilizarlo con la finalidad de invocar el m


todo que le hemos especificado.
Para esto simplemente debemos indicar el nombre de su instancia y su lista de pa
rmetros entre parntesis (en nuestro caso la lista es vaca, debido a que nuestro m
todo no posee ningn parmetro).
La forma de invocacin del mtodo contenido en el delegado que hemos utilizado
puede parecer un poco extraa a nuestra vista: el lenguaje entiende, aqu, que debe
invocar el mtodo contenido en el delegado.

El delegado es una clase


Como ya hemos mencionado, el delegado es una clase especial. Cuando declaramos
un delegado, en realidad estamos declarando una clase descendiente de System.
MulticastDelegate, slo que lo hacemos con una sintaxis distinta. Lo que har C# se
r convertir esta declaracin en lo siguiente:
<modificadores> class <identificador> : System.MulticastDelegate

;
// Declaracin de algunas variables especficas
//

...

// Declaracin de algunos mtodos especficos

// ...
public <identiicador>(object o, int punteroAMtodo) {}
public virtual <tipo de dato> Invoke(dista de parmetroa>) {}

[ }

Pero nosotros no debemos complicarnos la vida con esta sintaxis. De hecho, la clase
declara algunas variables y mtodos mis que ni siquiera es menester mencionar aqu.
Simplemente es bueno tener en cuenta qu es lo que el lenguaje entiende realmen
te y cul es la naturaleza de este tipo de objeto nuevo que estamos utilizando.

EVENTOS
Un evento es un tipo especial de propiedad y est muy relacionado con los delegados,
ya que se utiliza para controlar el modo en que nuestro sistema hace uso de ellos.
u s r .c o d e

201

PROGRAMACION C#

Figura 3, Diagrama de declaracin de un evento.

Ahora volvamos a la implementacin de nuestro timer. Haciendo uso de delegados


y eventos, obtendremos una solucin ideal a nuestras necesidades:
public delegate void TidcHandler();
public clase Timar

{
public void StartO

{
// Invoco el evento Tiek
if (Tick I* nuil)

rieleo t
}
public event Tickllandler Ticfc - nuil;

}
clase Clasel

{
Timer a_timer;
public Clasel()

{
// Creo el objeto timer
m timer a new Timer ();

202

u s r .c o d e

E v e n to s

// Establezco el delegado
'ntiaer.Tick +' new TickHandlertthis.EsteEsElMtodoTick)
// Inicio el timar
m_tiaer.Start()

}
public void EsteEsElMetodoTicM)

{
Consol.Kritebine(*Ejecucin de EeteKsElMetodoTick da Clasel");

}
static void Main(string[] args)

{
Clasel obj = new Clasel 0;

}
}

Analicemos el cdigo anterior:


1. Declaramos un delegado, indicando que ste deber almacenar la referencia a un
mtodo sin parmetros.
2. Nuestra clase Timer poseer un evento inicializado en nuil que gestionar el ac
ceso al delegado TickHandler.
3. La clase Clasel crea un objeto del tipo Timer.
4. Hacemos uso del evento para relacionar el delegado con el mtodo del objeto
que deseamos invocar. Note que para esto utilizamos el operador +=. Podramos
seguir agregando mtodos para ser invocados por el delegado mediante este ope
rador, y podramos indicar lo contrario por medio del operador
5. Finalmente, cuando invocamos el mtodo Start, ste hace uso del evento para in
vocar el mtodo contenido en el delegado.
Entonces hemos solucionado el problema que tenamos. Logramos indicarle a un
objeto de nuestro sistema que cuando se produzca un determinado suceso invoque

3 INTERRUPCIN DE LA EJECUCIN EN CADENA


Es posible que se interrumpa la invocacin en cadena de los mtodos que un delegado tiene referenciados si ocurre una excepcin en alguno de ellos y sta es arrojada hacia el mtodo superior.

u s r .c o d e

203

PROGRAMACIN Cft

a un mtodo arbitrario definido por nosotros y situado en una de nuestras clases,


sin que sta deba poseer una relacin especfica de herencia con ninguna otra.
Cuando se presiona un botn en uno de nuestros formularios, podremos indicarle
al framework que invoque el mtodo que queramos para su tratamiento. De hecho,
podremos tener una clase que represente el formulario y especificar en ella los m
todos que deben ser invocados para todos los botones -y dems controles- que po
sea el formulario. Qu poco prctico sera aqu tener que crear una subclase espe
cfica por cada botn para tratar alguno de sus eventos!

Figura 4. Uso de eventos y delegados en GUiS.

Invocar mltiples mtodos


Ya dijimos que los delegados pueden no slo invocar un mtodo, sino todos los que
queramos. Delegados del tipo MulticastDelegate almacenan listas enlazadas de refe
rencias a mtodos, por lo que podemos solicitar la invocacin de todos los mtodos
albergados en cadena, uno detrs de otro (pero sin suponer un orden particular).

QU ES UNA EXCEPCIN?

Una excepcin es un recurso del lenguaje que permite alterar el flujo de ejecucin normal de un
programa. Usualmente son utilizadas para tratar los errores que se pueden producir en tiempo
de ejecucin en nuestras aplicaciones. Ms adelante veremos cmo hacer uso de ellas. Apren
deremos ms acerca de excepciones en el Captulo 9.

204

u s r .c o d e

E v e n to s

Mtodo 1

Mtodo 2

Figura 5. Ejecucin de mtodos en cadena.

unDelegado

void Hetodo2

{
throw new Bxception

(*...*),

Figura 6. El mtodo Metodo3 nunca ser invocado.

u s r .c o d e

205

PROGRAMACIN CU

Veamos cmo hacer esto basndonos en un ejemplo trivial:


class Claael

{
Timer m_timer;
public ClaselO

{
// Creo el objeto timer
m_timer = new Timar 0;
// Establezco el delegado
m_tiraer.Tick += new TickHandler(this.EsteEsElMetodoTickl);
m_timer.Tick += new TickHandler(this.EsteEsElMetodoTick2);
m_timer.Tick += new TickHandler(this.EsteEsElMetodoTickl);
// Inicio el timer
mtimer.Start();

}
public void EsteEsElMetodoTicklO
Consol.WriteLinel"Ejecucin de EsteEsElMetodoTickl
de Clasel");
public void KsteEsElMetodoTick2()

{
Console.WriteLine("Ejecucin de EsteEsElMetodoTick2
de Clasel");
public void EsteEsElHetodoTick3()
Console.WriteLine("Ejecucin de EsteEsElMetodoTickl
de Clasel");

}
static void Main{string[] args)

{
Clasel obj = new ClaselO;

Es totalmente obvio que esto resultara muchsimo ms prctico si los mtodos por
invocar fuesen de distintas clases.

206

u s r .c o d e

La clase System.Timers.Timer

LA CLASE SYSTEM.TIMERS.TIMER
La librera B C L nos ofrece una clase Timer que es ideal para utilizar en nuestras apli
caciones cuando stas deben realizar una determinada tarea cada cierto perodo de
tiempo. Esta clase hace uso de delegados y eventos (como no poda ser de otro mo
do). Veremos aqu cmo podemos utilizarla:
using System;
using System.Tiera;
namespace acDeTimar

{
clase Clasel

{
Timer

timer = new Timer();

Clasel()

{
// Indico que el intervalo sea de 1000 ms
_timer.Interval 1000;

// Especifico el mtodo que ser invocado por el delegado


_timer.Blapsed += new BlapsedEventHandler (this.Tick) ;

//Le doy comienzo al timer

timer. S t a r t O ;
public void Tick(object sender, ElapsedBventArge e)

{
// Envo a pantalla un mensajecada vez que se
// invoca el mtodo Tick
Console.WriteLine(*Tick') ;

}
static void Main(string(] args)

{
// Creo un objeto del tipo Clasel
Clasel c = new Clasel();

// Solicito el ingreso de unstring, para que

el

// programa no termine
string str = Consol.ReadLineO;

u s r .c o d e

207

PROGRAMACIN C#

Como se aprecia en el listado anterior, no existen grandes diferencias respecto al c


digo que venamos escribiendo. Tal vez deberamos notar que el mtodo para invo
car posee dos argumentos: el primero es el objeto que utiliza, el evento para invocar
nuestro mtodo (es decir, el objeto Jim er), y el segundo posee informacin relacio
nada con el evento que se produce, en este caso, el transcurso de cierto tiempo.
Para conocer cul ser el prototipo del mtodo (tipo de dato retornado y parme
tros) que debemos definir, debemos consultar la informacin de referencia oficial
que acompaa al framework .NET SDK.

CASO DE ESTUDIO
Construir un pequeo programa que conste de tres clases (Clasel,

Clase2 y Clase3).

Un objeto de Clase3 deber contener un objeto de Clase2, el cual deber contener


un objeto de Clasel.

Figura

7. Relacin de contencin entre objetos de la clase.

Declarar, adems, un delegado que permita almacenar referencias a mtodos con un


parmetro entero.

Clasel

Clase2

deben poseer un evento relacionado con el delegado declarado.

Adems, deben contener un mtodo llamado

Start

que cuando sea invocado en

Clasel

dispare su evento, lo cual producir la invocacin de un mtodo de Clase2,


que dispara su propio evento, y esto producir finalmente la invocacin de dos
eventos distintos de la clase Clase3.

r DELEGADOS EN JAVA
Java no soporta delegados. Para realizar mplementaciones similares a las vistas, suelen utili
zarse interfaces de

208

un solo mtodo que la clase en cuestin debe sobrecargar.

u s r .c o d e

Caso de estudio

El siguiente diagrama de secuencia clarifica lo mencionado:

Figura 8. El diagrama de secuencia del ejercicio.

Resolucin

Declarar, adems, un delegado


que permita almacenar referencias a mtodos con un parmetro entero, sim

Con relacin al enunciado escrito anteriormente:


plemente debemos ingresar como cdigo:

Q Q EVENTOS DE CLASES EN LA DOCUMENTACIN OFICIAL


En la documentacin oficial de referencia que incluye Visual Studio ,NET (a la cual se puede acce
der en forma libre desde Internet), se identifican fcilmente los eventos que implementan las cla
ses (as como los mtodos y las propiedades), debido a que estn perfectamente categorizados.

u s r .c o d e

209

PROGRAMACIN C#

public delgate void MiDelegado(int num);

Prestar especial atencin a que ahora nuestro delegado posee un parmetro entero
que nos solicita el enunciado.
Definir las tres clases con sus propios mtodos y eventos es muy sencillo:
public class Clasel

{
public void Startdnt num)

{
}
public event MiDelegado Evento n nuil;

}
class Clase2

{
Clasel objClasel;
public event MiDelegado Evento = nuil;
public Clase2()

{
public void MI(int num)

{
public void Startdnt num)

{
}
}
class Clase3

U H QU SUCEDE SI INVOCAMOS UN EVENTO NULO?


Inicialmente, los eventos poseen asociado el valor nulo. Si aun asi lo utilizamos para invocar los
delegados asociados, se producir una excepcin del tipo System.NullReferenceException.

210

u s r.c o d e

Caso de estudio

Clase2 objCla8e2;
public Clase3()

public void MI(int num)

}
public void M2{int num)

}
public void Start(int num)

Ahora deberemos relacionar la invocacin de mtodos y eventos, segn solicita el


enunciado. Completando entonces el programa:
using System;
namespace DelegadosYEventosEjerciciol

{
public delegate void MiDelegado(int num);
public class Clasel

{
public void Start(int num)

{
// Invoco el evento
i (Evento != nuil)
Evento(num);

}
public event MiDelegado Evento = nuil;

}
class Clase2

{
Clasel objClasel;
public event MiDelegado Evento = nuil;
public Clase2{)

{
// Creo el objeto

u s r .c o d e

211

PROGRAMACIN C#

objClasei a new ClaselO;

// Establezco el delegado
objClasei.Bvento += new MiDelegado(thiB.Hl);

}
public void MI (int num)

{
Console.WriteLine('Ejecucin de MI de Clase2.
Nmero = {o}", num);

,// Invoco el evento


if (Evento 1= nuil)
Evento(num);

}
public void Start(int num)

{
objClasei.Start(nua);

}
}
class Clase3

{
Clase2 objClase2;
public ClaselO

{
// Cree el objeto
objClaae2 * new Clase2();

// Establezco el delegado
objClase2.Evento +o new MiDelegado(this.Ml);
objClase2.Evento += new MiDelegado(this.M2);

}
public void MI(int num)

{
Console.WriteLine('Ejecucin de MI de Clase3.
Nmero

{0}", num);

}
public void M2(int num)

{
Console.WriteLine("Ejecucin de M2 de Clase3.
Nmero = {O}*, num);

}
public void Start(int num)

212

u s r .c o d e

Caso de estudio

{
objClaae2.Start(nua);

}
static void MainfstringU args)

{
Clase3 obj = new Clase3();

// Invoco Start con un nmero cualquiera


obj.Start(5);

}
}

RESUMEN

Finalmente hemos visto los conceptos ms importantes del lenguaje que nos permitirn su
mergirnos de lleno en la programacin de aplicaciones de ventana.
En el prximo capitulo veremos cmo, por medio de la librera BCL, podremos crear aplicacio
nes con botones, cuadros de texto, listas y muchsimos controles ms. Aprenderemos, entonces,
que los delegados y los eventos forman parte de los recursos ms populares que utilizaremos
para colgar cdigo de los sucesos que pueden producirse en los controles y en el formulario.

u s r .c o d e

213

ACTIVIDADES

TEST DE AUTOEVALUACIN
1 Qu es realmente un delegado?

U Qu ventajas conlleva utilizar delegados


y eventos respecto a mtodos virtuales?

2 Para qu se utilizan usualmente los dele


gados y los eventos?

3 Qu diferencia sustancial existe entre in


vocar un mtodo e invocar un mtodo me
diante un evento?

5 En qu namespaces de la librera BCL son


ms populares los delegados y eventos?

214

u i.c o d e

PROGRAMACION CS

Aplicaciones
con Windows.Forms
Ha [legado el m om ento de introducirnos
en la creacin de aplicaciones con
ventanas y controles. Por eso, en este
captulo darem os los pasos bsicos para
crear una aplicacin con interfaz de
usuario. Presentarem os los controles
bsicos de la librera y verem os cules
son sus m todos y propiedades bsicas.

Arquitectura de una aplicacin


Windows
216
La clase Application
221
Controles
222
Formularios
Crear una aplicacin sencilla
Convencin de nombramiento
para controles
Manipulacin de los controles
bsicos
Caso de estudio i

servicio de atencin al iector: le cto res@ m pe dicio ne s.com

Caso de estudio 2
Caso de estudio 3
Caso de estudio 4
Caso de estudio 5
Resumen
Actividades

227
229
232
234
234
239
241
246
250
253
254

PROGRAMACIN C#

ARQUITECTURA DE UNA APLICACIN WINDOWS


Toda aplicacin para Windows que requiera interaccin con el usuario y que se pre
cie de tal cuenta con una interfaz grfica (G U I). En el pasado han quedado aque
llos sistemas en los cuales solamente podamos utilizar, por medio de la lnea de co
mandos, clsicos del viejo y vetusto DOS.
C# permite crear aplicaciones de consola y con interfaz de usuario. Desde el co
mienzo del libro hasta aqu slo hemos tratado el primer tipo de aplicaciones. Fi
nalmente, ha llegado el momento de adentrarnos en la construccin de aplicacio
nes ms bonitas y, desde varios puntos de vista, ms interesantes.
Veamos, paso a paso, cmo crear una sencilla aplicacin con interfaz de usuario uti
lizando Visual Studio .NET 2003.

Crear una aplicacin con interfaz de usuario

PASO A PASO

D En primer lugar deberemos comenzar, como siempre, accediendo a la opcin de


nuevo proyecto

(New Project).

New Project

Project Types:
^
ffl
O

i j c l l

Iem plates:

Visual C # Projects
Visual C + + Frojects
Setup and Deploym ent Projects

Ciass Librar;/

!+': _ J Other Projects

Windows
Control Library _ J

{ _ ] Visual Studio Solutions

I Smart D evice ASP, NET W eb Com ponent.,.


Application
Application
D ata U brary
A project fo t creating an a p p k a tic n w ith a W indows user interface
ame:

G U lA ppl

Locat.cn:

I E:\users\diego\libro CS(code-cap7

y"|

g row se...

Project will b e created a t E:\users\diego\libro C S \co d e -c a p 7 \ IA p p I,

T M o rj.

OK

Help

Especificaremos ubicacin y nombre del proyecto, pero en esta oportunidad no

Consol Application, sino


tion, y luego presionaremos el botn Ok.
seleccionaremos

216

Cancel

que elegiremos

Windows Applica

u s r .c o d e

Arquitectura de una aplicacin Windows

%'GUIAppl MLfMoflVrtMlC'.N!T{4eiinj fom1 x t (Dttifcn]

f>

ten Y&**X PfOT.J Cut


*I

B O

tyM F^nnot I k
f ;

>w

W nk*
- [# .'ui

%%.
?. X

Fwlxt Itta^n] ]

2B 3

oJutntflwr(t *-i

f. 0 UJIAppl

' CWJC

?X

Z{

"5a.. 5>..PB>-. gaoxfe ' :--

D Si todo ha ido bien, deberamos ver en nuestra pantalla algo similar a lo que ex
presa la figura anterior.

Ahora bien, en la pestaa Solution Explorer encontraremos tocios los archivos que
pertenecen al proyecto o estn relacionados con l; algunos nos resultan conocidos
y otros no. Veamos:
Carpeta References: dentro de esta carpeta se listarn los distintos assemblies que
utiliza nuestro proyecto. Recordemos que un assembly es un componente de soft
ware que en su interior posee cdigo ejecutable v/o recursos (los assemblies, que
estarn relacionados con nuestros proyectos, se encontrarn generalmente en archi
vos de tipo dll). Por el momento, entre ellos podremos encontrar:

System
System.Data
System.Drawing

System.Windows.Forms
System.XML

App.ico: el icono que representa nuestra aplicacin. Puede ser modificado median
te el editor integrado que posee Visual Studio (aunque es recomendable trabajar
con editores externos si es que se desea construir iconos con ms de 16 colores).
u s r .c o d e

217

PROGRAMACIN Ctt

* AssemblyInfo.es:

archivo con cdigo fuente C#, posee atributos del assembly de

nuestra aplicacin.

Forml.cs: archivo con cdigo fuente C#. Posee una clase que desciende de System.
Windows.Forms.Fonn y cdigo generado por el asistente de Visual Studio.
La clase Forml representa un formulario en nuestra aplicacin. Los formularios son
contenedores de controles (botones, cuadros de texto, etc.). Estos sern tiles para
construir una interfaz que le permita al usuario interactuar con nuestra aplicacin!
Existen muchos tipos de controles, el framework 1.1 incluye ms de 50 y existe en
la Red una oferta de muchsimos otros para todos los gustos (algunos gratuitos y
otros comerciales), que podremos incorporar a nuestras aplicaciones.
Entre los mtodos que el asistente escribe en nuestra clase Formulario se encuentra
uno llamado InitializeComponent. A primera vista, este mtodo no estar visible an
te nuestros ojos, pues se encuentra dentro de un bloque regin llamado Windows
Form Designer generated code . Si expandimos este bloque, encontraremos el
mtodo buscado dentro de l.

#region NOMBRE

bloque ocultable

#endregon
Figura 1. Bloque expandido.

n o m bre

Figura 2. Bloque colapsado.

Dentro del mtodo InitializeComponent, el diseador de Visual Studio .NET colo


car las propiedades de los controles a las cuales les hayamos especificado valores
distintos de los predeterminacos.

QU ES UN ATRIBUTO?

Un atributo brinda informacin acerca de los datos que describen nuestra aplicacin. En el Ca
pitulo 10 hablaremos ms acerca de ellos: veremos cules son los atributos predefinidos y cmo
declarar los nuestros propios.

218

u s r .c o d e

Arquitectura de una aplicacin Windows

Si compilamos y ejecutamos la aplicacin, presionando la tecla F5 o accediendo al


men Debug, opcin Start, veremos en pantalla la siguiente ventana:

Figura 3. La aplicacin en modo de ejecucin.

Es importante notar que, a diferencia de las aplicaciones de tipo consola que antes
creamos, ahora la aplicacin no termina inmediatamente. Es decir que no existen
-visiblemente- ciertas lneas de cdigo que deben ser ejecutadas secuencialmente,
tas lo cual el programa se da por finalizado.
Ahora, el programa se ejecuta hasta que cerremos la ventana principal o lo exprese
mos explcitamente mediante cdigo.
De hecho, es interesante analizar el cdigo de nuestro mtodo esttico Main:
Application.Run(new FormlO);

El mtodo esttico Run de la clase Application ejecutar un bucle de mensajes para


nuestra aplicacin. Pero qu es un bucle de mensajes? En Windows los procesos se
comunican con el sistema mediante mensajes. Estos mensajes poseen un cdigo y,
en ocasiones, informacin relacionada. Cada aplicacin posee una cola de mensajes
en la cual Windows deposita los mensajes que corresponden a la aplicacin.

QU ES UN BLOQUE REGION?
Los bloques regin nos permiten mejorar la legibilidad del codigo de nuestro programa. Estn
compuestos por un par de directivas dentro de las cuales todo el cdigo escrito podr ser expan
dido o eolapsade. De este modo, si el listado total de una hoja de coigo fuente es muy extenso,
con este tipo de bloques podremos reducir su longitud visible, agrupando mtodos afines.

u s r .c o d e

219

PROGRAMACIN C#

220

u s r .c o d e

A r q u ite c tu r a d e u n a a p lic a c i n W in d o w s

Por ejemplo, si el usuario presiona un botn del mouse, entonces Windows genera
r un mensaje del tipo WM_LBUTT0ND0WN) que usualmente ingresar en la cola de
mensajes de la aplicacin que posea el foco en ese momento (la aplicacin activa).
Cada aplicacin se encuentra en un bucle, esperando a que ingrese algn mensaje. Ca
da vez que un mensaje ingresa, la aplicacin lo despacha con el manejador que corres
ponda. Volviendo al ejemplo del botn del mouse, nuestro programa podra poseer
una funcin que realice una determinada tarea cuando el botn izquierdo del mouse
es presionado; si no es as, el mensaje ser tratado por un manejador predeterminado.
En C#, todo este mecanismo de bucle de mensajes queda un tanto oculto (no sera
as si programramos en lenguaje C). El sistema de despacho de mensajes ser implementado por el framework, y nosotros nos limitaremos a especificar mtodos
que respondan a eventos de un modo similar al que vimos en el captulo anterior,
cuando no sea el mismo Visual Studio quien escriba dicho cdigo por nosotros.

La clase Application
Application es una clase que representa a nuestra aplicacin. Posee una serie de m
todos y propiedades estticos que nos brindar una gran cantidad de informacin
respecto a ella. Las propiedades ms importantes son:

CompanyName: nos devuelve informacin del atributo AssemblyCompany que espe


cificamos para nuestro assembly (por predefinicin, en el archivo Assemblylnfo).
ProductName: nos devuelve informacin del atributo AssemblyProduct que especi
ficamos para nuestro assembly.
ProductVersion: nos devuelve informacin del atributo AssemblyVersion que espe
cificamos para nuestro assembly.
ExecutablePath: ruta de ejecucin de la aplicacin.
StartupPath: ruta de arranque de la aplicacin.
Y los mtodos estticos ms importantes son:

DoEvents: a los programadores de Visual Basic les resultar conocido este mto
do. Aunque en aquel lenguaje se encontrase como una funcin global, aqu su
propsito es el mismo: atender otros mensajes mientras nuestra aplicacin se en
cuentra trabajando en algn proceso que demande cierto tiempo. Por ejemplo, si
nuestra aplicacin se encuentra dentro de un bucle extenso, es normal que un
programador coloque dentro de l un DoEvents. De este modo, nuestra aplicacin
seguir atendiendo los mensajes en cola y evitaremos que, por ejemplo, el formu
lario quede sin repintarse.

Exit: finaliza la aplicacin.


Run: comienza una aplicacin ejecutando un bucle de mensajes.
u s r .c o d e

221

PROGRAMACIN CU

CONTROLES
Para modificar las propiedades de cualquier elemento bastar con seleccionarlo, pre
sionar el botn derecho del mouse sobre l y acceder a la opcin del men contextual llamada Properties. Hecho esto, aparecer la pgina de propiedades del control
en la cual podremos observar y modificar sus propiedades, y tambin podremos
agregar mtodos que manejen sus eventos.
Adems, toda modificacin de propiedades se puede realizar mediante cdigo. Lo
que sucede es que, aqu, Visual Studio genera dicho cdigo por nosotros, pero que
no estemos utilizando este entorno no significa que estemos imposibilitados de tra
bajar con controles ni mucho menos.
Properties
P Form i

jd

S ystem . W indow s.F orm s.F orm

im n ?
AccessibleNam e
AccessibleP.ole

A
D efau lt

El .

BackColor

| C ontrol

B aclg ro u n d lm ag e

1 (n o n e )

Cursor

D efault

Fo n t

M icrosoft Sans S e r f, ,2 5 p t

r o re C o b r

IB

Form B orderS tyle

Sizable

R ig h tT o le ft

No

Te*
0

C uritrulT ext

im ilicauJikuuj^

Allow Drop

False

C o n te x tM e n u

(n o n e )

Enabled

True

IrneM ode

NoC ontrol

0
0

(D ynam icP roperties)

0
0

(D ataB indings)
Tac

0
(Namc-l

F o rm !

Oraw Crid

True

0 GridStee_
................

S.

Figura 5. La p g in a de prop ie d a d e s .

Es imprtame notar que ios controles son ciases, y cuando seleccionamos un con
trol dei toolbox y iu insertamos en nuestro formulario, estamos creando una instan
cia de dicha ciase (un objeto) que Visual Studio automticamente agrega a nuestro
formulario con ei nombre que indique la 'propiedad' (ame).
222

t u r .c o d e

Controles

Existen controles que poseen representacin grfica (la mayora) y otros que no (co
mo Timer,

ImageList,

etc.):

Los componentes sin representacin grfica ofrecen sus funcionalidades al


programador, pero son invisibles en tiempo de ejecucin (significa que no di
bujan sobre el formulario).
Este tipo de controles desciende de la clase System.ComponentMode.Component.
Por otro lado, los controles con representacin grfica ocupan un espacio en nues
tro formulario, y en tiempo de ejecucin dibujan sobre su espacio algn contenido.

Este tipo de controles desciende de la clase System.Windows.Forms.Control (que a


su vez desciende de System.ComponentMode.Component).
En la siguiente tabla, podemos ver los controles ms importantes que provee el ffamework .NET en su versin 1.1:

Label

Representa una etiqueta sencilla, un trozo de texto no seleccionable ni editable por el usuario.

linkLabe

Representa una etiqueta con un enlace dentro de eHa. Cuando posamos el puntero del meuse sobre sta
y hacemos un clic, automticamente se abre el navegador predeterminado del sistema apuntando al sitio
que especifica ei control.

Button
; TextBox

Representa el clsico botn. Puede contener un texto y/o una imagen relacionada con l.
Representa un cuadro de texto editable y selecdonate (si sus propiedades as lo determinan).
Es el modo tradicional de ingresar datos por un formulario.

MainMenu

Representa el men de una ventana que es relacionado con la propiedad Men de un formulario. En tiempo
de diseo se permite modificar las opciones y propiedades de los elementos que lo componen.

CheckBox

Representa un cuadro de verificacin, fe utilizado para campos que pueden tomar dos valores (verdadero/
falso, si/no. encendido/apagado, etc.), aunque tambin se permite un tercer estado que es indeterminado.

RadioButoon

Representa un botn de opcin que puede tomar el valor de marcado o no marcado. Usualmente se combinan
varios botones de este tipo, donde su valor de verdad es mutuamente excluyente con el resto del conjunto.

GroupBox

Representa una agrupacin de controles, enmarcados y con una etiqueta. & ideal para agrupar opciones afines
dentro de un ormulano complejo.

PictureBox

Representa un cuadro que puede poseer una imagen en su interior.

Panel

Representa un contenedor de controles. Es prctico en muchos cases, como cuando se desea controlar la
propiedad de visibilidad de muchos controles afines de modo simple

DataGrid

Representa una grilla relacionada con un conjunto de datos. Facilita muchsimo la interaccin con bases
de datos.

ListBox

Representa un cuadro de lista sencillo que siempre est desplegado.

CheckedstBox Representa un cuadro de lista sencillo donde los elementos poseen asociados cuadros de verificacin.
Combo8oj

u s r .c o d e

Representa un control combinado de cuadro de texto y cu3dro de lista.

223

PROGRAMACIN Ctf

1 CONTROL
ListView

DESCRIPCIN '
Representa una lista de visualizacin. Este control es muy flexible y permite diversas vistas. Es utilizado por
muchas aplicaciones, como el explorador de archivos (cuadro derecho donde se muestran los contenidos
de las carpetas).

TreeView

Representa un rbol de vistas. Este control se complementa muy bien con el lisVie. Muchas aplicaciones
hacen uso de l. como el mismo Visual Studio y el explorador de archivos.

TabControl

Representa un control de pestaas que es muy til para organizar grandes cantidades de opciones dentro
de una ventana pequea.

DateTimePicker

Representa un control en el cual se ofrece un calendario para seleccionar una fecha en l cuanto
es desplegado.

MonthCalendar

Representa un control en el cual se ofrece un calendario para seleccionar una fecha en l. Es similar
a DatePicker, excepto que aqu el calendario siempre se encuentra desplegado.

HScroliSar

Representa una barra de desplazamiento horizontal.

VScrollBar

Representa una barra de desplazamiento vertical.

Timer

Representa un timer.

Splitter

Representa un divisor. Es muy til para otorgar al usuario la posibilidad de ajustar el tamao de ciertos
controles de modo automtico (como lo que ocupa un TreeView asociado a ListView).

OomainUpOown

Representa una lista de strings que puede ser modificada secuenciamente mediante botones

NumericUpDown

Representa una lista de nmeros que puede ser modificada secuenciamente mediante botones.

TiackBar

Representa una barra de desplazamiento.

ProgressBar

Representa una baa de progreso.

RichTextBox

Representa un cuadro de texto con formato de texto enriquecido. De este modo es posible cambiar el color
y la fuente de una parte del texto que se encuentra en su interior (a diferencia de) cuadro de texto normal,
donde las propiedades de tipografa y cok eran generales para lodo el control).

ImageUs

Representa una lista de imgenes. Este control se utiliza asociado a otros que requieren imgenes
(por ejemplo,TreeView, ListView, etc.). Es posible compartido entre varios controles.

ToolTip
ContextMenu

Representa una pequea etiqueta flotante que brinda una ayuda sobre algn control del formulario.
Representa un men contexta! que puede ser abierto cuando el usuario realiza determinada accin
con nuestra aplicacin (por ejemplo, presiona el botn derecho sobre algn elemento).

Toolbar

Representa una barra de herramientas (generalmente colocada debajo del men de la aplicacin).

StatusBar

Representa una barra de estado (generalmente situada al pie del formulario).

Notifylcon

Representa un icono que aparece en el tray (iconos que se encuentran a la derecha del reloj en la barra
de tareas de Windows). Es posible asociarle un ContextMenu.

OpenFileDialog

Representa un dilogo para abrir archivos.

SaveFiieOialog

Representa un dilogo pare grabar archivos.

FolderBrowser

Representa un dilogo pare navegar por carpetas.

FontOialo

Representa un dialogo pare seleccionar tipografas.

ColorDiaiog

Representa un dilogo para seleccionar colores.

PrintDialog

Representa un dilogo de impresin.


Tabla 1. Controles que provee framework .NET 1.1.

224

u s r.c o d e

Controles

En la Gua Visual 1 vemos los principales elementos que componen una ventana de
Windows

y cmo estn identificados de acuerdo con el framework .NET.

Ventanas de Windows '

O Men.

O ListView.

O Toolbar.

StatusBar.

O ComboBox

TreeView.

6U(A VISUAL 1

DOCUMENTACIN OFICIAL
Recordemos que la documentacin electrnica que provee Visual Studio .NET es ideal para uti
lizar como referencia cuando deseamos conocer las propiedades, mtodos o eventos que posee
un control. Tambin podemos acceder a esta ayuda en linea mediante un navegador en el sitio:

http://m sdn.m icrosoft.com /library.

u s r .c o d e

225

PROGRAMACIN CU

Veamos, ahora, cules son las propiedades comunes y ms populares de los contro
les que poseen representacin grfica:
PROPIEDAD

DESCRIPCIN

BackCotor

Color de fondo del control.

Enabled

Habilita o deshabilita el control (cuando un control se encuentra deshabilitado no es posible interactuar con l).

SE

f $ f y

ForeColor

<fente, tsmaitorcok,ate.).

Color principal utilizado por el control.

a
Left

Posicin izquierdadel control eo relacinconel padre (formulariouotrocontrol dondeest contenido).

Height

Alto en pixeles.

Jert

Textoasociadoal control.

TextAlign

Alineacin del texto asociado al control.

Top

Posicin superior del control en relacinconti padre(formulario uotrocontrol dondeest contenido).

Visible

Muestra u oculta ei control.

Wldth

Anchoen pixeles.
Tabla 2. Propiedades de controles con representacin grfica.

Figura 6. Alto, ancho y posicin del control.

PROPIEDADES. MTODOS Y EVENTOS

Aqu estamos citando las propiedades, mtodos y eventos que consideramos ms importantes
(los que van a utilizarse con mayor frecuencia). Existen muchos otros que pueden consultarse en
la documentacin de referencia oficial que acompaa al framework SDK o a Visual Studio .NET,
o inctuso en el sitio MSDN.

226

u s r .c o d e

Formularios

Y los mtodos ms importantes son:

Focus

Transfiere el foco al control (la entrada por teclado es dirigida al control que posea el foco).

Hide

Oculta el control (mismo efecto que fijar la propiedad Vstele en false).

Show_ _ _ _ _ _ _ Muestra el control (mismo efecto que fijar la propiedad Visible en true)._ _ _ _ _ _ _ _ _ _ _ _ _
Tabla 3. Mtodos de controles con representacin grfica.

Y, finalmente, los eventos:

Click

Se produce cuando el usuario presiona el botn izquierdo del mouse.

Doubleclick

Se produce cuando el usuario realiza doble che con el mouse.

GetFocus

Se produce cuando el control gana foco.

KeyDown

Se produce en el momento en que la teda es presionada.

KeyPress

Se produce cuando se presiona una tecla sobre el control.

KeyUp

Se produce en el momento en que la tecla es liberada.

LostFocus

Se produce cuando el control pierde el foco.

MouseOown

Se produce cuando el usuano presiona un botn del mouse.

MouseMove

Se produce cuando el puntero del mouse se mueve encima del control.

Mouselp

Se produce cuando el usuario suelta el botn del mouse sobre el contxol.

MnuseWheel

Se produce cuando el usuario mueve la rueda del mouse._ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _


Tabla 4 . Eventos de los controles con representacin grfica.

FORMULARIOS
Si hacemos doble clic en

Forml.cs

en la pestaa

Solution Explorer,

mulario principal de la aplicacin en tiempo de diseo (vista

veremos el for

de diseo del formu

lario). Aqu: podremos agregar otros controles del Toolbox, y modificar las propie
dades del formulario y de los controles. Las propiedades ms importantes son:

ALTERNATIVAS A VISUAL STUDIO .NET

V is u a l S tu d io .N E T e s un e x ce le n te e n to rn o de p ro g ram ac i n , pero ta m b i n existen a lte rn a tiv a s .


E n e l sitio

.net coders (www.dotnetcoders.com/web/Article5/ShowArticle.aspx7articlessA9l

co n tra re m o s un listad o con o tros e n to rn o s q u e so n o p c io n e s

u s r .c o d e

en

a la h e rra m ie n ta d e M icrosoft.

227

PROGRAMACIN CU

1 PROPIEDAD

'

DESCRIPCIN

AcceptButton

Indica qu botn del formulario es presionado si el usuario pulsa la tecla Enter.

BackCotor

Odor de fondo del formulario.

CancelButton

: Pont
ForeColor
: lext
Location

'. 1

Indica qu botn del formulario es presionado si el usuario pulsa la tecla Escape.


Tipografa predeterminada que emplear el formulario y los controles que contenga.
Color de la tipografa del formulario.
Titulo del formulario.
Ubicacin del formulario en la pantalla.

! MaximurtSize

Tamao mximo del formulario (en pixetes de alto y ancho). Si estas propiedades se encuentran en (0,0),

MinimumSize

Tamao mnimo del formulario (en pixeles de alto y ancho). Si estas propiedades se encuentran en (0,0),

entonces el formulario no tendr tamao mximo.


entonces el formulario no tendr tamao mnimo.
: Size
StarlPosition

Tamao del formulario.


Puede ser:
-Manual: la posicin es especificada por la propiedad Location.
-CenterScreen: se centra la ventana en relacin con la pantalla.
-WindowsDefauItlocation: posicin predeterminada.
-WindowsDefaultBounds: posicin y tamao predeterminados.
-CenterParent: se centra la ventana en relacin con la ventana padre.

WirtdowState

Puede set;
-Normal: ventana en modo normal
Minimized: ventana en moo minimizado.
Maximized: ventana en modo maximuado.

ControIBox

Indica si la ventana poseer los botones de minimizar, maximizar, cerrar y el men contexta! que se desprende
de ella cuando hacemos clic sobre su extremo superior izquierdo,

; Icn
MaximizeBox
Men

MinimizeBox

TopMost

Icono que representar a ventana.


Indica si la ventana poseer botn de maximizado.
Indica cul es ei men de la ventana (luego veremos esta propiedad en detalle).
Indica si la ventana poseer botn de minimizado.
Opacidad de la ventana. Mediante esta propiedad podremos volverla semitransparente
Indica si la ventana se encuentra delante de todas las dems, ms all de estar o no seleccionada.
Tabla 5. Propiedades del form ulario.

Los mtodos ms comunes del formulario son:

Cise
, Hide
Show

Cierra el formulario.
Ocuita el formulario.
Muestra el formulario.
Tabla 6. M todos del form ulario.

I
228

u s r .c o d e

Crear una aplicacin sencilla

Los eventos ms comunes del formulario son:


1 EVENTO

DESCRIPCIN

Activated

'

|i

Es invocado cuando el formulario es activado de algn modo.

Ciosed

Es invocado inmediatamente despus de que el formulario es cerrado.

Closing

Es invocado justo antes de que el formulario sea cerrado.

Deactrvated

Es invocado cuando el formulario pierde el foca (deja de ser e) formulario activo).

Load

Es invocado antes de que el formulario sea visualizado por primera vez.


Tabla 7. Eventos del formulario.

Cada vez que modificamos el valor predeterminado de alguna propiedad del formu
lario o de algn control del formulario, Visual Studio agrega cdigo al mtodo InitializeComponent que mencionamos antes. Podemos verificar esto modificando, por
ejemplo, la propiedad Text del formulario. Inmediatamente despus observaremos,
en el mtodo mencionado, el siguiente cdigo:
prvate void InitializeComponentO

{
//

...

// Form l

II

...

this.Text = "Formulario principal";

Cuando comencemos a agregar controles sobre el formulario, este mtodo no de


morar en hacerse realmente extenso, por lo tanto, es una buena idea colocarlo den
tro de un bloque regin.

CREAR UNA APLICACIN SENCILLA


Comenzaremos a modificar nuestra aplicacin creada por el asistente de Visual

Studio agregando dos controles al formulario.

Para esto deberemos acceder a la vista de diseo del formulario y luego hacer visi
ble la barra de herramientas llamada

Toolbox

(debera estar a la derecha o a la iz

quierda del formulario cuando ste se encuentre en diseo).

u s r .c o d e

229

PROGRAMACIN CA

Toolbox
M y U ser Controls
D a ta
Cofiiponents

W indow s Forms
^

Pointer

A Label
A LinkLabd
j b j Button
[ab TextB ox
M ainM eru

|7 CheckBox
(

RadioButton

L j GroupBox
m

PictureBox

Pant!

n p DataGric
D 3 LfstBox
1 3 C h ecke d istB o x
!

CornboBox
ListView
TreeVIew

J J TabControl
DateTmePicker
D I M o n th C en d ar
j j ) HScroIlBar

, :

G eneral

Figura 7. La caja de herramientas.

Ahora, agregaremos a nuestra aplicacin dos controles: un TextBox y un Button.


Para esto seleccionamos el TextBox del Toolbox y lo insertamos en el formulario. Lo
mismo hacemos con el Button, ajustando ambos controles hasta lograr el aspecto
que deseemos. Podemos cambiar sus nombres si as lo deseamos, o la leyenda pre
determinada que muestra el TextBox y la que exhibe el Button.
Hecho esto, deberamos estarante nuestra ventana con un aspecto similar a ste:

!EI lenguaje-de programacin Cfc

E:ciibit mer-raie en cuad>o de texto

Figura 8. Agregando dos controles.

230

u s r .c o d e

C r e a r u n a a p lic a c i n s e n c illa

Ahora, cuando presionamos el botn, querramos cambiar el contenido del cuadro


de texto. Requerimos que el framework nos

avise cuando se produce la ocurrencia


Se ha hecho un clic sobre el botn. Cmo podramos hacer esto? Con even
tos! As es, los delegados y los eventos entran nuevamente en accin. Y con Visual
Studio, la manera de fijarlos es muy sencilla: la pgina de propiedades posee un bo
tn que conmuta a ver los eventos del control seleccionado (Figura 9).

buttonl

S ystem .W indow s.F orm s.B utton

t iia S

SBHPmmamimmtBm
buttonl Click
0 .

,i> .

Paint

0 ! I '.
C hang eU IC ues
H d p R eq u ested
Q ueryAccessiblityHelp
StyleC hanged
System ColorsChanged

0 (D ataB indings)
0 l s< l.vx
D ragD rop
D ra g E n ter
Drag L e ave
D ra g O ver
GiveFeecfoack
Q u ery C o n tn u e D ra g

8 f OOH
E nter
L e av e
Validated
Valdating

Figura 9. Seleccin de eventos en la pgina de propiedades (Properties).

U H LA "PROPIEDAD" (AME)
Cuando modifiquemos la propiedad (ame) desde el Toolbox del editor de formularios, Visual

Studio modificar el nombre de nuestro objeto instanciado a partir de la clase del control del for
mulario. Cualquier referencia a l dentro del cdigo deber ser modificada manualmente.

u s r .c o d e

2 31

PROGRAMACIN CU

Ntese que ahora la pgina muestra los eventos del control activo (en este caso, el
botn). Si hacemos doble clic sobre el evento llamado Click, entonces automtica
mente generar el cdigo requerido para que un mtodo de nuestro formulario ma
neje dicha ocurrencia. El cdigo agregado por el diseador de formularios ser:
El mtodo que trate el evento con identificador conformado por el nombre del
control, seguido por el signo underscore y del nombre del evento por tratar (como
por ejemplo: buttonl_Click).
Agregado del mtodo al evento por tratar dentro del mtodo InitializeComponent.
this.buttonl.Click += new System.EventHandler(this.buttonl_Click);

Luego de que el entorno haya agregado el cdigo correspondiente, nos situar al co


mienzo del mtodo que trata el evento para que podamos escribir el cdigo espec
fico que deseemos.
En nuestro caso queremos modificar el valor de la propiedad Text del control

Text-

Box, por lo tanto escribiremos:


textBoxl.Text = "El lenguaje de programacin C#";

Ntese que nuestro Button se llama buttonl y nuestro TextBox se llama textboxl. Es
tos son los nombres de las instancias (objetos) que ha fijado el entorno automtica
mente. Nosotros podremos hacer los cambios que consideremos adecuados.

Convencin de nombramiento para controles


Ms adelante nuestros controles sern nombrados haciendo uso de una conven
cin de nombramiento que consiste en anteponer a los nombres de los controles
un prefijo de -generalmente- tres letras, correspondiente al tipo de control. Lue
go, se prosigue con el nombre que mejor describa lo que el control hace, sin se
paraciones con caracteres especiales, sino especificando en maysculas los nom
bres de las palabras que lo conforman. Por ejemplo:
Botn de Ok: cmdOk.
Botn que imprime una ficha de cliente: cmdlmprimirCliente.
TextBox que alberga el nombre de un usuario: txtUsuario.

ListView que muestra procesos: IvwProcesos.

232

u s r .c o d e

Crear una aplicacin sencilla

La siguiente es una lista de prefijos en funcin del tipo de control. No es un deber


seguir esta convencin, pero muchos programadores lo hacen y facilita en gran me
dida la legibilidad del cdigo.

u s r .c o d e

CtieckedUstBox

chkl

ColofOiaiog

ctallg

ComboBox

cbo

ConlextMenu

anns

Control

ctr

: ataGrid

dgr

DataList

dlst

DateFimePictef

dtp

DropDownList

cbo

FontDIafeg

fntrflg

Form

frm

Group8ox

ffl

HelpProvider

hpv

HscrollBar

hsb

Image

img

Imagest

its

Label

Ibl

linktabel

Ubi

ListBox

Ist

UstView

Iw

Men

mnu

MonthCalendar

mclr

Notifylcon

nicn

NumericUpDown

nudn

OpenFlleDialog

ofdlg

i PageSetupDialog

psdlg

Pane!

pnl

PictureBox

pie

PrintDialog

prtdlg

PrintOocuntent

prtdoc

ProgressBar

prg

RadkrButton

rdb

RadioButtonList

rdbl

RichTextBoi

rt

233

PROGRAMACIN C#

TIPO DE CONTROL

PREFIJO

Tabla 8 . Prefijos segn el tipo de control.

MANIPULACIN DE LOS CONTROLES BSICOS


Veremos ahora cmo realizar una aplicacin que posea controles del tipo:
Button y ListBox.

TextBox,

Caso de estudio 1
Controles empleados: TextBox,

ListBox, Button.

Crearemos una aplicacin con un cuadro de texto, un cuadro de lista y tres botones.
La idea ser que, presionando un botn, se agregue el texto del cuadro a la lista, con
el segundo botn se elimine la informacin seleccionada en la lista y con el tercer bo
tn se limpie la lista por completo. La aplicacin tendr el siguiente aspecto:
*

Fo rm u la rio p rin c ip a l
A flre ja r

Figura 10 . Haciendo uso del ListBox.

234

u s r .c o d e

Manipulacin de los controles bsicos

TextBox
Sus propiedades ms importantes son:
1 PROPIEDAD
MaxLength

DESCRIPCION

Mxima cantidad de caracteres del cuadro.

Muttiline

Indica si el control os multilnea.

ReadOnly

Si es verdadero, impide que el usuario pueda modificar el contenido del texto dentro del cuadro.
'

Text

Indica el contenidode textodel cuadro.

TextAlign

Indica la alineacin del texto dentro del cuadro.

PasswordChar

Indica el signoque simbolizar uncarcter en una clave.

Tabla 9. Propiedades del TextBox.

Sus mtodos ms importantes son:


,

. . .

1 MTODO DESCRIPCIN ..
Clear

Limpia el control.
Tabla 1 0 . Mtodo del TextBox.

Sus eventos ms importantes son:

TextChanged

Es invocado cuando cambia el texto dentro del cuadro.


Tabla 1 1 . Evento del TextBox.

Button
El botn lo utilizaremos para disparar las acciones. Simplemente nos colgamos del
evento Click como lo hemos hecho anteriormente.
Sus propiedades son:
1 PROPIEDAD

DESCRIPCIN

Image

Indica la imagen que contendr el botn (si es que poseer alguna).

Imagelndex

Indica el ndice de la imagen si esque el botn posee unImagetist relacionado.

Text

Indica el contenido de texto del botn.

TextAlign

Indica la alineacin del textodentro del botn.

Tabla 1 2 . Propiedades del Button.

Sus eventos ms importantes son:


EVENTO

DESCRIPCIN

Click

Es invocado cuando se presiona el botn izquierdo del mouse sobre el botn.


Tabla 13 . Evento del Button.

u s r .c o d e

235

PROGRAMACIN Ctt

ListBox

Existen controles que no manejan un solo dato, sino un conjunto de datos. Co


mo vimos, la librera B C L provee un excelente soporte a las colecciones. Por lo tan
to, los controles que manipulan conjuntos de datos usan varias de las interfaces de
colecciones que ofrece la librera, para trabajar con el conjunto de datos que poseen.
Esto es bueno, ya que muchas de las operaciones nos sern conocidas.
Tal vez la propiedad mas importante que posee el control

ListBox es Items. Items es

una propiedad del tipo ListBox.ObjectCollection que implemento las interfaces IList,

ICollection e Enumerable;

esto significa que dispondremos de los mtodos imple-

mentados de estas interfaces para manipular el contenido de la lista.

in te rfa z
IList

ListBox

in te rfa z
Collection

in te rfa z
Enumerable

ListBox.ObjectCollection

Figura 11. El diagrama de clases simplificado del control ListBox.

Entonces, para agregar un elemento a la lista deberemos utilizar el mtodo Add de


la propiedad Items de la lista. Para eliminar el contenido de la lista deberemos uti
lizar el mtodo Clear de la misma propiedad, y, finalmente, para eliminar un tem
deberemos utilizar el mtodo Remove.

El mtodo Add
El mtodo Add recibe un objeto de tipo Object como parmetro. Luego, como he
mos visto, todo Object debe implementar un mtodo ToString() que devuelva una

OTROS CONTROLES

En la Red encontraremos muchos sitios que ofrecen libreras de controles para bajar e integrar
muy fcilmente a nuestras aplicaciones. ComponentOne es uno de los ms conocidos en este as
pecto (www.componentone.com).

236

u s r.c o d e

Manipulacin de los controles bsicos

representacin del contenido del objeto en formato texto. Dicho texto ser el que
exhibir el ListBox.
Adems, el hecho de que toda clase sea descendiente de Object resulta en que el ListBox
puede almacenar en su interior cualquier tipo de objeto definido por nosotros.
El cdigo que especificaremos para agregar texto a nuestra lista ser:
IstOsuarios.Items.Add(txtsuario.Text);

El mtodo Clear
Utilizar el mtodo Clear es muy sencillo, no posee parmetros.
Simplemente escribiremos:
IstOsuarios.Items.Clear();

El mtodo Remove
El mtodo Remove recibe un objeto de tipo Object como parmetro. Este objeto se
r el que la lista misma nos informe que est seleccionado.
Escribiremos, entonces:
lstsuarios.Items.Remove(IstUsuarios.Selectedltem);

Ahora, agregaremos una verificacin extra. No deseamos que el usuario pueda agre
gar a nuestra lista dos nombres iguales. Si esto ocurre, se deber informar esta situa
cin mediante un cuadro de mensaje. Tampoco deseamos introducir valores nulos.
Por lo tanto, el cdigo que invoca el evento Click de nuestro primer botn ser:
if (txtsuario.Text == "")
return;
if (lstsuarios.Items.Contains(txtsuario.Text) == false)
lstsuarios.Items.Add(txtsuario.Text);
else
MessageBcx.Show(''El valor ya se encuentra en la lista");

u s r .c o d e

237

PROGRAMACIN CU

Otras propiedades del control ListBox:

Items

Coleccin de elementos de la lista.

Selectedlndex

India cul es el ndice deltemseleccionado.

Selectedlndices

Indica cules son los ndices de los tems seleccionados.

Seiectedltem

indita cul es et temseleccionado.

Selectedltems
} SelectedValue

Sorted

Indica cules son los elementos seleccionados.


Indica cul es el valor del temseleccionado.

Indica si la lista se encuentra ordenada.


Tabla 14. Ms propiedades del ListBox.

Otros mtodos importantes:

FindString: busca el primer tem de la lista que comienza con el texto especificado.
Otros eventos importantes:

SelectedlndexChanged: invocado cuando la propiedad Selectedlndex se modifica.


SelectedValueChanged: invocado cuando la propiedad SelectedValue se modifica.
Sin embargo, mejor sera que si el texto del cuadro txtsuario fuera nulo, el usua
rio ni siquiera pudiera presionar el botn

Agregar.

Cmo podramos hacer esto?

Existe una propiedad de casi todos los controles llamada Enabled, que permite ha
bilitar o deshabilitar un control. Luego, los cuadros de texto poseen un evento lla
mado TextChanged, que es invocado cuando existe una modificacin sobre el con
tenido del cuadro.
Utilizaremos la propiedad y el evento citados para cumplir nuestro cometido.

cmdAgregar ahora comenzar con valor false en la propiedad Enabled.


2. Nos colgarem os del evento TextChanged del cuadro de texto txtUsuario y escri
1. El botn

biremos la siguiente lnea de cdigo:


cmdAgregar.Enabled = I(txtUsuario.Text ==

Enabled de cmdAgregar ser la nega


txtUsuario.Text == En consecuencia, si el cuadro
de texto s est vaco, el botn no se habilita, en tanto que si el cuadro de texto no
se encuentra vaco, el botn s se habilita.
Con esto queremos afirmar que la propiedad

cin de la expresin booleana

236

usr.code

Manipulacin de los controles bsico:;

De un modo similar procederemos con los botones cmdQuitar y cmdLimpiar. No


queremos ofrecerle al usuario la posibilidad de hacer algo que no tiene sentido
que ocurra. Por qu habilitar el botn

Quitar cuando no existe ningn elemento

seleccionado en la lista?, o por qu ofrecer la posibilidad de limpiar la lista cuan


do se encuentra vaca?
Implementar estas verificaciones es muy sencillo:
1. Cada vez que se agrega un elemento, se habilita el botn Limpiar.
2. Cada vez que se quita un elemento: a) se verifica que la lista no haya quedado
vaca; b) se verifica que exista alguna seleccin vlida.
3. Cada vez que se limpia la lista: a) se deshabilita el botn Limpiar; b) se deshabi
lita el botn Quitar.
4. Cuando se modifica en la lista el elemento seleccionado activo (evento SelectVa-

lueChanged), verificamos si debemos activar el botn Quitar.


El cdigo completo de esta aplicacin lo podemos encontrar en el proyecto

GUIAppl, que se puede descargar desde el sitio onweb.tectimes.com.


Caso de estudio 2
Controles

em pleados: RadioButton, GroupBox y CheckBox.

A continuacin prestemos atencin a cmo utili

! Formulario Principal

zar los botones de opcin, los cuadros de verifica


cin y los cuadros de grupo.
La aplicacin es muy simple. Solamente colocare
mos cdigo en los eventos ms comunes de los
controles y utilizaremos sus propiedades bsicas.

R adioB utto n seleccionado;

Uno

g ro u p B o x l

!<
FaoBttorii
C ra d io 8 u tto n 2
C

radioB uttonS

E stad o de checkBox 1: C h eq u ead o


E stad o de checkB ox2; C h eq u e a d o

(7 checkB ox 1
Figura 12. El manejo de botones de opcin y cuadros

17 checkB ox2

de verificacin es muy sencillo.

Las propiedades que marcan o desmarcan los botones de opcin, as como los cua
dros de verificacin, es Checked. Esta opcin es booleana, por lo que acepta dos va
lores: verdadero

u s r .c o d e

(true)

o falso

(false).

239

PROGRAMACIN CU

El cuadro de verificacin, sin embargo, podra quedar en un tercer estado, que es


indeterminado. Para poder fijar el control en este estado particular utilizaremos la
propiedad CheckState. Esta acepta los valores Checked, Unchecked e Indeterminate.
El cuadro de grupo se suele utilizar para agrupar controles. Si bien posee sus pro
piedades y algunos eventos, en general stos no varan en tiempo de ejecucin.
El evento que se invoca cuando el control cuadro de opcin o cuadro de verifica
cin es modificado se llama CheckedChanged. En resumen, el cdigo que escribire
mos ser, principalmente:
prvate void rdbl CheckedChanged(object sender, System.EventArgs e)

{
lblRBSeleccionado.Text = "Uno";

}
prvate void rdb2_CheckedChanged(object sender, System.EventArgs e)

{
lblRBSeleccionado.Text = "Dos";

}
private void rdb3_CheckedChanged(object sender, System.EventArgs e)

{
lblRBSeleccionado.Text = "Tres*;

}
private void chkl_CheckedChanged(object sender, System.EventArgs e)

{
if (chkl.Checked)
lblEstadoCBl.Text = "Chequeado";
else
lblEstadoCBl.Text = "No chequeado";

}
private void chk2_CheckedChanged(object sender, System.EventArgs e)

{
if (chk2.Checked)
lblEstadoCB2.Text = "Chequeado";
else
lblEstadoCB2.Text = "No chequeado";

}
Podemos encontrar el cdigo completo de esta aplicacin en el proyecto GUIApp2,
que se puede descargar desde el sitio oficial del libro
240

(onweb.tectimes.com).

u s r .c o d e

Manipulacin de los controles bsicos

Caso de estudio 3
Controles empleados:

ListView, ImageList.

El control ListView es muy empleado gracias a su flexibilidad. De algn modo reem

ListBox, que ahora slo se utiliza en casos muy sencillos. Es que el


ListView nos permite crear listas con mltiples columnas, iconos representativos, di
plaza al clsico

versas vistas de la informacin, etc. Sus propiedades ms importantes son:


L , i . >. M e ES '1^

3; . y ggf f i

Columns

Coleccin de columnas.

FullRowSelect

Indica si la seleccin es por toda fa fila.

GridLines

Indica si se deben mostrar las lneas de gua.

Items

Coleccin de elementos de la lista.

LabelEdit

Indica si se permite la edicin de elementos sobre la lista.

Selectedlndices

Indica cules son los ndices de los tems seleccionados.

Selectedltems

Indica cules son los elementos seleccionados.


Tabla 15. Propiedades del control ListView.

Sus mtodos ms importantes:


DESCRIPCIN

Clear

Elimina todos los elementos y columnas del control (no confundir con el Clear de la propiedad Items).

Sort

Ordena los elementos de la lista.


Tabla 16. Mtodos del control ListView.

Sus eventos ms importantes:


DESCRIPCIN

ColumnClick

Es invocado cuando el usuario realiza un clic sobre alguna columna.

ItemCheck

Es invocado cuando cambia el estado de verificacin de algn elemento.

SelectedlndexChanged

Es invocado cuando la propiedad Selectedlndex se modifica._ _ _ _ _ _ _ _


Tabla 17. Eventos del control ListView.

t i ! ! PROPIEDADES COMUNES
Gracias al buen diseo de la librera BCL, muchas de las propiedades que encontraremos en con
troles que nunca antes hemos utilizado nos sern familiares. Si al control se le puede fijar un tex
to, seguramente se realizar por medio de la propiedad Text. Esto no ocurra en versiones ante
riores de Visual Basic ni en la librera VCL de Borland.

u s r .c o d e

241

PROGRAMACIN C#

Observemos una aplicacin de ejemplo sencilla en la cual veremos un conjunto de


daros, que en este caso sern nombres de archivos de un directorio, y que nos per
mita jugar con algunas de las propiedades de la lista.
La manipulacin de los datos internos del ListView es similar al ListBox; aqu tambin
existe una propiedad que implementa las interfaces IList, ICollection e lEnumerable.
Excepto que ahora la propiedad Items ser del tipo ListView.ListViewItemCollection.

Figura 13. D ia g ra m a de cla s e s s im p lific a d o d e l c o n tro l L is tV ie w .

Los mtodos que encontraremos en esta implementacin de coleccin sern, por su


puesto, los declarados en las interfaces, pero cabe hacer una mencin: el mtodo Add
no recibe un objeto del tipo Object, sino que espera un objeto del tipo ListViewItem:
y es que ahora no existe slo una columna, sino varias (o al menos existe la posibili
dad de que esto suceda). Tambin podremos hacer un uso trivial de la lista aprove
chando una versin de Add que recibe un string, escribiendo:
lvwArchivos.Items.Add("Este es el item 1 ");
lvwArchivos.Items.Add("Este es el item 2");
lvwArchivos.ItemB.Add("Este es el item 3 ");
lvwArchivos.11ems.Add("Es te es el item 4 ");

III

NUESTROS PROPIOS CONTROLES

Crear un control nuevo es muy sencillo. El asistente de aplicaciones generar el marco de la li


brera que requeriremos, y slo deberemos encargarnos de escribir cdigo especifico del tipo de
control que deseemos crear.

242

u s r .c o d e

Manipulacin de los controles bsicos

Adems, antes de utilizar el control deberemos especificar las columnas que posee
r. Esto se puede realizar en tiempo de diseo (propiedad Colunins):

Hembeis:

columnHeadet 1 Properties.:
HHH

1 IcolumnHeadet!

'B

E (DyrvamicPropcttli

4i a .

21 colutcnHeadirv
r

(N-ar.ne)

columnHeadcrl

Modfier;

Prvate

Tea

Nombre

Te:<tAIn

Lef:

Wldth

146

1
Add

gemove

O):

Cancel

Help

Figura 14. Agregando columnas al ListView.

Y tambin podramos hacerlo mediante cdigo:


lvwArchivos.Columns.Clear () ;
ColumnHeader ch;
ch = new ColumnHeader();
ch.Text = "Columna 1";
ch.Width = 100;
lvwArchivcs.Columns.Add(ch);
ch = new ColumnHeader();
ch.Text = "Columna 2";
ch.Width = 100;
lvwArchivos.Columns.Add(ch);
ch = new ColumnHeader();
ch.Text = "Columna 3";
ch.Width = 100;
lvwArchivos.Columns.Add(ch);

La propiedad Columns es del tipo ListView.ColumnHeaderCollection, que tambin implementa


u s r .c o d e

IList, ICollection e IEnumerable.

Luego, en caso de que deseemos agregar


243

PROGRAMACIN C#

columnas, el mtodo Add acepta objetos del tipo ColumnHeader, por lo que debemos
crear dicho objeto con anterioridad.
Notemos que en el listado anterior no reutilizamos el objeto

ch para todas las co

lumnas, sino que creamos objetos nuevos. El asunto es que aqu el control almace
na referencias a las columnas, y si utilizamos los mismos objetos, el control no se
comportar como esperamos que lo haga.
Respecto a las filas, el modo de manejarnos ser similar:
ListViewItem lvi;
lvi = new ListViewItem("primera fila, primera columna");
lvi.Subltems.Add{"priinera fila, segunda columna");
1vi.Subtems.Add("primera fila, tercera columna");
lvwProcesos.Items.Add(lvi);
lvi = new ListViewItem("segunda fila, primera columna");
lvi.Subltems.Add("segunda fila, segunda columna");
lvi.Subltems.Add("segunda fila, tercera columna");
lvwProcesos.Items.Add(lvi);

// ...

ListViewItem, al que agregaremos subelementos


Subltems.Add y luego lo relacionaremos con la lista

Aqu crearemos un objeto del tipo


utilizando para ello el mtodo
por medio de su mtodo Add.

Con la nica finalidad de hacer un poco ms atractiva la aplicacin, ingresaremos


los datos al control ListView a partir de la informacin que obtengamos del listado
de archivos de un directorio.
Haciendo uso de la clase System.IO.Directorylnfo podremos obtener la informacin
que deseamos sobre el directorio.
L,uego, relacionaremos los datos de las filas con un icono representativo. Para esto
deberemos agregar a nuestro formulario un control del tipo ImageList. Este control
es un contenedor de imgenes que se puede relacionar con otros controles.
Para relacionar nuestro ListView con nuestro flamante .ImageList, deberemos acce
der a la propiedad SmalllmageList que posee el ListView desde la vista de diseo
de formularios. Esta propiedad es especificada seleccionando un elemento de la lis
ta que nos ofrece. Si la desplegamos, podremos observar que nos ofrece todos los
244

u rr.c o d e

M a n i p u l a c i n d e lo s c o n t r o l e s b s i c o s

nombres de los ImageList que posee nuestro formulario. Una vez que selecciona
mos el nico que hemos agregado, la relacin ha sido consumada.
Las imgenes dentro del ImageList poseen un ndice, deberemos referirnos a alguna
de ellas por medio de este nmero. En nuestro ejemplo, hemos agregado un peque
o bitmap de 16x16 al ImageList que referenciaremos por su ndice: el nmero cero.
ListViewItem lvi;
lvi = new ListViewItem("primer fila, primer columna'
);
lvi.Subtema.Add("primer fila, segunda columna*);
lvi.Subtems.Add("primer fila, tercer columna");
ivi.Imagelndex = 0;
lvwProcesos.Items.Add(lvi);

Como se puede apreciar en el listado anterior, antes de agregar el objeto del tipo

ListViewItem al ListView, especificamos que su Imagelndex sea 0.


Finalmente, cabe sealar que este tipo de listas posee distintos modos de visualizacin (que ya conocemos, por usar diariamente el explorador de archivos de W in
dows). Existe el modo Details, donde se observan todas las columnas y la informa
cin en modo de filas; el modo Smalllcon, donde se aprecian los elementos slo por
el nombre ingresado en la primera columna y con un icono pequeo que le hemos
relacionado; el modo Largelcon, que es similar al

Smalllcon, aunque utiliza un ico

no ms grande que tambin deberamos relacionarle; y finalmente el modo List, que


muestra la lista como Details pero ocultando todas las columnas menos la primera.

En el ejemplo usamos un control de tipo ComboBox para elegir la vista del ListView.

CheckBox para modificar la propiedad GridLines del List


GridLines activado, la lista muestra unas lneas de guas horizontales y
verticales (slo es visible en modo Details).

Tambin colocamos un

View.

Con

r CONTROLES CONOCIDOS
Los controles que ofrece la librera BCL son les que podremos encontrar en cualquier otra apli
cacin convencional de Windows, y son lo suficientemente vastos como para adapta-se a much
simas necesidades.

u s r .c o d e

245

PROGRAMACIN CU

6 S formuario Principal
fD etafc

Nombre

| ( 7 Grilla Visible
I Tamao

Q i o s . p ic

6730

tA

|S 108.pic

6JOO

tA

| 3 .p c

6710

b b b b m w

i''-'"

,m

tA
m

E fb o o tiri

211

tA

SfiBootfont.bin

4952

ca

ffjCONFIG.SYb

cA

[jdatdbase.bdb

180633o

tA

23) debug.txt

1689

(A

p l ii b e r f s y s

536399372

tA

IO .S Y 5

cA

)fn fc 7 l.d *

1060364

cA

3] m fc7tu.dll

1047552

tA,

S M 5DQ 5.SY5

tA

t) msvcp71.dll

499712

tA

||m svcr7l.dl

348160

tA

|N TD E TEC T,C O M

47564

tA

B r it U r

250640

cA

lp a g e fite .s y s

805306368

cA

459646

tA

SjThum bs.db

7680

tA

@ )vefdurd,fcm p

196664

tA

iS fZ inioInstal.tx t

6316

tA

3 ;

tA

Figura 15. El control TreeView mostrando los datos que le ingresamos.

Podemos encontrar el cdigo completo de esta aplicacin en el proyecto

GUIAppS,

que se puede descargar desde el sitio oficial del libro.

Caso de estudio 4
Controles

em pleados: TreeView, ImageList.

El control TreeView es muy prctico y poderoso. Es la pareja ideal para el

ListView,

y muchsimas veces se utilizan en conjunto. Este control nos permite mostrar la in


formacin de un modo jerrquico, es decir que los elementos del control pueden
depender de otros elementos (como archivos dentro de carpetas).
Al igual que el ListView, el TreeView permite asociar imgenes de un ImageList a sus
elementos. El modo en que se relacionan ambos controles es exactamente el mismo
que el que ya hemos analizado.
Tambin, adems de muchos otros controles que manejan un conjunto de datos,
posee una propiedad que implementa las interfaces iList,

246

iCollection e iEnumerable.

u s r.c o d e

Manipulacin de los controles bsicos

Esta propiedad es Nodes y pertenece a la clase TreeNodeCollection.

Figura 16, Diagrama de ciases simplificado de TreeView.

Por medio de Nodes manipularemos la informacin de los datos que muestre el


Si deseamos agregar un elemento, deberemos escribir:

TreeView.

TreeNode tnl = new TreeNode('Uno', 0, 0);


tvwElementoe.Nodes,Add(tnl);

El primer parmetro que recibe el constructor de TreeNode es el texto que represen


tar el nodo; el segundo es un ndice de una imagen del ImageList relacionado que
se utilizar como icono pata el nodo en cuestin, y el tercer parmetro tambin es
uir ndice de imagen, pero ser empleado slo cuando el usuario est seleccionando
el nodo (en nuestro caso utilizamos la misma imagen, pero podramos cambiarla
para dar un efecto esttico distinto).
Luego, con el objeto de tipo TreeNode creado, simplemente haremos uso del mto
do Add de la propiedad Nodes de la clase TreeView.

MEJORANDO LA INTERFAZ DE USUARIO

Antes de crear la nterfa2 de usuario de nuestra aplicacin, ser conveniente conocer un poco la
ciencia que subyace tras su diseo. Existen libros que tratan este tema, y varios artculos que po
dremos encontrar en la Red, como en www.medlcalcomputingtoday.com/flagui.html.

u s r .c o d e

247

PROGRAMACIN Cff

Si observamos cautelosamente, lograremos advertir que la clase TreeNode tambin


posee una propiedad Nodes.
Esto quiere decir que cada nodo puede contener otros nodos, y precisamente esto
es lo interesante del control
que lo componen.

TreeView:

la organizacin jerrquica de los elementos

Entonces, si deseamos crear un subnodo del nodo tn l, podremos escribir:


TreeNode tn2 = new TreeNode("Dos", 1, 1);
tnl.Nodes.Add(tn2);

Tngase en cuenta la pequea y sutil diferencia que posee este listado en compara

cin con el anterior: en este momento no utilizamos el objeto tvwElementos (que es

el nombre de nuestro objeto de tipo


de tipo TreeNode.

TreeView), sino tn l,

que se trata de un objeto

Esta operacin tambin podra repetirse con tn2, es decir que cada

n od o

puede po

seer uno o ms nodos hijos sin que el control especifique lmite alguno.
Para limpiar los elementos de la coleccin no hay novedades; deberemos escribir:
tvwElementos.Nodes.Clearf);

Luego existen algunas otras propiedades de inters de la clase TreeView, que son:
1 PROPIEDAD
CheckBoxes

Indica si se deben mostrar cuadros de verificacin junto a los nodos.

Imagelndex

ndice de imagen predeterminado que se utilizar en los nodos.

Indent

Distancia desde el margen Izquierdo hasta los nodos.

labelEdit

Indica si se permite editar el texto de los nodos.

Selectedlmagelndex ndice de imagen de nodo seleccionado por predefinicin que se utilizar en los nodos.
Showtmes
ShowPlusMinus

indica si se deben mostrar fas lneas de guas.


Indica si se deben mostrar los cuadros junto a los nodos que indican si ste se encuentra expandido
o contrado.

ShowRootlines

Indica si se debe mostrar le lnea raz del rbol.

TopNode

Devuelve el primer nodo visible del control.

VisibleCount

Devuelve la cantidad de nodos visibles que muestra el control.


Tabla 18. Propiedades de la clase T r e e V ie w .

248

usr.code

M a n i p u l a c i n d e lo s c o n t r o l e s b s i c o s

Sus mtodos ms importantes son:

Tabla 19. Mtodos ms importantes del control TreeView.

Y sus eventos ms importantes:


| EVENTO

A H I

AfterCheck

Invocado despus de marcar un cuadro de verificacin relacionado con un nodo.

AfterCollapse

Invocado despus de contraer un nodo.

AfterExpand

Invocado despus de expandir un nodo.

AfterSeiecl

Invocado despus de seleccionar un nodo.

BeforeCheck

Invocado antes de marcar un cuadro de verificacin relacionado con un nodo.

BeforeCollapse

Invocado antes de contraer un nodo.

BeforeExpand

Invocado antes de expandir un nodo.

BeforeSetect

Invocado antes de seleccionar un nodo.


Tabla 20. Eventos de la clase TreeView.

La aplicacin de ejemplo que desarrollaremos a continuacin tendr la funcin de


realizar un esquema de elementos arbitrario y modificar algunas de las propieda
des pertenecientes al control.

USFormulario Principal

Elemento seleccionado

Uno

|Cos

Tres
Algunas propiedades del TreeView
|

jr

TreeView con cuadros de verificacin

17 M o strar Sheas
[7 Mostrar cuadrlos

i (7 M o strar linea raz

UJ_I

17 Habilitado

Figura 17. La aplicacin del ejemplo en accin.

Podemos encontrar el cdigo completo de esta aplicacin en el proyecto GUIApp4,


el cual se puede descargar desde el sitio oficial del libro: onweb.tectimes.com.
u s r .c o d e

249

PROGRAMACIN CE

Caso de estudio 5
Controles empleados: mltiples formularios, Men,

TrackBar, ProgressBar.

Hasta ahora, nuestras aplicaciones tenan slo un formulario. Pero usualmente las
aplicaciones poseen ms de uno. Para agregar un nuevo formulario a nuestra apli
cacin, slo deberemos seleccionar nuestro proyecto desde el Solution
sionar el botn derecho del mouse e ingresar en la opcin Add/Add

Explorer, pre
Windows Form....

CUIApp5 MtrojoflVbualCf.NldwljnJ foiml.ci


t*
' r
* 33 35-.
\ ... :* : r i *<' ' J
& H - .
i1""Bfcifc li3
v,.;
: >
j<aiJlAftfJrirfWi 1^ da:frrWsr:S>*ieri.Wndr*yifiir>.Frn{..)
2 oe
dial
?
Mugw'JJWaoT(lcirvt'
|<;a3A<v5.lnrM*.
2}
d
Zl
Sj Rstuld
kej.iiirJ ic-i k.sJV* crfen,o:.?t v.Wc
'
al
JMherKs..
i6ise>Ioipc?>ebl().
AdJOctoence.. lij AddtnstryUor..

MJWfbPefaence.. NwWn
. --..ir |LI M | e t ! l
5* te>
.3MdWnom&nOctwj

JJ AJJ(r/*edFarr. j
i Conti..
;C WfSUIA*'.
/ MUrrrteCrrtrul. j.V-inrri* .VI.J >-<Uxl
)
....*-.
^ 'jX Bemc-f
MJCcfConnt.
i .km- :
ftspwtJH Rtrjc
t MQku.
II < -tW, l. j)
CUtApcSjg

y ij
i i;
)
Bh"oikiffc
LJ. : )
i:.:|
>
3
:J -f ir........
Merf
.......... ..."...... ....~
i Outxxi
IX
joefcuq
i t*W
.f.UlV
o
o
fc
ti
n
:
l
o
*
!

'

.
c
:
\w
|
n
d
>
v,\u
i
e
ro
i
v
(l
.M
i
W
l
uiu;ik\vl
1
.
IJ.'
.
ltici,
lll
d
i
)
H
e
lyitrli
nl-: Ut4.J-1.
Cvccifi.y
*:k^7
UXinAtvvj
|f .feraiU.O
jtC.USIC
Ac*of.C_>
t*7?',.icJJJ Jo
*,)C
.w
i CCIAffS..,.': lLoe.J..
ed.
Nvri^v
<
.....V
Ecunilsa..
te:,

Figura 18. Agregando un formulario a nuestro proyecto.

Ahora nuestra aplicacin posee dos formularios. Cul es el principal? El primero?


El segundo? En realidad, ninguno. El formulario que se ver cuando el usuario ini
cie la aplicacin ser el que mostremos nosotros, y esto actualmente lo estamos ha
ciendo en el mtodo esttico

Main,

que se encuentra en el formulario

Forml

pero

podra estar en cualquier formulario de nuestra aplicacin.


Para mostrar un formulario en particular, slo deberemos invocar el mtodo Show o
ShowDialog. La diferencia entre ellos consiste en el modo de mostrar el formulario.
Show abre el formulario de modo no m odal, es decir que el usuario podr seguir ope
rando con otros formularios de nuestra aplicacin sin tener que cerrar el formulario
que le acabamos de abrir.

ShowDialog,

en cambio, muestra el formulario de un mo

do modal; esto significa que el usuario no podr seguir interactuando con otros for
mularios abiertos de nuestra aplicacin hasta que se cierre el recin abierto.
250

usr.code

Manipulacin de los controles bsicos

En la aplicacin de ejemplo, el formulario 2 lo abrimos a partir de un men que


colocamos en el formulario 1. Para esto bastar con seleccionar el control de men
desde el Toolbox y luego presionar el botn izquierdo sobre nuestro formulario.
El control Men es representado por un pequeo icono debajo de nuestro formula
rio (donde generalmente se colocan los controles sin representacin grfica). Y tam
bin es visible como men del formulario. All mismo podremos comenzar a edi
tarlo., agregando opciones y eventos a las opciones especificadas.

Control Men

GUAVISUAL 2

mtubrto Principal

E25E3 \21:
Ablir Form ulario 2

&
Sal

^ mainMenut

O Icono que representa al men.


O Men editable en tiempo de diseo.

Entonces, escribiremos cdigo para el evento Click de la opcin de men que espe
cifiquemos para abrir el segundo formulario; este cdigo ser:
Form2 frm2 = new Form2();
fna2.Show ();

u s r .c o d e

251

PROGRAMACION CS

Cuando el usuario haga clic sobre la opcin de men, se distanciar el formulario


y se mostrar en pantalla.
Para evitar que se cree un objeto nuevo cada vez que el usuario abra el formulario,
podramos agregar a frm2 como una variable de Forml y con un inicializador (ha
ciendo un new Form2() en la misma lnea en que lo declaramos), y luego simple
mente podramos hacer:
frm2.Show();

Pero si el usuario no abre nunca el formulario 2, de todos modos lo habremos instanciado al inicio de la aplicacin. Tal vez sta no sea una buena idea: depender de
la importancia del formulario 2 para la aplicacin: si siempre ser abierto o no.
Una tercera opcin podra ser inicializar la variable
desee abrir el formulario, escribir:

frm2 a nuil y luego, cuando se

if (fnn2 == nuil)
rm2 = new Fono2();
frm2.Show();

Cuando la aplicacin se inicie, no se solicitar memoria para frm2. Esto slo se har
la primera vez que el usuario desee abrir dicho formulario. Lo malo de esta solucin
ser que siempre, antes de utilizar alguna propiedad o mtodo de frm2, deberemos
verificar que no sea nuil, o generaramos una excepcin en tiempo de ejecucin.
En nuestro ejemplo, el formulario 2 es muy sencillo. Slo posee un botn que lo oculta:
HideO;

Tambin podramos haberlo cerrado:


Cise () ;

Pero frm2 nunca ms podra ser abierto; por eso deberemos hacer otro new

Form2().

Por ltimo, agregamos dos controles ms al formulario 1 para hacer ms interesan


te la cuestin. Estos son el TiackBar y el ProgressBar, ambos muy sencillos de usar.
252

u s r .c o d e

Manipulacin de los controles bsicos

En nuestro ejemplo, nos colgamos del evento Scroll del TrackBar que se invoca ca
da vez que alguien quiere modificar el valor de la barra (por cdigo o por interac
cin con el mouse), y dentro de este evento escribimos:
prgMedidor.Valu = tbrBarra.Valu;

El valor de un TrackBar se lee y se escribe del mismo modo que el control ProgressBar: a travs de su propiedad Valu.
Existen otras propiedades generalmente modificadas cuando se utiliza este tipo de
controles, que son:

Mnimum

Valor mnimo que puede tomar el TrackBar o ProgressBar.

Mximum______ Valormximoquepuede tomar et TrackBar o ProgressBar.


Tabla 21. Otras propiedades.

Este es el segundo formulario


Ocutar

Figura 19. Nuestro pequeo ejemplo en accin.

Podemos encontrar el cdigo completo de esta aplicacin en el proyecto GUIAppS,


que se puede descargar desde el sitio oficial del libro: onweb.tectimes.com.

M I RESUMEN
En este captulo hemos dado el puntapi inicial en la construccin de aplicaciones con con
troles. .NET hace esto m u y sencillo gracias al excelente diseo que posee la librera BCL. En
los prximos captulos, todos los ejemplos que estudiemos estarn basados en aplicaciones
de este tipo, y cuando veamos alguna propiedad o mtodo nuevo relacionado con los contro
les, lo indicaremos convenientemente.

usr.code

253

J 3 ACTIVIDADES

TEST DE AUTOEVALUACIN

EJERCICIOS PRCTICOS

1 Nombrar tres controtes que manipulen co

Construir un pequeo juego basado en un

lecciones y tres que no lo hagan. Nombrar

formulario con seis botones que posean co

tres controles que no posean representa

lores diferentes. El formulario tambin debe

cin grfica en tiempo de ejecucin.

poseer dos botones ms: uno para comen


zar el juego y otro para cerrar la aplicacin.

2 Pueden ciertos controles contener a otros?

El juego consiste en generar una secuen


cia aleatoria en la cual los botones se van

3 Puede un TextBox poseer en su interior


texto de diversas tipografas?

encendiendo y apagando Icambiando de


color de fondo a uno ms claro para gene
rar este efecto), que el jugador debe imitar.

U Son los valores de los controles de tipo

Dicha secuencia va extendindose progre

CheckBox dentro de un GroupBox mutua

sivamente en cada turno a medida que el

mente excluyentes? Y los controles de tipo

jugador acierte.

RadioButton?

Entonces, en el primer turno el juego en


ciende un botn y espera a que el jugador lo
imite. Si lo hace bien, vuelve a encender el
mismo panel y agrega otro ms (avanza so?
bre la secuencia generada); nuevamente el
jugador deber imitar la secuencia propues
ta. El juego termina cuando el jugador con
sigue imitar el tamao mximo de la se
cuencia (este valor debe estar especificado
en una constante) o cuando se equivoca. En
ambos casos se debe generar un mensaje
de texto que informe de la situacin.

254

usr.code

Captulo

PROGRAMACIN C#

Acceso a datos
externos
Un programa que no interacte con
elementos externos no resulta de mucho
inters. En este captulo veremos cmo
acceder a archivos de texto y binarios,
como tambin a bases de datos
relacinales por medio de AD0.NET.

Archivos

servicio de atencin al lector: le cto re s@ m p e d icio n e s.co m

256

File
.1 1 1 J
Tipos de streams
Manipulando archivos de texto
Manipulando archivos binarios

56
256
257
260

Bases de datos
SQL
Elementos de una base
de datos relacional
Un ejemplo sencillo

266
269

263
. 2 6 5

Crear un OataSet mediante


cdigo
Resumen

279
281

......

282

Actividades

PROGRAMACIN C#

ARCHIVOS
Todos sabemos que un archivo es una coleccin de datos situada en algn disposi
tivo de almacenamiento, y que posee un nombre por medio del cual podemos refe
rendario para interactuar con l.
La librera BCL ofrece muchas clases para facilitarnos su manipulacin. De stas,
tal vez la ms popular sea la clase File.

File
La clase File se compone slo por mtodos estticos que nos permiten crear, copiar,
eliminar, mover y abrir archivos. Veamos algunos de sus mrodos ms importantes:

Copy

Copia un archivo.

Create

Crea un archivo.

Delete

Elimina el archivo especificado como parmetro (por nombre),

Existe

Informa si el archivo parado como parmetro (por nombre) easte o no.

Move

Mueve un archivo.

GetAltributes

Devuelve los atributos de un archivo.

Open

Abre un archivo.

DpenText

Abre un archivo de texto.

SetAttributes

fija los atributos de un archivo.


Tabla L Mtodos de la clase File.

Lo que no posee la clase File son mtodos para leer o escribir el contenido del archivo.
Para esto deberemos utilizar los objetos que nos devuelven los mtodos Create y Open.
Estos mtodos nos devolvern diversos tipos de streams (flujos) con los cuales s po
dremos manipular el contenido de los archivos.

Tipos de streams
Existen diversos tipos de streams:
Streams de memoria (clase MemoryStream): la fuente de datos se encuentra sita
da en la memoria de la computadora.

Streams de archivos (clase FileStream): la fuente de datos son archivos.


Streams de redes (clase NetworkStream): la fuente de daros es el extremo de una
comunicacin que se efecta va red.

256

u s r .c o d e

Archivos

Todos estos tipos de streams descienden de la misma clase Stream, como se puede
apreciar en el siguiente diagrama de clases:

Figura 1. El diagrama de clases simplificado de los streams.

En funcin de la ubicacin en la que se encuentre la informacin por manipular,


deberemos utilizar uno u otro tipo de stream citado. Sin embargo, esto no es todo.
La informacin posee una semntica que deberemos tener en cuenta para saber qu
otra clase debemos utilizar en conjunto.
Bsicamente, esta semntica consiste en si la informacin es texto (codificada con
algn juego de caracteres) o si es binaria. Entonces, existe otra tipificacin de

streams que se combina con la anterior:

Lectura de informacin de tipo texto (clase StreamReader).


Escritura de informacin de tipo texto (clase StreamWriter).
Lectura de informacin binaria (clase BinaryReader).
Escritura de informacin binaria (clase BinaryWriter).

Manipulando archivos de texto


Veamos un poco cmo trabajan estas clases. Crearemos una aplicacin similar al
Notepad que simplemente nos permita abrir y grabar un archivo.
Introduciremos tambin aqu un nuevo control, que son los dilogos de archivos.

Q Q QU ES UN STREAM?
Un stream es un objeto que encapsula una secuencia de datos. Los streams de lectura producen
informacin, mientras que los streams de escritura la reciben. Los streams abstraen al progra
mador del modo concreto en el cual se opera con la fuente de datos.

u s r .c o d e

257

PROGRAMACIN C #

H B B

' * Anotador
Archivo
Requerimiento:; mrrmos do la splicacin

Para podar ejecutar la aplicadn se requiere tener instalado:


1. El framework ,NET 1.1 o superior
Esto lo podemos verificar desde el panel de control, en la opn
"Agregar o Quitar programas". Si el framevrorl.se encuentra nstalado,
all deber aparaten Adems junto con el nombre del programa
aparece su versin:
"Microsoft Framework ,NET 1.1"

Figura 2. Nuestro pequeo anotador.

Nuestra aplicacin poseer un men principal, un cuadro de texto (fijado en modo


multilnea, y con la propiedad Dock fijada en Fill), un dilogo de apertura de archivos
(clase OpenFileDialog) y un dilogo de escritura de archivos (clase SaveFileDialog).
Para abrir un archivo a partir de su nombre y copiar su contenido al control TextBox,
deberemos escribir:
StreamReader sr = Pile.OpenText(nombreArchivo);
txtTexto.Text * ar.ReadToEndl);
sr.CloseO;

En la primera lnea hacemos uso del mtodo esttico OpenText de la clase File. Estemtodo nos retornar una referencia a un objeto

StreamReader,

con el cual mani

pularemos el contenido del archivo.


El objeto StreamReader posee los siguientes mtodos:

Cise
Peek

Cierra el stream.
Devuelveel simiente carcter del stream, peronoloconsume (esto signiiea queen la prximaoperacin de Peek
oReadvolveremosa leer el mismocarcter).

Read

Devuelve y consumeel siguiente carcter del flujo.

Readne

Devuelveun stringcon la siguiente lnea detent.

ReadToEnd Devuelve un stringcon el contenido detexto de todo el stream.


Tabla 2. Mtodos del objeto SreamReader.

En el listado de cdigo anterior utilizamos el mtodo ReadToEnd porque deseamos


colocar todo el contenido del archivo en el control (tal vez, si nuestra aplicacin tra
bajase con archivos muy extensos, esto no sera una buena idea).
258

u s r.c o d e

Archivos

Finalmente cerramos el stream utilizando el mtodo Cise.


Para grabar el archivo modificado o un archivo nuevo, escribiremos:
StreamWriter sw * File.CreateText(nombreArchivo)j
8w.Write(txtTexto.Text);
sw.Closel);
H B H H H R B H B H B E B B W m KHBHHBRHh N h HHBREBRIBh H M

En este caso empleamos el mtodo CreateText de la clase File, que nos devolver un
objeto del tipo StreamWriter.
El objeto StreamWriter posee, principalmente, los siguientes mtodos:

Cise

Cierra el stream.

flosti

limpia los taiffetsrelacionadoslc*ido efectivala intormacsnescrita pfeviamenieen el seam.

Write_ _ _ _ _ _ _ Escribe informador de texto en el stream._ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _


Tabla 3. Mtodos del objeto StreamWriter.

Del objeto de tipo StreamWriter utilizamos el mtodo Write y le pasamos un string


que en su interior contiene la informacin que deseamos almacenar en el archivo.

En ltimo trmino, cerramos el stream.

Respecto a los controles de dilogo, su utilizacin es muy sencilla. Pero cabe desta
car que no tenemos por qu utilizarlos; aqu los introducimos simplemente porque
es habitual ofrecer este tipo de dilogos al usuario cuando se solicita que se seleccio
ne un archivo para abrir o guardar.
dlgAbrirArchivo.Title
Abrir archivo de texto*;
dlgAbrirArchivo.Filter = "Archivos de texto (*.txt)|*.txt|Todos
los archivoB (*.*)|*.** ;
if (dlgAbrirArchivo.ShovDialogO == DialogResult.OK)

{
// Almaceno el nombre
nombreArchivo = dlgAbrirArchivo.FileName;

// . . .
}

dlgAbrirArchivo es el objeto de tipo OpenFileDialog


u s r .c o d e

de nuestro formulario.
259

PROGRAMACIN CS

En cuanto a la grabacin del archivo, el proceso es muy similar. Utilizaremos un ob


jeto del tipo SaveFileDialog (llamado dlgGrabarArchivo).
s*
v&msmsrm i -.y-.

dlgGrabarArchivo.Ti
tle = "Grabar archivo de texto";
dlgGrabarArchivo.Pilter "Archivos de texto (*.txt)j*.txt|Todos
los archivos (*.*}}*.*" ;
if (dlgGrabarArchivo.ShowDialogO == DialogRestilt.OK)
.

nombreArchivo a dlgGrabarArchivo.FileName;
// ...

Como se puede apreciar, ambos listados de cdigo son muy parecidos, y es que am
bos tipos de dilogo poseen casi las mismas propiedades, ya que son descendientes
de la clase FileDialog.
Veamos sus propiedades ms utilizadas:
PROPIEDADES

DESCRIPCIN

FileName

Nombre del archivo seleccionado.

1 FBtet

Especifica las opciones <te filtro que se leofrecern al usuario para que elija un tipo de archivo vlido.

InilialDirectoiy

Permite especificar en qu directorio comenzarel dilogo.

Title_ _ _ _ _ _ _ _ Titulo de la ventana de dilogo._ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _


Tabla 4. Propiedades de la clase FileDialog.

Y sus mtodos:
b

ShowDiaiog

Muestra el dilogo en modo moda!.


Tabla 5. Mtodos de la clase FileDialog.

Manipulando archivos binarios


Crearemos una aplicacin que nos permita leer y escribir los valores de las variables
de un objeto definido por nosotros arbitrariamente.
Esta vez, de la clase File utilizaremos el mtodo OpenRead y OpenWrite. Ambos m
todos nos devolvern un objeto de tipo FileStream. A partir de l crearemos otros
objetos, con los cuales manipularemos los archivos BinaryReader y BinaryWriter.
260

u s r .c o d e

Archivos

Veamos el cdigo. Leyendo el archivo binario:


PileStream fe a File.OpenRaadfnambreArchivo)?
if (fs 1= nuil)

{
BinaryReader br = new BinaryReader(fs);
varBntera br.ReadInt32();
varString * br.ReadStringO;
varPloat = br.ReadSingleO;
br. Cise ();

}
f8.Cise 0 ;

Como mencionamos, el mtodo OpenRead nos devuelve un objeto de tipo FileStream.


Con l deberemos crear un objeto BinaryReader. Luego podremos utilizar los mto
dos de BinaryReader para leer la informacin del archivo ya abierto.
Entre los mtodos ms importantes encontramos:

Read

Lee uncarcter del stream.

ReedBoolean

Lee unvalor booteanodel stream.

ReadByte

Lee unbytedel stream.

ReadDcuble

Lee un nmerode precisindobledel stream.

Readlntl6

Lee unnmero enterode 16 bits del stream.

Read)nt32

Leeun nmeroenterode32 bits del stream.

Readlnt64

Lee un nmeroentero de 64 bits del stream.

ReadSByte

Leeun bytenosignadodel stream.

ReadSingle

Lee un nmerode precisinsimple el stream.

ReadUln!l6

Lee unnmeroenterode 16 bitsnosignadodel stream,

ReadUlnt32

Lee un nmeroentero de 32 bits nosignadodel stream.

Readlllnt64______ Lee un nmeroenterode 64 bitsnosignado del stream.


Tabla 6. Mtodos del objeto BinaryReader.

Ahora escribamos el archivo binario.

u s r .c o d e

261

PROGRAMACIN C8

PileStream fs = Pile.OpenWrite(nombreArchivo);
i (fs 1= nuil)

{
BinaryWriter bw a new BinaryWriter(s);
bw.Write(varRntera);
bw.Write(varString);
bw.Write(varFloat

);

bw. Cise ();

}
fa.CloseO

Para la escritura del archivo binario procedimos de un modo similar. En este caso
slo utilizamos el mtodo Write de BinaryWriter, no existe la necesidad de especifi
car diversos mtodos con identificadores diferentes, pues el mismo Write est sobre
cargado para todos los tipos de datos que soporta.

Write: escribe el tipo de dato pasado como parmetro al stream.


Boolean

Chars

Int32

Byte
Bytes

Decimal
Double

Int64
SByte

Char

Intl 6

Single

Soporta:

U lntl
UInt32
UInt64

Figura 3. Nuestra pequea aplicacin en accin.

D Q UTILIZANDO EL NAMESPACE 10
Debido a que todas las clases de manipulacin de streams se encuentran bajo el espacio de
nombres 10, ser conveniente que agreguemos la siguiente lnea al comienzo de nuestro archi
vo de cdigo fuente: using System.IO;.

262

u s r .c o d e

Bases de datos

BASES DE DATOS
Una base de datos (DB, por su nombre en ingls) es una coleccin de informacin
relacionada. Fsicamente podra estar compuesta por uno o ms archivos estructu
rados internamente para optimizar la manipulacin de los datos que contienen.
Hoy en da, muchsimas aplicaciones poseen la necesidad de almacenar sus datos en
un medio eficiente, como una base de datos, para su posterior consulta o manipu
lacin. Para esto se podra seleccionar entre muchos productos gestores de bases de
datos que existen en el mercado. Los ms populares actualmente son:

Oracle Database Server


Microsoft SQL Server
Sybase Adaptive Server Enterprise
El

Informix Dynamic Server


MySQL Database Server

framework .NET ofrece una serie de clases que facilitan en gran medida la in

teraccin con bases de datos de un modo independiente al fabricante. Estas clases


son conocidas como ADO.NET

(ActiveX Data Objects).

AD O .NET es una evolucin de ADO, y una de sus principales novedades es que


ahora permite trabajar de un modo desconectado de la base de datos. Esta decisin
ofrece varias ventajas; una de ellas es el ahorro de recursos, ya que en muchas oca
siones las aplicaciones los desperdiciaban permaneciendo extensos perodos de
tiempo sin realizar operacin alguna (pero con una conexin retenida).
Con AD O .N ET nos conectaremos a la base, traeremos un conjunto de datos y fi
nalmente nos desconectaremos de ella. La aplicacin trabajar con los datos obte
nidos de modo local, y si existe la necesidad de realizar alguna actualizacin, volve
r a conectarse y el ciclo se renovar.
Por otro lado, esta nueva arquitectura es mucho ms adecuada para su uso en pro
gramacin web, por la naturaleza que posee este tipo de aplicaciones.

III

CONECTIVIDAD A BASES DE DATOS DESDE .NET

Desde .NET podremos conectarnos a casi cualquier base de datos que exista. Si sta no ofrece
clases especificas de ADO.NET, siempre podremos seguir conectndonos a ella mediante ODBC
(Open DataBase Connectvity\.

u s r .c o d e

263

PROGRAMACIN C#

Aplicacin ADO.NET
DataSet

DataReader
Adaptcr

Connection
Data

Base de
datos

.NET Data Provlder

DataSet

Data Table Connection


Data Tabla

DataAdapter

DataRowCollection

Comando SELECT

DataColumnCollection
Connection

Comando INSER

Command

Comando UPDATE

DataReader

Comando DELETE

ConstraintCollection

Base de
datos

DataRelatlonCollection

XML

Figura 4. Esquema de la interaccin entre la clase ADO.NET y una base de datos.

264

u s r .c o d e

Bases de datos

SQL
Podemos encontrar una gran variedad de productos gestores de bases de datos.
Afortunadamente para todos nosotros, existe un lenguaje declarativo estndar de
consulta llamado SQ L (Structured Query Language).
Con SQL no slo estaremos posibilitados para consultar la informacin almacena
da en la base de datos, sino que tambin nos permitir agregar, modificar y elimi
nar informacin, as como modificar las estructuras lgicas donde los datos se en
cuentran contenidos (por ejemplo, tablas).
No liaremos aqu una gran introduccin en el lenguaje SQL, slo nos limitaremos
a nombrar los principales comandos y dejaremos ai lector la tarea de profundizar en
l, en caso de que lo considere conveniente.
Existen tres tipos de comandos SQL:

{Data Manipulation Language)-. son los comandos que se encargan de la


manipulacin de informacin.

DML

SELECT: permite consultar por la informacin almacenada dentro de la base de da


tos en sus distintos elementos.
INSERT: permite ingresar informacin en la base de datos.
UPDATE: permite modificar la informacin en la base de datos.
DELETE: permite eliminar informacin de la base de datos.
DDL

{Data Definition Language)-. comandos para la definicin de informacin.

CREATE: permite crear los distintos elementos de la base de datos.


ALTER: permite modificar la estructura de los distintos elementos de la base.
DROP: permite eliminar los elementos definidos previamente.
DCL

{Data Control Language)-.

estos comandos estn destinados a las tareas de

control y configuracin de la base de datos.

[U

ESCRIBIENDO COMANDOS SQL

Conocer SQL para trabajar con bases de datos es muy recomendable. Sin embargo, si no nos ma
nejamos muy bien con este lenguaje, podremos utilizar los asistentes que ofrecen los controles
de AD0.NET para que sean ellos los que construyan los comandos SQL por nosotros.

u s r .c o d e

265

PROGRAMACIN CU

DENY: niega permisos a usuarios para realizar determinadas tareas.


GRANT: otorga permisos a usuarios para realizar determinadas tareas.
REVOKE: revoca permisos otorgados.

Elementos de una base de datos relacional


Una base de datos se encuentra compuesta por diversos elementos. Entre los ms
destacables podemos mencionar:

Tabla: es el elemento fundamental. Una tabla representa una entidad y sus rela
ciones; contiene unidades de informacin denominadas registros, que especifican
valores para cada campo que la tabla puede almacenar (determinados en colum
nas). Posee un nombre mediante el cual se referencia.
CDIGO

NOMBRE

APELLIDO

EDAD

juan

ritz

20

pedio

pa

23

carlos

toms

25

ivan

werty

26

-Columnas

-Registros

Figura 5. Una tabla posee columnas y registros.

ndices: los ndices son estructuras de datos que se relacionan con una o ms co
lumnas de una tabla, con el fin de acelerar el proceso de bsqueda de registros
cuando se utilizan los campos de dichas columnas como criterio.
son tablas virtuales creadas dinmicamente a partir de consultas preesta

Vistas:

blecidas. Poseen la virtud de simplificar el acceso a la informacin.

Procedimientos almacenados: son Scripts administrados por el gestor de bases de


datos que actan, principalmente, sobre los elementos de sta. El lenguaje en el
cual se programan estos scripts depender del gestor de la base de datos.
son scripts que se disparan cuando se suceden ciertas

Disparadores (triggers):

operaciones sobre los elementos de la base de datos (por ejemplo: cuando se in


tenta agregar un registro a una tabla).
Los elementos de una base de datos pueden ser creados, modificados o eliminados
por medio de comandos SQ L (del tipo

DDL).

Sin embargo, es bastante frecuente

emplear aplicaciones ms amistosas que nos faciliten la tarea mediante una interfaz
de usuario (estas aplicaciones se encargan de generar los comandos SQ L que corres
pondan a partir de nuestra interaccin).
AD O .N ET ofrece un poderoso conjunto de clases para manipular la informacin
de la base de datos. Ejecutar comandos SQL es slo una parte nfima de sus funcio
nalidades. Veamos cules son las clases ms importantes.
266

u s r .c o d e

Bases de datos

DataSet
Un

DataSet

es un conjunto de datos provenientes de una base de datos, de un ar

chivo XML, creados dinmicamente con cdigo, etc.


En el caso habitual contendr una o ms tablas relacionadas que sern obtenidas de
una fuente. Podremos trabajar con el

DataSet consultando por la informacin que

contiene, agregando, modificando o eliminando su contenido.


Posteriormente, si hemos realizado cambios, y en el caso de que deseemos que estas
modificaciones se hagan efectivas, podremos recorrer el camino inverso y actualizar
la fuente de datos con el DataSet (slo cuando la fuente lo permita).
Internamente, un DataSet posee:
Una coleccin de tablas (tipo

DataTable).

Una coleccin de registros por tabla.


Una coleccin de columnas por tabla.
Una coleccin de restricciones por tabla.
Una coleccin de relaciones.

DataSet
DataRelationCollection

DataTable Collection

DataTable
DataColumnCollection

DataRowCollection

ConstralnCollection

Figura 6. El interior de un DataSet.

Las tablas no tienen por qu estar colocadas dentro del DataSet de modo indepen
diente, sino que tambin pueden poseer relaciones que se expresan a travs de ob
jetos que se encuentren dentro de l.

PROGRAMACIN C#

Connection
Mediante un objeto del tipo Connection se realizar la conexin a la base de datos.

DataAdapter
Hemos mencionado anteriormente que un DataSet se alimenta de una fuente de da
tos, que en este momento para nosotros sera una base de datos.
El modo en el cual el DataSet se conecte a dicha base ser por medio de un objeto
del tipo DataAdapter, que se encarga de hacer de puente para la informacin, ya sea
desde la base hacia el DataSet o por el camino inverso.

DataSet

sjc--.NET Data Provider


DataAdapter
Comando SELECT

Connection

Comando INSERT

Com m and

Comando UPDATE

DataReader

Comando DELETE

Figura 7. Un D a t a S e t se conecta a una base de datos a travs de un D a t a A d a p t e r .

Internamente, un DataAdapter estar compuesto por comandos SQL, que sern uti
lizados para las operaciones que el DataSet requiera realizar con la base.

Command
Representa un comando SQL, el cual se ejecuta a una fuente de datos utilizando
para tal propsito un objeto del tipo DataAdapter.
268

u s r .c o d e

Un ejemplo sencillo

DataReader
Permite navegar hacia adelante por registros de una base de datos mientras se est
conectado a ella. Una aplicacin suele optar por utilizar DataReaders, en lugar de
DataSets, cuando la cantidad de datos por traer es muy grande (con DataSets se uti
liza mucha memoria) y se requiere un acceso de consulta muy rpido.

UN EJEMPLO SENCILLO
Ahora que hemos introducido los principales conceptos deADO.NET, podremos
ver un sencillo ejemplo. En nuestro caso utilizaremos una base de datos de tipo
Microsoft Access. Esta contendr slo una tabla que manipularemos utilizando
C# y las clases ADO.NET.
Nuestro primer paso ser crear una pequea base de datos con una tabla sencilla,
que luego consultaremos desde una aplicacin C#.
ID

NOMBRE

EDAD

CALLE

PISO

DEPTO

usuarol

25

CalleX

4555-0001

usuano2

26

CalleY

4555-0009

usuario3

23

CalleZ

4555-0201

usuario4

22

CalleW

4555-0441

TELFONO

Figura 8. Nuestra tabla de Usuarios.

Con la tabla creada veremos ahora cmo operar desde Visual Studio. Para esto
construiremos una aplicacin con interfaz de usuario del modo tradicional y arro
jaremos un control

DataGrid al formulario.

El control DataGrid es bastante prctico para interactuar con DataSets. Una vez que
ste se encuentre colocado en la porcin del formulario que ms nos agrade, agre
garemos otros controles ms. En este caso, dentro del

II

Toolbox,

cambiaremos de

QU BENEFICIOS DA UTILIZAR UNA BASE DE DATOS?

Utilizar una base de datos -en vez de archivos binarios- trae muchsimas ventajas debido a que
son sistemas creados para organizar y gestionar informacin. Entre otras caractersticas, podre
mos contar con integridad referencial de datos, seguridad de acceso, optimizacin de consultas,
etc. El uso de archivos binarios se justifica slo en aplicaciones muy sencillas.

u s r .c o d e

269

PROGRAMACIN C#

grupo y pasaremos de WebForms a Data. Dentro de esta seccin podremos encon


trar bsicamente tres tipos de controles:

Connection

DataAdapter

Command

Cada uno de ellos poseer un prefijo:

OleDb: conexin a una fuente de informacin a travs de un proveedor de datos


de tipo OLE DB. Este tipo de conexin ser la que utilizaremos para trabajar con
bases de datos creadas por la aplicacin Microsoft Access (Jet DB).
Sql: conexin a bases de datos Microsoft SQL Server.
Oracle: conexin a bases de datos Oracle.
Odbc: conexin a una fuente de informacin a travs ce un proveedor de datos
O D BC [Open DataBase Connectivity).
Todos los objetos de tipo

Connection

implementan la interfaz IDbConnection. Esto

es muy positivo, ya que cada implementacin tendr las particularidades que re


quiera para dialogar con el producto especfico para el cual fue construida, pero, al
mismo tiempo, tendr el mismo conjunto de propiedades y funciones.

Figura 9. Clases que implementan la interfaz IDbConnection.

[ U I ALTERNATIVAS DE CONEXIN
Es posible que, en ciertas bases de datos, tengamos varias alternativas para conectarnos a ellas.
En el caso de Oracle, por ejemplo, podremos utilizar OracleConnection y OdbcConnection. Siem
pre ser mejor usar el objeto especfico creado para dicha base, debido a que posee optimizacio
nes propias del fabricante.

270

u s r .c o d e

U n e je m p l o s e n c i ll o

De la misma manera que en el caso anterior, los objetos del tipo Command implementan la interfaz IDbCommand.

Figura 10. Clases que implementan la interfaz IDbCommand.

Y los objetos del tipo DataAdapter implementan la interfaz IDbDataAdapter.

Figura 11. Clases que implementan la interfaz IDbDataAdapter.

Si bien aqu veremos cmo utilizar objetos del tipo

OleDb,

en principio no habr

grandes diferencias en el uso de objetos para otros proveedores.


Por lo tanto, tomamos un control del tipo

OleDbConnection

y se lo agregamos a

nuestro formulario. De este control ser importante especificar la propiedad ConnectionString, que ser la que se ocupe de indicar al objeto la ubicacin y el modo
de conectarse a la base de datos.
Esta propiedad puede ser estipulada por cdigo o bien por medio de un asistente
que se dispone con esta finalidad.
usr.code

271

PROGRAMACIN Ct>

Asistente para conexin a la base de datos

PASO A PASO

El Si utilizamos el asistente, deberemos seleccionar Microsoft Jet 4.0 OLE DB


Provider como proveedor de datos.
e Propiedades de vinculo de datos

Provede* Conexin j Avaniedet | Toda: j


Seleccione b: datos a los que detea conctate.
I PfpYeedwet de OLOB
; MedbCaldogDB OLE DB Provider
i MediaCaialogMergedDE OLE D9 Provider
MediaCaalogWebDB OLE DB Provider
MiciocoflJet 3.51 OLE DB Provider
iMbo-^UcMOOLE DBPiovidw
Microsoft OLE OB Prvida ForData Mining Service;
MicrocoftOLE D Provider or Indexing Service
MicroottOLE DB F'iovidef for Internet Pubfehing
Micrcct OLE DB Provider Ior ODBC Diivcf
MbocoftOLE DB Provider Ior OLAP Service.
Microsoft OLE DB Prvida for OLAP Services 8.0
MicrosoftOLE DB Provider for Oracle
Microsoft OLE DB Provider la SQL Server
Microsoft OLE DB Simple Provider
MSOalaSiape
Pioveedo de base: de datos OLE para servicios de director v '

<

>

r&ifl^ente'>j
Aceplai I

Cancela! i

Ajajda

Luego, en Conexin podremos indicar la ruta completa a la base de datos.


e Propiedades de vinculo do datos
Pioveeda Cerrejn | Avanzadas I Todas |
Especifique bguenta paia conectase a data: de Access
1. Seleccior* o escriba el ncmtxe de una base de alca.
pbd.mdtj
.Escriba lanloiiTacion para non sesin en la tase de dalos:
Nonixe de ysuerc. lAdrnn

P Cortrasefia en blanco V Peinyii guafdei conliasea

tioba ccnen

Acopla |

272

Cancelar

Apjria

u s r .c o d e

U n e je m p l o s e n c i ll o

B Ahora, agregaremos el control OleDbDataAdapter. Cuando hagamos esto, un


asistente se abrir automticamente y nos ofrecer sus servicios.
?: Dala Adapte! Configuration Wizard
W elcom e to the Data Adaptar
Configuration Wizard
Ihis wi:crd hefp you spetfy thecomedinnd
database commands that the data capte: ues to
sdect records and handle changes tothe databasc,
You need to provide connectton ifocmatron and mate
decisions about how yvj want the databas*
commands stored -y>dexecuted. You* ability to
complete thts wizard iray deperrf oothe parmbftons
you har in the databa.
ClickNext te continu.

Cmtd

d >

Aqu deberemos seleccionar el objeto de tipo Connection por el cual nos conec
taremos a la base de datos (en nuestro caso ser el que hemos creado en las l
neas anteriores).
01 Dala Adapter Configuration Wizard

Choose Your Data Connection


The data adapter wtll ejecute queiee iwrig this connection to load
and update data.

K
'/

Choose froro the k t of data conrecttons currenty In Server Explorer a add a new
connection If the me you wentisnotfeted.

W hkti data connection should the data adapter U e?

vert9a\VTtejiAcqCS,'hn\Ciet!(Jl

u s r .c o d e

New Connection...

273

PROGRAMACIN C#

El Especificamos el modo de acceder a la base de datos. Las opciones que se en


contrarn disponibles dependern en forma exclusiva de las funcionalidades
que ofrece el gestor de base de datos.
? Data Adapter Confifuration Wizard
Choose a Query Type
The data adapter uses SQL statements or stored procedures.

J f

How shoddthe data adapter accett the delatase?

* Use SQL statements

Spec#y a Select statemant to load data, andthe wwaid w# genesHe the Insert, Update,
and Mete statements lo save data cherges

Specfy a Select statarent, and the wizard vi# generate new stered procederes te
select, insert, updete, and dtete recode.

C h f i-., .tui.j <nredit.nedi:nae


Chxase an eastirv; storrd procodure for eh operatan (select, insert, update and
deteste).

Ahora deberemos especificar el comando SELECT, por medio del cual se traer la
informacin desde la base de datos a travs del DataAdapter. Si no sabemos SQL,
podremos utilizar un creador de consultas presionando del botn Query

Builder.

* Data Adapter Confgurallon Wizard


G e n e ra te t h e SQL s ta te m e n ts
The Sefect stdtement mil be us*J to ae*te the Inser- Update, and
Deie-te statements.

Type in your SQL Sded statemer* or use the Query BufcJer to gr'dpbcelly desjgn the query.

Wfvat data shouW the data adapter load loto the dataset?

i
Advanced Optlorc...

Query Builder...

Cancel

274

<6A

u sr.code

U n e je m p lo s e n c illo

D La opcin Query Builder se encargar de solicitarnos que seleccionemos la


totalidad de las tablas que se utilizarn para realizar nuestra consulta (en nues
tro ejemplo, slo disponemos de una).

El An en el Query Builder, luego de que hayamos seleccionado las tablas, tambin


deberemos indicar cules sern las columnas que formarn parte de la consul
ta (no nos encontramos en la obligacin de traer todas las columnas de una ta
bla, sino solamente las que vayamos a utilizar).

1 m tk w i* *

; * (A l Colemos)
.'C e

QS3MMI
:id

v i

jOutput i Sort Type

|SortOrdw

lOtoia

U/Oircs

Usuarios

Ff

III
D Una vez que hemos cerrado el Query Builder, ste nos deja el comando SELECT
escrito en nuestro cdigo.

u s r .c o d e

275

PROGRAMACIN C#

En el ltimo paso, el asistente nos informa los comandos que fueron creados por
nosotros para manipular la informacin seleccionada.
$ Data Adapter Configuraron Wizard
V ie w W iz a r d R e s u lts
Review the fot of la (he wizord has performed. Ckk Fruih (o
complete or Back (o make charges.

Tne data adapter ofeObOateAdapterZ" waj configured successfiiy,

Details:
^ Generated SELECT siatemeot.
* Generated table mappings.
F Generated IN3ERT statement.
* Generated UPDATE tatemar*,
r1 Generated CELETE statenvent,

To appfi these settings toyour adapter, dkkFaush.

Cancel

Bien. Tenemos nuestro

OleDbConnection,

<feack j

| sh

que nos conectar a la base de datos, y

nuestro OleDbDataAdapter, que se encargar de hacer de puente para traer los datos

276

u s r .c o d e

Un ejemplo sencillo

de la base. Pero dnde los alojar? Podramos especificar para ello un DataSet pro
gramticamente o en tiempo de diseo.
Para especificarlo en tiempo de diseo deberemos seleccionar el DataAdapter, acce
der a su men contexta! y luego seleccionar la opcin Generate Dataset....

Cut

[fe Copi;

fe <*<
X

(dete

IS1 Properties
dbComertion

oleDbOai WWPW7---

Figura 12. Generando el DataSet.


Generate Dataset
enerate a dtaset that intludes the spocified tabte.
Chooi adatase*:
r fcating |

_ J

? fjew.
hoose Vitilch teb!e(s) to add to the dataset:
y UsuarlosdeDbOataAdapterl)

|7 Add this dstasct to the designer.

OK

Cantei

Help

Figura 13. Seleccionando el nombre de nuestro DataSet tipado.

u s r .c o d e

277

PROGRAMACIN Ctt

Completada esta operacin, notaremos que nuestro proyecto posee una nueva
clase. Esta clase es un DataSet tipado, creado especficamente para nuestras tablas.
Esto quiere decir que ahora podremos manipular las columnas, los registros, las
restricciones y las relaciones de nuestro objeto por medio de propiedades y mto
dos, como si fuese un objeto ms.
Veamos ahora cmo, casi sin escribir cdigo, podremos utilizar el control

DataGrid

para manipular nuestro DataSet llamado dssuarios.


Para esto simplemente deberemos fijar la propiedad DataSource del control DataGrid
a nuestro DataSet. Luego, mediante cdigo indicaremos de modo explcito que se
consulte la informacin de la base de datos:
adpUsuarios.Fi.il(dsUsuarios);

Podramos colocar esta lnea en el constructor del formulario, si as lo deseramos.

Figura 14. El control DataGrid en accin.

Por predefinicin, mediante el control podremos modificar la informacin conte


nida dentro del DataSet (o de la tabla seleccionada del DataSet). Este comportamien
to puede ser modificado si fijamos la propiedad ReadOnly en verdadero.
De todos modos, el hecho de modificar el

DataSet

no implica que los cambios se

hagan efectivos en la fuente (en este caso, nuestra base de datos). Para hacer los cam
bios efectivos deberemos utilizar el DataAdapter en sentido inverso (conceptualmen
te, claro). Podremos efectuar esta tarea escribiendo:
adpsuarioa.pdate(dssuarios, 'Usuarios");

278

u s r .c o d e

U n e je m p lo s e n c illo

Agregando datos al DataSet


Para agregar datos al

DataSet

de manera programtica, deberemos proceder del si

guiente modo:
// Creo un nuevo registro
DataSetsuarioe.BuariosRow newrow * dsOsuarios.Usuarios.NewsuarioaRowO;

// Especifico sus propiedades (columnas de la tabla del dataset)


newrow.id = 10j
newrow.nombre = 'guadalupe*;

// Agrego el registro nuevo


dataTable.AddOsuariosRow(newrow

);

// Actualizo la tabla (dataset -> tabla)


adpsuarios.pdate(dataSetll, 'Usuarios*);
..

:y

.vSSR

Analicemos el listado anterior.


En la primera lnea de cdigo creamos un nuevo registro del tipo UsuariosRow. Es
te tipo de dato fue creado automticamente en el momento en que generamos el

DataSet mediante el asistente citado.


Como habamos mencionado previamente, la ventaja de poseer un DataSet tipado
es enorme. Una de esas ventajas consiste en la verificacin de tipos de datos que se
realizar en tiempo de compilacin evitando de esta manera que cualquier error de
programacin surja en pruebas del sistema.

Crear un DataSet mediante cdigo


Es posible crear un DataSet de modo totalmente programtico sin que su conteni
do sea extrado de ninguna base de datos. Para ejemplificar esto crearemos una pe
quea aplicacin que posea slo un control DataGrid; dicho control no poseer nin
guna propiedad fijada en tiempo de diseo, tampoco arrojaremos al formulario nin
gn control de ToolBox.Data.
Los pasos que realizaremos sern bsicamente los siguientes:

1.a. Crear una tabla (objeto de tipo DataTable).


l.b . Especificar las columnas de dicha tabla,
l.c . Crear un DataSet (objeto de tipo DataSet).
l.d . Agregar la tabla creada al DataSet anterior.

u s r .c o d e

279

PROGRAMACIN C

2.a. Crear un nuevo registro.


2.b. Especificar el valor de los campos de dicho registro.
2.c. Agregar el nuevo registro a la tabla de nuestro DataSet.
3. Relacionar el DataSet al control DataGrid.
Veamos el cdigo para el paso 1:
.// 1.a. Creamos una tabla
DataTable tbArchivoe = new DataTable("Archivos");

// l.b. Agrego dos columnas


tbArchivos.Columna.Add{"nombre", Type.GetType("System.String*));
tbArchivos.Columna.Add{"tamao", Type.GetType("Sy8tem.Int32*));

// l.c. Creamos el dataset


dsArchivos * new DataSet ();
// l.d. Agregamos la tabla al dataset

);

dsArchivos.Tables.Add(tbArchivos

Del paso 2:
Directorylnfo di = new DirectoryInfo("c:\\");

// Get a reference to each file in that directorv.


FilelnfoH fiArr * di.GetFiles ();
// Display the ames of the files,
foreach (Filelnfo fri in fiArr)

{
// 2.a. Creo un registro
DataRow dw s dsArchivos.Tables ["Archivos"] .NewRowO ;

// 2.b. Especifico valores para el registro


dw["nombre"] = fri.ame;
dw["tamao*] * fri.Length;

// 2.c. Agrego el registro nuevo a la tabla


dsArchivos.Tables ["Archivos"].Rows.Add(dw);

Prstese especial atencin a que los registros se encuentran compuestos por infor
macin de consulta de archivos a un directorio arbitrario (esta tarea es simplemen
te para tomar datos de algn lugar).

280

u s r .c o d e

Un ejemplo sencillo

Y, finalmente, el paso 3:
dgDirs.D&taSource = dsArchivos.Tablea("Archivos*];

En este ltimo caso, el control tambin nos permite especificar, no una tabla, sino
un DataSet completo. En dicho caso ofrece un enlace con los nombres de las tablas
que componen el DataSet para ingresar en ella.
-*DataSets creado...

Archivos d e \
; nombre

f^~|fB]fx)

tamao

jdebug.txt

1689

ihkerfil.syj

536399872

iIO.SYS

mfc7l.dll

1060864

mfc71u.cl

1047552

HS005.SYS

jmsvcp71.dB

499712

:msvcr71.t0

348160

NTDETECT.C

47564

jntldr

2S0640

pagefile.sys

805306368

;5
tkb.txt
'Thumb.db

459646
7680

Figura 15. Nuestro ejemplo en accin.

RESUMEN
En el mundo real, las aplicaciones interactan con datos externos a la aplicacin misma: a r
chivos, bases de datos, objetos remotos, etc. En este capitulo hemos introducido varios con
ceptos importantes y, en particular, AD0.NET, un tema del cual podramos escribir un libro
entero. En el siguiente captulo estudiaremos cmo manejar los errores que podran produ
cirse en nuestros programas por medio de la manipulacin de excepciones.

u s r .c o d e

281

J T

a ct y id a d s

TEST DE AUTOEVALUACIN

EJERCICIOS PRCTICOS

1 Por qu la clase BinaryReader no posee

Modificar la aplicacin Anotador (que lee

slo un mtodo del tipo Read sobrecargado

y escribe archivos de texto) para que se

devolviendo en cada caso el tipo de dato

permita la modificacin de la tipografa

que corresponda?

utilizada por el control TextBox (haciendo


uso del control FontDialog). Agregar, ade

2 Podra un DataSet poseer informacin de


ms de una base de datos?

3 Qu es un DataSet tipado? Qu beneficios

ms, un formulario con informacin del


tipo Acerca de....

Arifoo

otorga? Es posible interactuar con una ba

ftaqueitmanlM rrflntMde la ac*cyin

se de datos con un DataSet no tipado?

f fu a porW pjrul v U phcacm it i M t t lefiei hit alado


l . El iamevcri. .fJET 1.1c auptiioi
Eno 1>j podaros -er.:* de-Je i :<jrd de .oriol, c-iIalv
" t v jr q x o Quita pi agramas*. U t i h & m e jy & entuerto t a alado.
ol deber
ai. Aderi>junt.itw<cl>iomCp Je! pto^tor
Ofrece SJ vetjtti:
IferottftFror.Kv,. .fJCT l.l*

282

u s r .c o d e

PROGRAMACIN C

Captulo

Manejo
de excepciones
Qu sucede cuando en la ejecucin
de nuestros programas las cosas no salen
de la manera prevista? 6Qu ocurre
cuando no es posible encontrar aquel
archivo que necesitamos abrir o cuando
el usuario ingresa un dato invlido?
C# ofrece un sistema de manejo de
excepciones muy completo que nos
permitir lidiar con estas situaciones
de un modo muy sencillo y efectivo.

Tratamiento de errores
Encerrar las excepciones

284
28B

Clases de excepciones
Generar excepciones

287
234

Crear nuestras propias clases


de excepcin
servicio de atencin al lector: le cto res@ m pedicio nes.c om

Resumen
Actividades

296
297
298

PROGRAMACIN C#

TRATAMIENTO DE ERRORES
Sabemos que los programas que escribimos pueden poseer errores, algunos de los
cuales son detectados en tiempo de compilacin (errores de sintaxis, semnticos,
etc.), pero otros podran permanecer inadvertidos por ser errores de lgica o raquerir ciertas condiciones para manifestarse.
Si debemos efectuar una divisin y el denominador es provisto por una variable in
gresada por el usuario, el proceso de compilacin finalizar de manera satisfactoria.
Pero en nuestro programa podra producirse un error en el supuesto caso de que el
usuario especificara cero como denominador.
Por otro lado, siempre existe la posibilidad de que se presenten situaciones impre
vistas, a pesar de no que no existan errores de programacin en nuestra aplicacin
(siempre y cuando no tomar todas las precauciones en cada caso no sea considera
do por nosotros como un tipo de error).
C# ofrece un sistema para manejar este tipo de situaciones, heredado del lenguaje
C++, que se denomina manejo de excepciones ( exception handli?ig).
Una excepcin es una alteracin en el flujo de ejecucin normal de la aplicacin. El
sistema de manejo de excepciones tiene como principal finalidad permitir el trata
miento de errores en nuestros programas.
Hasta el momento, el cdigo desarrollado por nosotros no ha hecho tratamiento de
excepciones. Por ejemplo, la lnea de cdigo que observamos a continuacin pare
cera no poseer inconveniente alguno:
int num = Convert.ToInt32 (txtNum.Text);

Aqu, nuestra intencin fue convertir a nmero entero el contenido de un cuadro


de texto especificado.

In g re s e un nm ero

20
Convertir

Figura 1. Convirtiendo texto a nmero.

284

u s r .c o d e

Tratamiento de errores

Cuando e] usuario ingrese un nmero dentro del cuadro de texto, la funcin de


conversin retornar con el resultado de modo satisfactorio. Pero qu sucedera si
el cuadro de texto posee algo que no sea un nmero en su interior? La conversin
fallar, y en pantalla observaremos la presencia de un mensaje que nos informar de
lo ocurrido, luego de lo cual nuestra aplicacin se cerrar.
Si estamos ejecutando la aplicacin desde el entorno de desarrollo, veremos en pan
talla el siguiente mensaje, y luego se marcar la lnea que produjo la ocurrencia.
Microsoft Development Environment
,\

An unbandied exceptlon of type 'System.FormatException' occuned in


mscorlib.dll
Addibonal nforaatlon; Input string was not in a corred (ormat.

Bieak ~~lj

|[

Continu

!ov-

Help

Figura 2. Oops! Algo sali mal.

Si, en cambio, estamos ejecutando la aplicacin externamente, veremos:


Manejo de excepciones
An unhandled exception has occutred in yout app'ication. If you click
Conlinue. Ihe appcalion wl ignore Ihis error and altempt lo continu.
II you click Quit, Ihe appcalion witl be shut down immedialely.
Input string was no! in a corred formal.

raSs

Continu

S.uit

Figura 3. stas no son buenas noticias.

Lo que ocurri fue que el mtodo esttico ToInt32 de la clase Convert arroj una ex
cepcin. Este es un modo de avisarnos que algo sali mal, por lo tanto deberamos
hacer algo al respecto o la aplicacin no podr seguir su curso normal.

E Q EXCEPCIONES DE LA LIBRERIA BOL


L a s c la s e s d e la lib re ra B C L a rro ja r n e x ce p cio n e s cu a n d o los p a r m e tro s e n v ia d o s no se a n tos
e sp e ra d o s o cu a n d o se p roduzca a lg n tip o de e vento no esp erad o . S ie m p r e que a lg n m to d o
de e s ta s c la s e s "p u e d a f a lla r ", s e r co n ve n ie n te e n c e r r a r lo en un b lo q u e

u s r .c o d e

try..catch.

285

PROGRAMACIN Cfl

ENCERRAR LAS EXCEPCIONES


Es posible capturar las excepciones que puedan arrojar los diversos mtodos que in
voquemos. Para esto deberamos encerrar el cdigo que podra arrojar la excepcin
en un bloque try..catch. Veamos:
try

{
num = Convert.ToInt32(txtNum.Text);

: }
catch

'{
Me8sageBox.Sbow(,,Se ha producido una excepcin");

ste es el modo ms bsico de manejar una excepcin. Ahora, si se llega a producir

alguna dentro del cdigo del bloque try, el flujo de ejecucin saltar automtica
mente a la primera lnea del bloque catch. Luego, la ejecucin del programa conti
nuar normalmente, si es que no establecemos lo contrario.

Figura 4. Izquierda: no se produce excepcin. Derecha:


se produce una excepcin, por lo que se ejecuta el cdigo del catch.

Es cierto que tambin podramos realizar las verificaciones del caso para evitar que
pueda producirse una excepcin. Es decir que en el caso anterior podramos haber
286

u s r .c o d e

Clases de excepciones

verificado que el texto por convertir contuviera slo nmeros. Sin embargo, estas
verificaciones terminan agregando cdigo que siempre ser ejecutado y no nos ase
gura que, de todos modos, se produzca la excepcin por alguna verificacin que he
mos olvidado o que ni siquiera pueda realizarse.
Adems, de este modo se mezclara el cdigo relacionado con la lgica del progra
ma con el cdigo asociado al manejo de errores. En cambio, utilizando un bloque

try..catch se diferencia a simple vista cul es el objetivo de cada trozo de cdigo.

CLASES DE EXCEPCIONES
Hemos logrado capturar una excepcin arrojada por un mtodo, encerrando su in
vocacin dentro de un bloque try..catch.
Pero qu fue lo que ocurri? Qu produjo el error? Qu le informamos al usua
rio? Existe ms informacin que podremos obtener al respecto; el bloque catch pue
de recibir un objeto de algn tipo de excepcin.
Rehagamos nuestro ejemplo y veamos que podremos ofrecerle al usuario no slo la
indicacin de que algo ha fallado.
try

{
num = Convert.ToInt32(txtNum.Text);

u s r .c o d e

287

PROGRAMACIN C#

catch {PormatBxception fe]

U{
:

MesaageBox.Show(fe.Ma3sage);

Ahora, si se produce una excepcin, en el cuadro de texto no habr un mensaje ge


nrico, sino informacin un poco mis especfica de lo que ocurri:

Input string w not in a corred format.

Figura

6. Enviando a un cuadro de mensaje

informacin de la excepcin capturada.

Las clases de excepcin en .NET descienden de la clase Exception, la cual ofrece un


conjunto de propiedades y mtodos que nos ayudarn en la obtencin de mayor in
formacin y en un mejor tratamiento de la ocurrencia que gener la excepcin.
Existen muchas clases descendientes de

Exception.

En el siguiente diagrama se

encuentran detalladas algunas de ellas:

Figura 1. El diagrama de excepciones del framework .NET.

288

u s r .c o d e

Clases de excepciones

En caso de que se produzca una excepcin del tipo FormatExeption, podremos cap
turarla especificando como parmetro un objeto del tipo FormatExeption o un ob
jeto de tipo superior (como, por ejemplo, el objeto SystemException).
Por lo tanto, el siguiente cdigo tambin ser vlido:
try

{
num = Convert.ToInt32(txtNum.Text);

}
catch (SystemSxception se)

''

{
KessageBox.Showfse.Meesage);

o incluso:
try

{
num o Convert.ToInt32(txtNum.Text);

}
catch (Bxception ex)

{
MessageBox,3how(ex.Message);

La idea de este sistema cobra sentido cuando comprendemos que pueden existir
mltiples bloques catch por cada bloque try, y el flujo de ejecucin se desviar al
que corresponda segn la excepcin generada.

5 3 CONOCER EL TIPO DE EXCEPCIN


Los nombres de las clases de excepcin predefinidas son muy elocuentes, por lo que podremos
intuir qu tipo de excepcin es arrojado en cada caso. Luego podremos consultar la documenta
cin de la librera BCL (incluida con el fram ework SDK y Visual Studio .N E T ) . Lo difcil ser en
tender lo que nos arroje el fram ework .NET cuando la excepcin se produzca por primera vez.

u s r .c o d e

289

PROGRAMACIN C#

Supongamos el siguiente ejemplo:


int nua, ras;
try

'

'

nua Convert.ToInt32(txtNum.Text)}
res. * 5 / num;

}
catch (PormatException fe)

: {
// Tratamiento de la excepcin de formato

Si se produce una excepcin de formato (haba texto dentro de txtNum.Text), sta se


r tratada por el bloque catch que especificamos. Pero qu ocurre si num es igual a ce
ro? Tambin se producir una excepcin, pero no de tipo formato, sino de tipo divi
sin por cero, y nuestro bloque catch no la aceptar, por lo que estaremos como en
el caso inicial (sin tratar excepciones) y la ejecucin de nuestra aplicacin se detendr.
Entonces, estamos ante dos posibles soluciones:
Especificamos una clase ms general en el tipo de objeto que recibe catch para que
sta abarque los dos casos.
Creamos otro bloque catch con la clase de excepcin que corresponda.
La primera parece buena idea, pero parte de la gracia aqu est en poder especificar
diferente cdigo para cada una de las ocurrencias que se podran suscitar ante un
error, es decir que si existiera una excepcin de formato, querramos ejecutar cierto
cdigo, y si existiera una excepcin de divisin por cero, querramos ejecutar otro.
Entonces veamos cmo implementar nuestra segunda opcin:

lili

IDENTIFICADORES DE OBJETOS DE EXCEPCIN

El identificador con el cual declaremos el objeto de excepcin es totalmente arbitrario. En los


ejemplos usamos se o ex simplemente porque son cortos. De todos modos, dicho objeto slo se
r vlido dentro del bloque catch para el cual fue declarado, y no deberan ser muy extensos en
cantidad de lneas, por lo que no existe la necesidad de crear un identificador superexpresivo.

290

u s r .c o d e

Clases de excepciones

int nun, res;


try
num Convert.ToInt32(txtNum.Text);'
res = 5 / num;
catch (FormatExcepticn fe)

// Tratamiento de la excepcin de formato


catch (DivideByZeroException dbze)
U

Tratamiento de la excepcin divisin por cero

Ahora, en funcin de lo que ocurra, el flujo de ejecucin se dirigir a un lugar o a otro.


Podremos especificar tantas ramas catch como tipos de excepciones queramos cap
turar; con la nica restriccin de no poder especificar un catch con una clase de ex
cepcin que sea base de la clase de excepcin de otro catch que se encuentre deba
jo de el. Expresado de otro modo, sabemos que FormatException desciende de Ex

ception.

Siempre deberemos ir en un sentido de

ms especfico a m s general.

Por lo tanto, el siguiente cdigo no es vlido:


int num, res;
try
num = Convert.ToInt32(txtNum.Text);
res = 5 / num;

}
catch (Exception ex)

{
// Tratamiento de la excepcin

}
catch (FormatException fe)

// ;Error!

// Tratamiento de la excepcin de formato

PROGRAMACIN Ctt

En cambio, el siguiente s lo es:

catch (FormatException e)

// Tratamiento de la excepcin de formato


catch (Exception ex)

// Tratamiento de la excepcin

Tambin podremos especificar un bloque finally, el cual se ejecutar siempre, ocu


rra o no ocurra excepcin.

Figura 8. El c d ig o d e n tro d e l b lo q u e f in a l ly se e je c u ta sie m p re .

292

u s r .c o d e

Clases de excepciones

En el bloque finally se suele colocar cdigo relacionado con la liberacin de recur


sos adquiridos posterior a la ocurrencia de una excepcin.
Por ejemplo, si se ha abierto un archivo dentro del bloque try, es conveniente ce
rrarlo, se haya producido una excepcin o no.
Veamos esto en pseudocdigo:
try

{
Abrir archivo

}
catch (AlgunaExcepcin el)

{
Tratamiento de excepcin el

}
catch (OtraExcepcin e2)

{
Tratamiento de excepcin e2

}
finally

{
Cerrar archivo

De este modo, si se suscita una excepcin o no, igual se ejecutar el cdigo corres
pondiente al finally.
Claro que usted podr pensar: pero... podra cerrar el archivo luego de todo el blo
que try..catch? Para comprender la respuesta a este interrogante deberemos estudiar
un tema ms: el arrojo de excepciones por medio de la sentencia throw.

[ J [ | REGLAS DE LOS BLOQUES CATCH


Pueden poseer tantas lneas de cdigo como se requiera Ipero es una buena prctica mantener
los breves). Slo se acepta un catch sin especificacin de clase de excepcin. Cada catch puede
tratar slo un tipo de excepcin. Las clases ms especificas de excepcin deben ir primero.

u s r .c o d e

293

PROGRAMACION C#

GENERAR EXCEPCIONES
Nuestros objetos tambin podrn generar excepciones. Si verificamos en el cdigo
alguna de nuestras funciones, podremos informar al mtodo invocante que, por
ejemplo, un parmetro no es vlido. Para esto, se utiliza la sentencia throw.
Veamos un ejemplo. Supongamos que creamos un mtodo que opera con un par
metro entero que debe ser impar. Si el mtodo verifica que el nmero recibido no
es impar, podra arrojar una excepcin al mtodo invocante que informe esto.
prvate void Calcula(int num)

{
// Verifico que el nmero sea impar
if (num % 2 as 0)
throw new FormatException(HEl nmero debe ser impar*);
// Si sigo aqu es porque el nmero ES impar
//

...

En este caso, la sentencia throw ir acompaada por el objeto del tipo excepcin que
mejor se adapte al tipo de error que ha ocurrido. Tambin podramos crear nuestra
propia subclase de alguna excepcin existente si lo considerramos conveniente
(SystemException, FormatException, etc.).
Cuando se ejecuta el throw, se abandona el mtodo y se produce la excepcin.
Tambin es habitual que cuando se produce una excepcin, sta sea tratada y luego
transferida al mtodo superior;
int num, res;

try
{
num = Convert.ToInt32(txtNum.Text);
res = 5 / num;

}
catch (FormatException fe)

{
// T ra ta m ie n to de l a e x ce p ci n de fo rm ato

...

throw f e ;

294

u s r .c o d e

Generar excepciones

Ahora s podemos volver al caso del

finally.

Por qu no era conveniente cerrar el

archivo despus de todo el bloque try..catch? Porque si se transfiere la excepcin ha


cia el mtodo invocante, el cdigo del

finally

es ejecutado antes de abandonar el

mtodo, mientras que el cdigo posterior al bloque try..catch no.

Figura 9. A pesar de existir un throw previo al finally,


ste es ejecutado antes de abandonar el mtodo.

En el caso de que hubiramos colocado el

cerrar archivo

inmediatemente despus

del bloque try..catch, ste habra quedado sin ejecutar.

EL CDIGO DENTRO DE LOS BLOQUES TRY Y CATCH

En ambos bloques, la cantidad de lneas de cdigo que pueden contener no se encuentra limita
da. Sin embargo, es una buena prctica mantenerlos breves,

u s r .c o d e

295

PROGRAMACIN C#

CREAR NUESTRAS PROPIAS CLASES


DE EXCEPCIN
Para crear nuestras propias clases de excepciones, simplemente debemos heredar de
alguna excepcin del tipo SystemException o descendiente de sta.
Volviendo al ejemplo del nmero impar, podramos pensar que FormatException tal
vez 110 fuera el tipo de excepcin ms adecuado para describir lo que ha ocurrido.
Por lo tanto, podramos crear la siguiente clase:
public clasa NumlmparException : FormatException

{
public NumlmparException{) : base(*El nmero no es impar.")

}
public NumlmparException(string atrErr) : base(strErr)

{
}
}

En este caso se permite construir el objeto haciendo uso del mensaje predetermina
do o personalizando el mensaje que ser enviado.
Para arrojar la excepcin ahora podramos escribir:
private void Calcular(int num)

{
if (num % 2 a* 0)

throw new NumlmparException();

ii

...

Y sta podra ser atrapada escribiendo:


try

{
int num = Convert.ToInt32(txtNum.Text);

296

usr.code

Crear nuestras propias clases de excepcin

Calcular(num);
catch (NumlmparException nie)
MesBageBox.Show(nie.Mesaage);

catch (Exception ex)


MessageBox.Showex.Meseage);

RESUMEN
El manejo de excepciones es un poderoso sistema para especificar cmo debe comportarse
nuestro programa cuando se produce algn evento no previsto. En el captulo siguiente anali
zaremos ms aspectos avanzados del lenguaje, entre ellos, uno de los ms interesantes y
atractivos de todos: Reflection.

u s r .c o d e

297

fflj

ACTIVIDADES

TEST DE AUTOEVALUACIN
1 Por qu es mejor utilizar el sistema de ex

U Qu ocurre si colocamos un catch de una

cepciones que el clsico sistema de errores

excepcin ms general por encima de una

retornados como valor de una funcin?

excepcin ms especifica?

2 Existe alguna desventaja del sistema de


excepciones respecto al clsico pasaje de
cdigo de error por retorno de funcin?

3 Cuntos catchs podra poseer un bloque


try.xatch?
a. Cero o ms.
b. Uno solo.
c. Uno o ms.
d. Ms de uno.

5 Cuntos catch sin parmetros son acepta


dos en un bloque try.xatch? Existe- alguna
regla que imponga su/s posicionamiento/s?

298

u s rx o d e

PROGRAMACIN C#

Captulo 1 0

Caractersticas
avanzadas
del lenguaje
En este captulo ingresaremos
en los aspectos ms avanzados
con los que cuenta el lenguaje.
Qu es el boxing/unboxing, qu son
y para qu se utilizan los atributos,
qu es Relection y cmo acceder
a libreras creadas en otros lenguajes.

Boxing/Unboxing
Atributos

300
301

Atributos predefinidos
Consultar tos atributos
en tiempo de ejecucin
Reflection

305
306
307

Ejecutar mtodos de tipos


desconocidos
Acceso a otras libreras
Punteros
SERVICIO DE ATENCIN AL LECTOR: le C to r e S @ m p e d C 0 n e S .C 0 in

308
311
313

Resumen

315

Actividades

316

PROGRAMACIN C#

BOXING/ UNBOXING
Boxing es un proceso implcito que consiste en la insercin de un tipo de dato por
valor en un objeto. Esto ocurre cuando se espera una referencia pero se provee un
valor, entonces el framework automticamente crea un objeto al vuelo, coloca di
cho valor dentro de l y luego pasa la referencia a quien la esperaba.
int num = 10;
object obj = num;

El proceso contrario al Boxing es denominado Unboxing, y en contraposicin al pri


mero, ste debe ser explcito.
Para esto deberemos estar seguros de que dentro del objeto existe un tipo de dato
por valor encerrado. Luego podremos escribir:

PRECAUCIONES CON BOXING/UNBOXING

Si estamos realizando una aplicacin de alto desempeo, ser importante conocer cundo

se

realiza este tipo de operaciones implcitas, debido a que consumen algunos ciclos extra de CPU,
especialmente, en zonas crticas como los bucles internos.

300

u s r .c o d e

Atributos

int num = (int) obj;

Si acaso intentramos realizar un unboxing de un objeto que en realidad no posee


un tipo de dato por valor encerrado dentro de l, entonces la plataforma arrojara
una excepcin del tipo InvalidCastException.

ATRIBUTOS
Los metadatos son datos acerca de los datos. C# ofrece un sistema para insertar metadatos en nuestros assemblies mediante atributos.
Un atributo simplemente se define por medio de una clase descendiente de System.
Attribute. Es bastante frecuente que el nombre que poseen estas clases descendientes

III

USO DE LOS ATRIBUTOS

Los atributos nos permiten fijar informacin de las estructuras que posee nuestro programa. Es
to podra ser til en muchos casos y, en particular, cuando nuestros programas sean inspeccio
nados mediante Reflection (tema que veremos un poco ms adelante en este mismo captulo).

usr.code

301

PROGRAMACIN C#

termine en Attribute (como por ejemplo;


trata de una regla obligatoria.

CualquierNombreAttribute),

aunque no se

Luego, a nuestra clase de tipo atributo podremos agregarle propiedades, pero por el
momento analicemos un ejemplo bien sencillo:
f clase CualquierNombreAttribute : Attribute

{
}

De esta manera, hemos creado un atributo llamado

CualquierNombreAttribute.

continuacin veremos la manera de utilizarlo;


[CualquierNombreAttribute] c la sa Poo

{
}

O .simplemente:
[CualquierNotnbre] clasB Poo

{
}

Estos dos ltimos listados de cdigo son equivalentes, ya que el compilador permi
te simplificar el nombre del atributo quitando el Attribute detrs de l.
Tambin podramos agregar atributos a mtodos, enumeradores, propiedades,
eventos, etc. No obstante ello, un atributo especfico podra restringir su rango
de aplicacin por medio de un parmetro de tipo

AttributeUsage

AttributeTargets

del atributo

a la definicin de nuestra clase atributo.

MS ACERCA DE LOS ATRIBUTOS

En la documentacin oficial que acompaa a Visual Studio .NET podremos encontrar ms infor
macin sobre el uso de los atributos. Tambin podremos acceder a dicha informacin online des
de http://m sdn.m icrosoft.com /library/en-us/csref/htm l/vclrfintroductiontoattributes.asp.

302

u s r .c o d e

Atributos

[Attributesaga(AttributeTargeta.Class)]
public class CualquierNombreAttribute: Attribute

{
}

Ahora, nuestro atributo

CualquierNombre slo es aplicable a clases.

Tambin es posible combinar los AttributeTargets para hacer el atributo aplicable a


ms de un elemento:
[Attributesage(AttributeTargets.Class | AttributeTargets.Method)]
public class CualquierNombreAttribute: Attribute

{
}

Nuestro atributo

CualquierNombre

ahora es aplicable a clases y mtodos.


PUEDE PRECEDER A

All

Definiciones de cualquier elemento.

Assembly

Definiciones de assemblies.

Class

Definiciones de clases.

Constructor

Definiciones de mtodos constructores.

Delegate

Definiciones de delegados.

Enum

Definiciones de enumeradores.

Event

Definiciones de eventos.

Fietd

Definiciones de campos.

Interface

Definiciones de interfaces.

Meiod

Definiciones de mtodos.

Module

Definiciones de mdulos.

Parameter

Definiciones de parmetros.

Property

Definiciones de propiedades.

RetuinValue

Definiciones de valores de retomo.

Struct

Definiciones de estructuras.

Tabla 1. Posibles valores de AttributeTargets.

En las circunstancias donde estamos imposibilitados de determinar a qu elemento


se debe aplicar el atributo, es posible indicarlo de modo explcito. Para ello debemos
anteponer el nombre del elemento al nombre del atributo, como podemos observar
en el siguiente diagrama de sintaxis:
u s r .c o d e

303

PROGRAMACIN C#

/ El el*nemc al ?ue aptai loobwns

el cofnpilawpo( comcco

ewm ^

meihod

^ module ^

lefrtrficattor

do attflKo

O
/7\ >1porm
ofro
y'Jrr^ poiipofui

- O

t(Q\

Es posible especificar el elemento que aplica de modo explcito


o esperar a que el compilador lo obtenga por contexto
(aunque en ciertas ocasiones no puede hacerlo por existir ambigedades).
Figura 3.

A continuacin, agregaremos a nuestro atributo una propiedad capaz de ser fijada


por medio del constructor:
[AttributetJsage(AttributeTargets.Clase)]
public class CualquierNcrabreAttribute: Attribute

{
prvate string valor;
public CualquierNombreAttribute(string v) { valor = v; }

Y podremos utilizarlo del siguiente modo:


[Cualquieriombre"prueba")) class Foo
{
}

304

u s r .c o d e

A tributo?.

Tambin podramos definir una propiedad pblica, al igual que en cualquier clase:
(Attributesage (AttributeTargets.Class))
public class CualquierNcxnbreAt tribute: Attribute

{
private string valorl;

private string valor2;


public CualquierNombreAttribute(string v) { valorl = v; }

public string OtroValor

{
set { valor2 = valu; }
get '{ return valor2;

}
}

Y luego modificar su valor del siguiente modo:


[CualquierNombre(prueba", OtroValor=''otra prueba')] public class Foo

{
}

Atributos predefinidos
El framework .NET ofrece una serie de atributos predefinidos que pueden ser muy
tiles en la creacin de nuestros programas.
APLICABLE A

DESCRIPCIN

Conditonal

Mtodo

En funcin de la evaluacin de lo expresado en el atributo, se ejecuta

Dlllmport

Mtodo

1 NOMBRE DE ATRIBUTO

o no el mtodo relacionado.
Indica que el mtodo se encuentra definido dentro de una librera de enlace
dinmico con cdigo no gestionado por la plataforma .NET.
Obsolete

Mtodo

Permite marcar un mtodo como obsoleto.

Tabla 2. Algunos atributos predefinidos generales.

Ejemplo de atributo condicional:


public class Foo

u s r .c o d e

305

PROGRAMACIN C#

[Conditional("DEBUG")]
public static void EjecutaEnDebugO

{
MegsageBox.ShowCEjecucin de mtodo EjecutaEnDebug");

}
}

El atributo

Conditional verificar si la constante de compilacin condicional expre

sada se encuentra definida, y slo de ser as se ejecutar el mtodo relacionado.


La constante DEBUG es definida por el entorno slo cuando la compilacin se reali
za en modo depuracin. Si ahora escribimos:
Foo.Ej ecutaEnDebug();

Dicho mtodo slo se ejecutar realmente si el proyecto fue construido en modo


dicha lnea no formar par

Debug. Si, en cambio, fue construido en modo Release,


te del programa final.

Consultar los atributos en tiempo de ejecucin


Hasta el momento nos hemos dedicado a explicar cmo crear nuevos atributos y
cmo utilizarlos, aunque todava no se ha evidenciado su verdadero poder o real uti
lidad. La informacin de los atributos que especifiquemos dentro de un assembiy
podr ser consultada por un programa (disponible en el mismo assembiy o en otro),
el cual podr modificar su flujo de ejecucin en funcin de la informacin que en
cuentre dentro de los atributos.
De este modo, y por dar un ejemplo, podramos marcar qu mtodos deberan ser
invocados bajo determinadas condiciones en cierto componente, sin que el assembiy
que utilice el componente conozca de antemano los nombres de los mtodos por in
vocar ni su cantidad.
Tambin podramos ofrecer informacin transaccional de los objetos de un compo
nente o informacin de utilidad al usuario, que por medio del uso de un sistema,
pretenda utilizarlo dinmicamente.

Para poder acceder a esta informacin deberemos utilizar lo que en la plataforma


.N ET se conoce como Reection.
306

u s r.c o d e

Reflection

REFLECTION
Reflection es un sistema que permite analizar el contenido de un assembly en tiem
po de ejecucin. Este sistema bsicamente se utiliza para:
Analizar la informacin de atributos.
Descubrir nuevos tipos de datos e interactuar con ellos. De este modo podemos
utilizar desde nuestro programa objetos desconocidos, listando sus propiedades,
mtodos, eventos, etc.
Crear nuevos tipos en tiempo de ejecucin.
Para consultar por la informacin de atributos que posee un assembly, deberemos:
1. Obtener una referencia al assembly que deseamos inspeccionar.
2. Listar los mdulos que posee el assembly.
3. Listar los tipos (clases, interfaces, etc.) que posee cada mdulo.
4. Listar los atributos que posee cada tipo (con la posibilidad de solicitar todos o el
atributo del tipo especfico que estamos buscando).
// Obtengo ana referencia al assembly en ejecucin
Assembly asse = Assembly.GetRxecutingAssemblyO;

// Recorre todos los mdulos del assembly


foreach (Module modulo in asse.GetModuleaO)

// Recorro todos los tipos del assembly


foreach (Type tipo in modulo.GetTypes())

{
// Muestro en un cuadro de texto, el nombre del tipo actual
txtLog.Text = txtLog.Text +
String.Formatf'Tipo: {0}\r\nB, tipo.FulIName);

// Obtengo todos los atributos del tipo creado previamente


//por nosotros
CualquierNombreAttribute[) atts = (CualquierNombreAttribute[])
tipo.GetCustomAttributes(
typeof(CualquierNombreAttribute),
false);

Recorro todos estos atributos

foreach(CualquierNombreAttribute cna in atts)

// Muestro en el cuadro de texto la


// propiedad "OtroValor" del atributo

{
u s r .c o d e

307

PROGRAMACIN C#

txtLog.Text = txtLog.Text +
String.Pormat(" + Valor de atributo: {0}\r\n",
cna.OtroValor);

Ejecutar mtodos de tipos desconocidos


Mediante Reflection podremos conocer tipos nuevos en componentes cargados dinmi
camente. Tambin podremos invocar a voluntad mtodos de estos tipos desconocidos.
Para ejemplificar esto, observemos una pequea aplicacin que permite cargar un
assembly seleccionado por archivo, luego de lo cual inspecciona y ofrece sus mdu
los, tipos y mtodos con el fin de que el usuario pueda seleccionar, finalmente, qu
mtodo invocar. Cargando el assembly:
dlgAbrirArchivo.Title = "Abrir assembly';
dlgAbrirArchivo.Filtar = "Assembly (*.dll)|*.dll";
if (dlgAbrirArchivo.ShowDialogO

DialogResult.OK)

{
txtAasambly.Text a dlgAbrirArchivo.FileName;
BuscarModulos(dlgAbrirArchivo.FileName)?

Aqu obtenemos el nombre del assembly seleccionado a travs de un dilogo de


apertura de archivo, e invocamos el mtodo BuscarModulos:
private void BuscarModulos(string nombreA86embly)

[ I EL ESPACIO DE NOMBRES SYSTEM.REFLECTION


Para poder utilizar tas clases Assembly y Module ser conveniente agregar la linea using System,
Reflection junto a las otras directivas using al comienzo del archivo de cdigo fuente.

308

usr.code

Reflection

Assembly asse Assembly.LoadFile(nombreAssembly);


if (asse != nuil)

// Se ha cargado el assembly correctamente


// Cargo los mdulos
mdulos asae.GetKodulesO?
IsbModulos.Items.Clear();
foreach(Module m in mdulos)
IsbModulos.Items.Add(m.Mame

);

}
}

Utilizamos el mtodo esttico LoadFile de la clase Assembly para cargar un assembly


y obtener una referencia a l.
Luego, por medio del mtodo GetModules del objeto assembly cargado, obtendremos
todos sus mdulos, que colocaremos en una lista para que el usuario pueda seleccio
nar de qu mdulo listar los tipos.
Para listar los tipos de un mdulo escribiremos:
prvate void lsbModulos_SelectedIndexChanged(object sender,
System.EventArgs e)

{
if (mdulos.Length > 0)

{
tipos = nodulos[IsbModulos.Selectedlndex] .GetTypesO ;
if (tipos.Length > 0)

{
IsbTipos.Items.Clear() ;
foreach(Type t in tipos)
IsbTipos.Items.Add(t.ame);

}
}
}

Por medio del mrodo GetTypes del objeto mdulo seleccionado en la lista, obten
dremos todos los tipos que insertaremos dentro de otra lista.
Ahora, finalmente slo nos resta listar los mtodos del tipo seleccionado y colocar
los en otra lista. Para esto deberemos escribir en el cdigo:
u s r .c o d e

309

PROGRAMACIN C0

private void IsbTiposJSelectedlndexChanged(object sender,


System.EventArgs e)

{
if (tipos.Length > 0)

{
mtodos s tiposUsbTipos.Selectedlndex] .GetMathodsO;
labMetodos.Items.Clear();
foreach(MethodInfo minfo in mtodos)
1sbMetodos.Items.Add(minfo.ama);

}
}

El usuario, entonces, se encontrar posibilitado de elegir el mtodo que desee y pre


sionar el botn Invocar...:
private void cmdlnvocarClick(object sender, System.EventArgs e)

{
Methodlnfo ms = tipos[lsbTipos.Selectedlndex]
GetMethod(nombreHetodoInvocar);
if (ms != nuil)

{
try

{
ms.Invoke(null, nuil);

}
catch(Exception se)

{
MessageBox.Show(se.Message);

}
}
else
MessageBox.Show('No es posible encontrar el mtodo
especificado");

La nica restriccin que presenta nuestro ejemplo es que solamente est posibilita
do para invocar mtodos estticos que no posean parmetros (situacin que podra
modificarse de manera bastante sencilla). De otro modo se producir una excepcin
que luego se mostrar en un cuadro de texto.

310

u s r .c o d e

Acceso a otras libreras

Invocacin de Mtodos usando Reflection

fx

A^semUy a nspecoorwr
[E7YuseTs\d>&go\kbro CS\code-cap9\ReftectKnApp!\t>n\D6

Moddos de! Asimbi/

Mtod

ra n H H H H n a W a

IMtodo:
Metodo
Mtodo^
|Mtodo?

~
*:
In.'o;ar mtodo de componerte

Figura 4. Nuestro pequeo ejemplo en accin.

ACCESO A OTRAS LIBRERAS


Es posible acceder desde un programa .N ET a libreras de enlace dinmico creadas
en otros lenguajes como C. Para esto se debe crear una clase que relacione por me
dio de mtodos estticos a las funciones globales que posee la librera.
Supongamos que dentro de una librera de enlace dinmico, que llamaremos
libcpp.dll, creada en C, disponemos de las siguientes funciones:
extern "C*

LIBCPP_APIvoid fnl(void);

extern *C*

LIBCPP_APIint fn2(void);

extern "C LIBCPP API void fn3(char * pszText) ;

La primera funcin no recibe parmetro y nada retorna. Cuando es invocada mues


tra un cuadro de texto con informacin arbitraria.
La segunda funcin no recibe parmetros pero devuelve un nmero entero. Cuan
do es invocada devuelve una constante arbitraria.
La tercera funcin recibe un char*, que deber ser un arrav de caracteres de un byte terminado en \0 (convencin de strings en lenguaje C). Cuando es invocada,
muestra un cuadro de texto con la informacin pasada como parmetro.
u s r .c o d e

311

PROGRAMACIN C#

Ahora observemos, en el siguiente cdigo, cmo debe ser nuestra clase en C # para
permitirnos el acceso a la librera.
using System;
using System.Runtime.InteropServices;
public class LibCpp

{
[Dlllmport("libcpp.dll", CharSet=CharSet.Auto, SetLaBtError=true)]
public static extern void ful();
IDllImport(,'libcpp.dll'
, CharSet=CharSet.Auto, SetLastError=true) ]
public static extern int fn2();
[DlllmportClibcpp.dll'
, CharSet=CbarSet.Auto, SetLastError=true)]
public static extern void fn3(byte[J pszTsxt);

La clase en cuestin posee un mtodo esttico por cada funcin mapeada. Cada uno
de estos mtodos posee un atributo preestablecido por el framework que nos per
mite relacionar la funcin con la librera.
Cada mtodo debe poseer el mismo prototipo que la funcin en C que deseamos
invocar. Es decir que debemos mapcar los tipos de datos a los que mejor se adapten
en lenguaje C#. Si uno de dichos parmetros es una estructura, podremos declarar
una anloga en C#, pero siempre deberemos tener en cuenta que en memoria las
variables internas de la estructura deben mapearse exactamente igual (hay que tener
mucho cuidado con la alineacin de los miembros de la estructura).
Hecho esto, las funciones podrn ser utilizadas como si fuesen nativas.
Invocar la primera funcin:
LibCpp.fni () ;

Invocar la segunda funcin:


// Invoco la funcin
int num = LibCpp.n2() ;
txtRetorno.Text = num.ToString);

Invocar la tercera funcin:


312

u s r .c o d e

Punteros

// Paso de strina a un array de caracteres de l byte

bytef] txt s new byte[txtParam.Text.Length + 1);


for (int i=0; i<txtParam.Text.Length i++)
txt [i] * (byte) txtParam.Text[i] ;
txt(txtParam.Text.Lengthl = (byte) '\0';
// Invoco la funcin
LibCpp.fn3(txt);

3 Fundones deOLLs

Invocw funcin 1

Invocar funcin 2
Valor de retorno

1
Parmetro tpo string
Eite es el mensaje de texto a posar
|

Invocar funcin 3

Figura 5. Nuestro ejemplo en accin.

PUNTEROS
Un puntero es una variable que posee como valor una direccin de memoria asig
nada y desasignada explcitamente.
Este tipo de recursos es muy utilizado en los lenguajes de programacin C y C++,
debido al inmenso poder que otorgan, pero poseen una importante desventaja: es
fcil cometer errores en su manipulacin.
Los tipos de errores ms comunes son:
Errores de lectura o escritura en zonas de memoria no permitidas: si intenta
mos leer o escribir memoria que no nos pertenece, Windows, en forma preventi
va, cerrar inmediatamente nuestra aplicacin. este error se lo conoce como
error de proteccin general .
Errores en la desasignacin de memoria: si no liberamos la memoria de un modo
correcto, entonces un sector de sta quedar tomado por nuestra aplicacin pero no

ser utilizado (;memory leak). Si este error se comete repetidas veces en una aplicacin,
tarde o temprano se consumir todo el recurso de memoria de la plataforma.
u s r .c o d e

313

PROGRAMACIN C#

Por oiro lado, estos tipos de errores suelen ser muy difciles de extraer. Es por ello
que C#, al igual que Java, incorpor un gestor automtico de memoria para evitar
le al programador esta tediosa tarea.
Pero C# ofrece la posibilidad de utilizar punteros, si lo solicitamos explcitamente.
Para esto debemos hacerlo en un contexto no seguro (encerrado de un bloque unsafe); adems, deberemos modificar una opcin de nuestro proyecto para permitir
cdigo no seguro, y tambin debemos tener en cuenta que ciertas plataformas po
dran no permitir la ejecucin de aplicaciones con cdigo no seguro en su interior.
La operacin con punteros es algo diferente del manejo de variables convenciona
les. Observemos la tabla que se incluye a continuacin.

El operador & permite obtener la direccin de memoria donde se encuentra alojada la variable relacionada.

0 operador * permiteacceder al valor apuntadopor un puntero.

->_ _ _ _ _ _ _ _ _ _ El operador -> permite acceder a los miembros de una clase o estructura apuntada por un puntero.
Tabla 3. Manejo de operadores en los punteros.

Veamos un pequeo ejemplo del uso de punteros en C#:

int * pNum;

pNum

pNum
numl

int numl, num2;

num2

pNum
numl

numl = 10;

10

num2

pNum

numl

10

num2

10

pNum = Snuml;
314

u s r .c o d e

P u n te ro s

pNum

num2 = *pNum;

numl

10

num2

10

Otra de las precauciones que debemos tener en cuenta a la hora de trabajar con
punteros se encuentra relacionada con la gestin automtica de memoria que po
seen los elementos a los cuales apuntamos con los punteros.
Si el framework .NET entiende que una variable queda fuera de alcance, podra
querer reutilizar la memoria que sta ocupa, y de este modo, invalidar tal vez algn
puntero que la estaba utilizando.
Para evitar esto se utiliza la sentencia fixed de la siguiente manera:
int[] nums a new int [10];
fixed (int * pNum = nums)
:

{
//
}

De este modo prevenimos al framework .NET de reutilizar memoria con la cual


an estamos trabajando.
Los punteros no son muy populares en C#. A decir verdad, raramente veremos que
se utilicen ms all de la necesidad inevitable por interactuar con componentes no
gestionados que esperen punteros.

I.L -U I ILII
En este captulo hemos analizado algunas de las caractersticas ms avanzadas que posee el
lenguaje. Las posibilidades que nos brinda el mecanismo de Reflection son enormes. Muy f
cilmente podramos incorporar a nuestro programa un sistema de scripting por medio del cual
el usuario pudiera extender las funcionalidades de la aplicacin (por ejemplo, como si fueran
macros de Microsoft Word), y todo utilizando C#, lo que permitira, sin esfuerzo alguno, que
se instanciaran clases de nuestro sistema. Por otro lado, la posibilidad de utilizar libreras
creadas en otros lenguajes es una caracterstica que muchos programadores C/C++ aplaudi
rn, ya que podrn reutilizar aos de trabajo; incluso podran decidir realizar ciertas tareas
crticas en C mientras que todo el front-end de la aplicacin se ejecutara en C#.

usr.code

315

ACTIVIDADES

TEST DE AUTOEVALUACIN
1 Cules son las ventajas y las desventajas
de Boxing/Unboxing?

3 Es posible instanciar objetos desconoci


dos de un assembly cargado en tiempo de
ejecucin?

U Qu precauciones se deben tener en


cuenta en el mapeo de tipos de datos hacia
libreras externas?

5 Por qu se desaconseja el uso de punte


ros C# y, sin embargo, se ofrece la posibi
lidad de utilizarlos?

2 Cuando creamos una aplicacin de tipo


Windows Application con Visual Studio
.NET, dnde puede apreciarse el uso de
atributos?

316

u s r .c o d e

PROGRAMACIN C#
i_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

Captulo 1 1

Servicios web
Los servicios web son uno de los aspectos
de la plataforma que ms han crecido
en popularidad en ios ltimos tiempos.
Si bien no son una caracterstica exclusiva
de NET, Microsoft iia impulsado mucho
esta tecnologa y ha hecho un gran trabajo
en facilitar la tarea de su construccin
y utilizacin desde su entorno
de desarrollo. Veremos aqu de qu trata
esla tecnologa y cmo podremos
utilizarla desde nuestro querido

C t .

Qu son los servicios web?

318

Servicio de bsqueda de Google 318


Crear un servicio web
327
Resumen
331
SERVICIO DE ATENCIN AL LECTOR:

Iect0res@mpedici0nes.com

Actividades

_ _ _ _ _ _ 332

PROGRAMACIN Cfl

QU SON LOS SERVICIOS WEB?


Los servicios web

(web Services)

permiten crear aplicaciones distribuidas colocando

objetos en distintos puntos de la Red que publiquen servicios, que luego otras aplica
ciones puedan consumir de una manera muy sencilla y, prcticamente, transparente.
Estos servicios, adems, permiten originar arquitecturas no dependientes de la pla
taforma, ya que se basan en protocolos abiertos. Una aplicacin .NET podra estar
consumiendo servicios creados en Java, o viceversa.
Un servicio posee asociada una direccin que identifica al recurso en la Red y pro
vee una descripcin de su interfaz, por medio de la cual los clientes pueden cono
cer los mtodos que ofrece dicho servicio.
Crear una aplicacin en .N ET que consuma servicios es muy sencillo. Veamos, por
ejemplo, cmo crear una aplicacin C# que use el servicio de bsqueda de Google.

Servicio de bsqueda de Google


Google (www.google.com) ofrece un servicio web para que podamos realizar bs
quedas (sin fines comerciales, claro) desde nuestros sitios o aplicaciones.
Para poder comenzar a trabajar con l, en primer lugar requeriremos una descrip
cin formal de) servicio. Esta descripcin se especifica en un archivo WSDL.
Descargaremos el A PI (que contiene el archivo WSDL del servicio, documentacin
y aplicaciones de ejemplo) desde www.google.com/apis.
Hecho esto, podremos aprovechar la ocasin y obtener una cuenta Google, que nos
ser requerida para usar el servicio (es un modo de autenticacin que le permite a
Google controlar quin y cmo utiliza su servicio).

III

QU ES WSDL?

WSDL [Web Service Description Language1es un formato estndar para definir servicios web. Se
encuentra expresado en XML, y establece cmo acceder al servicio y qu operaciones se pueden
realizar con l. Enlace relacionado: www.w3.org/TR/wsdl.

318

u s r.c o d e

Qu son los servicios web?

E m a il n d d r e s s :
e.g. m yn3m c @ ex a m p le .co m . This w llb e y o u r u s e m a m e and signin.
P a s s w o rd :
M nim um o l 6 ch ara cle rs n length.
R e -e n te r p a ss w o rd :
W o rd V e riic a tio n :

Type th e c haracters you see in the aicture below.

% N f l9

c h s & c le .'s are n o ! C 9 & ~ 3 9 a 3 itv e

V ie w th e Term s of S eivice & Privacir P olicv .


You m ust accep t the Term s of Service to create a Google
account
I have read and agree to the Term s o Us e. Create m y account.

Figura 1. Los datos que solicita Google


para crear una cuenta son realmente pocos.

Nuestra cuenta nos permitir realizar hasta mil consultas diarias, algo considerado
ms que suficiente para fines personales.
Creada la cuenta Google, nos enviarn por correo una licencia consistente en una
clave alfanumrica de 32 caracteres. Esta clave es importante, ya que nos ser soli
citada cuando deseemos ejecutar una consulta utilizando el servicio web.
Ahora, veamos los pasos que deberemos realizar con Visual Studio .NET para po
der interactuar con el servicio.
Crearemos una aplicacin de tipo Windows
desde el

Captulo 7.

Application, como lo venimos haciendo

Esta aplicacin poseer un solo formulario y, bsicamente, un

control de cuadro de texto (que servir para especificar la consulta), un botn (que
usaremos para ejecutar la consulta) y una lista de visualizacin (donde sern mos
trados los resultados de la consulta).
Pero el paso ms importante y clave que nos posibilitar utilizar el servicio web se
r agregar una referencia web a nuestro proyecto. Por medio de esta referencia, le
indicaremos a Visual Studio .NET el servicio que deseamos utilizar mediante la es
pecificacin de un archivo

WSDL.

Para agregar dicha referencia seleccionaremos la opcin Add


men

Web Reference desde el


Project o desde el men contexta! sobre el panel Solution Explorer:

u s r .c o d e

319

PROGRAMACIN C#

Soluon E.-ptorer - WindowsAp-pBcationl


_______________
3 # Qi

JE S

J Solution 'W indow sA ppfo ationl' (1 p roject)

S-

jHWindowsflpplicationl

S sal ira
l i Pre
reiE------------'y - - -- - -- - 0 APP'K0 I
F ] Assem blj

^ddReference...
A dd W g b R e e r e f K e ,..-

jj
1:

F o r m l.

^'-I4--5View

^ So iu tio riE x ..,| 1 Resouce ...

Figura 2. Agregando una referencia web.

Una vez realizado esto, se abrir una ventana que nos solicitar el ingreso de la ubi
cacin de la descripcin del servicio:
dd Web Referente

1 M

1Ntate toa webservxe URL (dina uvw)and cW. AddP;{traer.*to


c

the Avatabfesetv>c feund

kttw URL.

o 0 a

W i
II
Start Browsing for Web Services

aw
SVebservkwtajnAtthKUfa:

atarI

Use thii page a>a


q pont tomd Web setyk. rou canebektthe
befe*, or tyse oYcotn URL into the odJie.s bor.
Browse to:

machlae

v. * t?.*

b ro w s e UODI S e rv e r s

o n th e lu rni niitv.orl
Quecy yojr loca) netwoikfcr UCCI wver.

.ULQPlPirtv.torjy

Oowy fr.e UC>0! txKfppfii


erv*.es,

to Ir.d cettptrws ar.d proauriion Web

|
i

T est -Microsoft UDDI Din/rtory


Locste test Web Services to use (JUry; de/efefvnere.

Cc!

Hek.

Figura 3. Debemos especificar la ruta de acceso


al archivo WSDL descargado de Google.

El archivo WSDL se encuentra ubicado dentro del paquete que liemos descargado de
Google. Hay que descomprimir dicho paquete y luego especificar la ruta completa
de acceso al archivo en cuestin, luego de lo cual Visual Studio .NET lo leer y en
contrar los mtodos que ofrece el servicio:

320

u s r .c o d e

Q u s o n lo s s e r v i c i o s w e b ?

doGetCachedPage: devuelve una pgina dentro de la cach de Google.


doGoogleSearch: establece una bsqueda por los criterios especificados.
doSpellingSuggestion: realiza una sugerencia de escritura de los trminos enviados.
A d d W e b Reference
I Ntrigste 1c a web *rhce URi (asm* cr w/S) andckfc Add Feortsxc te*jd el

O***-. O

evefatieferoces fand at thal URL.

O 0 !

IPL: |C:\ooglMrh.id

3 So
Vrebjorvxcs round d tm URI:

GoogleSearchService Description

1Service found:
- 'kcgieSearch

Methodv

doGetCachetlJage')
|
doGoogleSearchO
b doSfJcWngSuggetfiun!)

reftrence Qarno:
Webftderence
A d d R e /e re tx e

:
Centd
|

Figura 4. Los mtodos encontrados en el servicio GoogleSearchService.

Si en la ventana mostrada en la figura anterior presionamos el botn Add

Reference,

el entorno de desarrollo crear una clase proxy que nos permitir interactuar con el
servicio como si fuera un componente local, al tiempo que emplea el protocolo SOAP
para dialogar con el servicio web.
Class V iew - C onsum iendoServiciosW ebl

S p l ConsumiendoServiciosWebl
5

{ ) Consum iendoSefviciosW ebl

so p a s s s
S
^
fr.
!+.

D ire ctoryC ategory


GoogleSearchResult
G o ogleearchS ervice
ResultElem ent

t i ^ i j frm M ain

Class Viaw | 1 ^ S d - j i i M i . . .

| 1 R.esoufa

Figura 5. En el explorador de clases podemos apreciar


la referencia web incorporada a nuestro proyecto.

u s r .c o d e

321

PROGRAMACIN CU

De este modo, nuestra aplicacin interacta con el servicio de modo transparente:

Figura 6. El proxy nos evita tener que trabajar con el protocolo SOAP.

Utilizar llamados sincrnicos


Ahora lleg el momento de codificar. Principalmente, haremos uso del mtodo
doGoogleSearch de la clase GoogleSearchService.
El mtodo mencionado cuenta con los siguientes parmetros:

key

Clave de cuenta provista por Google como medio de autentificacin.

<1

Trminos a buscar, Estetoto puedemilitar ciertosoperadores para ajustar los resultadosde la bsqueda

start
HHHHM
maxResutts

filter
restrict

ndice (comentando por cero) del primer resultado para devolver.


Cantidad mximade resultadosdevueltos (ei mximoes 10).

Permite filtrar resultados similares o que provengan del mismo sitio.


Permite restringir la bsqueda a unsubconjuntoespecificado por un Indiceweb de Google(como un pas
ouna tecnologa muy popular)

SafeSearch

Indica si se deben filtrar enlaces a sitios con contenido adulto.

If

Restringe 13bsqueda a unidioma.

ie

Parmetro obsoleto. Estaba relacionado con la codificacin de caracteres utilizada para la entrada de datos.

oe

Parmetro obsoleto. Estaba relacionado con la codificacin de caracteres utilizada para la salida de datos.
Tabla 1. Parmetros del mtodo doGoogleSearch.

GoogleSearchService gss = new GoogleSearchService();


GoogleSearchResult gsr = ges.doGoogleSearch(

322

u s r .c o d e

Q u s o n lo s s e r v ic i o s w e b ?

clave_otorgadajpor_Google,

// clave

txtSaarch.Text,

// texto a buscar

0,

// ndice de comienzo

10,

// cant. mx. de resultados

true,

// filtro

String.Empty,

// ndice web de gocgle

true,

// bsqueda segura

String.Empty,

// restriccin por idioma

String.Empty,

// Parmetro obsoleto

String.Empty);

/ Parmetro obsoleto

Por otro lado, el resultado devuelto por la bsqueda se incluye en un objeto del ti
po GoogleSearchResult, que posee las siguientes propiedades:

documentFiltering

Valor booleano que indica si se practicunfiltradode la informacin (esto lo habamos

searchComments

Textopara mostrarle al usuariofinal que indica, por ejemplo, si se hanquitado palabras

especificado en la solicitud de bsqueda).

especificadasen la bsqueda por ser muycomunes {como los artculos).


estimatedTotalResultsCount

Cantidad total estimada de resultados que atoj la bsqueda (no la cantidad enviada hacia
nosotros, que como mximo es 10, sino el total que emiti la bsqueda por la base de datos),

estimatedlstxact

Valor booleanoque especifica si lodevueltopor estimatedTotalResuttsCount es exacto.

resultElements

Array de elementos de tipo resultElements quecontiene los resultadosde la consulta.

searcbQuery

Trminos(parmetro q) con los cuales se especificia

startlndex

ndice del primer resultado (comenzando por uno),

consulta,

endlndex

ndicedel ltimoresultado.

searchTips

Texto para mostrarle al usuario final, conconsejos acerca de cmo utilizar Google.

directoiyCategories

Un array de elementosde tipodirectoryCaiegory.

searchTime

En texto, el tiempo en segundos que tard labsqueda.__________________________


Tabla 2. Propiedades del objeto GoogleSearchResult.

DD QU ES SOAP?
SOAP (Simple Object Access Protocol1es un protocolo basado en XML que estandariza el modo
de interaccin con tos servicios web. Enlace relacionado: www.w3.org/TR/soap.

u s r .c o d e

323

PROGRAMACIN C8

Para poder otorgarle la informacin al usuario sobre las pginas encontradas, debe
remos recorrer el array resultElement, que posee las siguientes propiedades:

summary

Si el resultado se encuentra en el directorio OOP, aqu se ofrece una descripcin.

OflL

Ladtredo 8 la pgna relacionada.

snippet

Un pequeo resumen del texto encontrado en la pgina que se relaciona con la bsqueda.

! Me"

Titulode la pginarelacionara.

cachedSize

Tamao de la pgina en cach.

1 letatedtafoimatkmPrsseiU

hostName

Valor booleanoque indica si el trminodeconsulto "retated:" esvlidopara la URL

Para la segunda pgina encontrada relacionada con el mismo host, en esta propiedad se hallar
el nombre de ste.

: dlrectoryCategory

Categora de rfircctorioOOP.

directoiyTitle_ _ _ _ _ _ _ _ _ Ttulo del directoro OOP._ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _


Tabla 3. Propiedades del array resultElement.

La bsqueda se realiza de modo sincrnico, por lo que el control a nuestro progra


ma retornar cuando sta haya finalizado, y entonces podremos mostrar los resulta
dos del modo que mejor nos parezca.
(int inO; i<gsr.re8ultBleaent0.Length; i++)
// Extraigo algunos tags HTML
gsr.reaultBlenents[i].title *
gar.reaultElauentsli].title.ReplaceVt", *")j
gar.raaultElementali],title
gar.reaultElementsi].title.Replace{*</b>", "");
// Agrego el resultado al ListView
LiatViewItem li new ListViewItem(gar.resultBlement8(i].title);
li.Subtema.Add(gsr.resultBlementa[i].URL);
lavResultB.Items.Add(li);

Utilizar llamados asincrnicos


Tambin podramos haber realizado la bsqueda de modo asincrnico utilizando la
versin de los mtodos que comienzan con Begin y especificando el delegado co
rrespondiente para alertarnos del arribo de los resultados.
Si realizamos un llamado asincrnico, nuestra aplicacin no quedar en espera de
los resultados, sino que podr seguir operando normalmente. Lo importante es ana

324

u s r .c o d e

Q u s o n lo s s e r v i c i o s w e b ?

lizar si tiene sentido que la aplicacin quede esperando los resultados o si es ms be


neficioso para el usuario poder seguir operndola.

GoogleSearchService, notaremos que, adems de


doGoogleSearch y doSpellingSuggestion, existen otros
con los mismos nombres, pero con prefijo Begin y prefijo End; es decir:

Si exploramos la clase del servicio


los mtodos doGetCachedPage,

BegindoGetCachedPage y EnddoGetCachedPage
BegindoGoogleSearch y EnddoGoogleSearch
BegindoSpellingSuggestion y EnddoSpellingSuggestion
Es importante saber que esta versin de mtodos la ha creado Visual Studio, y
no son otros mtodos del servicio web que ofrezca Google.
Ahora, si en lugar de invocar

doGoogleSearch

invocamos

BegindoGoogleSearch,

el

flujo de ejecucin pasar a la lnea siguiente casi inmediatamente despus de invo


car el mtodo (sin que an los resultados se encuentren disponibles).
Y cmo sabremos cundo los resultados se encuentran disponibles? Otra aplica
cin ideal para los delegados!
Los mtodos Begin... reciben dos parmetros extra despus de la lista de parmetros
normales al mtodo en cuestin. Estos son:

AsyncCalIback callback

Delegado que ser invocado cuando los datos ambec.

obiect state

Objetoque almacena informacin de estado. Ser enviadoal delegadocuandotos datos arriben.


Tabla 4. Parmetros de los mtodos Begin...

Por lo tanto, nuestra llamada ahora podra modificarse a:


GoogleSearchService ges = new GoogleSearchService();
// Realizo un llamado asincrnico
gas.BegindoGoogleSearch(
clave_otorgada_por_Google,
txtSearch.Text,
0,

u s r .c o d e

// clave

texto a

buscar

// ndice de comienzo

10,

// cant. mx. de resultados

true,

// filtre

String.Bnpty,

// ndice web de google

true

// bsqueda segura

325

PROGRAMACIN CU

String.Empty,

// restriccin por idioma

String.Empty,

// Parmetro obsoleto

String.Empty,

// Parmetro obsoleto

new AsyncCallback(CorsultaTerminada), // Delegado


gss);

// estado

ConsultaTerminada ser el mtodo que indicamos que se invoque cuando los datos
se encuentren disponibles:
public void ConsultaTerminada(IAsyncResult ar)

{
GoogleSearchService gss (GoogleSearchService) ar.AsyncState;
// Recupero el objeto tipo GoogleSearchResult
GoogleSearchResult gsr = gsB.EnddoGoogleSearch(ar);
// Mostramos los resultados del modo usual

II

...

Como se puede apreciar en el listado anterior, primero recuperamos nuestro objeto Google
SearchService, que se encontraba encapsulado en el resultado de la operacin asincrnica.
Luego obtenemos el resultado que antes devolva el mtodo sincrnico, utilizando

para tal fin el EnddoGoogleSearch.


Finalmente, mostramos los resultados como mejor nos parezca.

M Bsqueda en Google
Bsqueda

|c#
Cantidad total d e resultados encontrados:

1070000
Search(Async)

Tiempo de bsqueda:
Titulo

0,106507
Enlace

Visual C# Developer Center


Visual Otud; Usmg Visual Studio .NET

http://msdn .microsolt.com/vcsharp/
http://msdn,.microsoft.com/vstudio/using/
C# Crner: C-Sharp, CI.NET, .NETDeveloper,.. http://www.c-sharpcorner.com/
C# C Sharp Help : For C# Developers -Csbar... http://www.csharphelp.com/
Mam Page - Mono
http://www,go-mono.com/
C# Statlon - Tutorial, links, Info - E Sharp
http://www,csharp-station.com/
C# Progtamming
http;//www, hitmiS.com/programmmg/dotNET/csharp..
APRESS . COM | BooPs for Professonals, by Pr... http://www.apress.com/
Visual C# Developer Center: Fromthe Team
http://www,,gotdotrvet.com/team/csharp/
C# C Sharp and Tutorials on C# Fnends.com

http://www.csharpfriend5.com/

Figura 7. Nuestra simple aplicacin de bsqueda en Google.

326

u s r .c o d e

C r e a r u n s e r v ic i o w e b

CREAR UN SERVICIO WEB


Es interesante consumir servicios web, pero mucho ms lo es crear nuestros propios
servicios, lo que nos permitir distribuir componentes de nuestra aplicacin en una
red. Veamos paso a paso qu procedimiento seguir para cumplir nuestro objetivo.

Microsoft IIS
[Internet Information Server) 5.0 o superior ejecutndose. El sistema operativo Win
dows XP Professional incluye el IIS 5.1, pero no es instalado por predefinicin.
En primer lugar, debemos verificar que poseemos un servidor web

Por lo tanto, hay que ir al panel de control, ingresar en la opcin Agregar o Quitar
desde all elegir Agregar o quitar componentes de Windows y, finalmente,

Programas,

marcar la opcin

Servicios de Internet Information Server e instalarlo.

IIS instalado y en ejecucin, crearemos un nuevo proyecto en Visual Studio


.NET; esta vez, el tipo de proyecto seleccionado ser ASP.NET Web Service:

Con

New Project

lis j

letrpttes:

Project Typm:
t Visual C# Prcjects

.. O Visual C++ projects


f'1 Setup and DepluyirnilPiojects

ti? B
0

A3P.UET V/ebl A5P.NET


Service I Mobite W...

3! L l Othef Projects
Q Visual Studio Solutions

P
Consol
Application

Web Control
Lfcrary

Windows
Service

Empty Project

A project for creating aML Web Services to use fromothef appcaticre

locatcn:

I http://localhost/WebServicel

_]

growse...

Project wtll be treated et http://tocalhast/WebSefvicel.


*Morj

C*

Hetp

Figura 8. Creando un servicio web.

Lo que hace en este caso el asistente es crear una carpeta dentro del sitio web que
especificamos, V dentro de ella coloca los archivos que componen el proyecto.

U IJ IIS NO EST EJECUTANDO ASP.NET 1.1


Si cuando deseamos crear una aplicacin del tipo ASP.NET, Visual Studio arroja un mensaje que
indica que la versin de IIS que se encuentra en ejecucin no posee instalada ASP.NET 1.1, pro
bablemente deberemos ejecutar el comando aspnetjregiis -r.

u s r .c o d e

327

PROGRAMACIN C#

Uno de estos archivos posee la definicin de la clase principal de nuestro servicio


web, que es una subclase de System.Web.Services.WebService:

System.Web.Services.WebServices
_

NuestroWebService

Figura 9. Nuestro servicio web debe ser descendiente de WebService.

El cdigo generado es bastante simple, y tiene un mtodo web escrito, pero bajo co
mentarios, que podremos eliminar.
Nuestro ejemplo consistir en crear cuatro mtodos diferentes, cada uno de ellos
con distintos tipos y cantidad de parmetros, simplemente para mostrar el mecanis
mo de funcionamiento de todo el sistema. Luego, estos mtodos podran trabajar
como lo hace cualquier aplicacin C# respecto al manejo de datos: accediendo a
una base va ADO .NET, o a archivos o a lo que nuestra aplicacin requiera.
Todos los mtodos que declaremos debern poseer un atributo llamado WebMethod
para que el compilador entienda que es un mtodo para incluir en el servicio. As,
pues, nuestros mtodos sern:
public clase Servicel : System.Web.Services.WebService

{
// Cdigo generado por Visual Studio .NET

//

II

...

EL TERCER PROTOCOLO: UDDI

Existe un tercer protocolo, muy utilizado en servicios web, pero no tanto como los otros dos
(SOAP, WSDL). Se llama UDDI 1Universal Description, Discovery and Integration), y permite loca
lizar e interrogar servicios web para descubrir qu operaciones ofrecen y de este modo poder uti
lizarlas. Enlace relacionado: www.uddi.org.

328

u s r .c o d e

C r e a r u n s e r v ic io w e b

[WebMethod]
public 3tring HetlO

{
,// Retorno un string arbitrario
return *el lenguaje C#*;

}
[WebMethod]
public string Met2(string str)

{
// Reto m o el string modificado
return *Me has pasado el string: * + str;

}
[WebMethod]
public int Met3(int numl, int num2)

{
// R e tomo la suma de los parmetros
return numl + num2;

}
[WebMethod]
public stringf] Met4()

{
string [] strs = new string [4];
strs[0] = "palabral"?
strs[l] = "palabra2";
strs [2] = ,1palabra3*';
stra[3] = "palabra4";
// Retorno la suma de los parmetros
return strs;

}
}

Q Q DNDE EST EL ARCHIVO WSDL?


Es posible generar el contenido WSDL de la interfaz de nuestro servicio por medio del archi
vo aspx generado por el enlomo, especificando wsdl como parmetro del siguiente modo:

http://localhost/W ebServicel/Servicel.asm x?wsdl. Suponiendo que nuestro proyecto se


llam WebServicel y el servicio, Servicel.

usr.code

329

PROGRAMACIN CU

Ahora, compilaremos nuestra aplicacin y la ejecutaremos. Hecho esto, se abrir un


navegador apuntando a un archivo del tipo asmx con el nombre de nuestro servicio.
Podremos, a travs de esta pgina, llevar a cabo una prueba de los mtodos de nues
tro servicio web, que nos permitir, incluso, especificar los parmetros que tenga el
mtodo que deseemos invocar.
3 Servicel Web Service -Microsoft Internet Explorer
ftfchivo

fcdtn

Ve*

@ ,fa 0

prontos

3 $
P***

[ve>n jjj) http://Vxafco#/WebSer>Tcel/Servlcel .ewnx?op Met3

Service 1

0 1
*

HerramieotM Ayyda
Fawrto

Q 0- :^

V iQ Ir

Vf,edos ^

......

Met3
T e st
To t e j t th e o p eraticn using the HTTP POST protocol, dick th e ln v o k e b u tton.

Parame*r Valu
n u m l:

jj____

num2:

Irtrant* local

Figura 10. Probando nuestro servido web.

Cuando invoquemos el mtodo en cuestin, podremos inspeccionar el resultado XML


que produce. En este caso, hemos invocado el mtodo Met3 con parmetros 5 y 4:
<?xml versin*"1.0" encoding*"utf-8" ?>
<int xmlns="http://vfww.dedaluB-software.coin.ar/">9</int>

Intentemos ahora desarrollar una pequea aplicacin que consume nuestro servicio,
de la misma manera en que lo hemos hecho con el servicio de Google. Los pasos
que deberemos seguir son muy sencillos:
1. Crearemos una aplicacin tipo Windows
2. Agregaremos una referencia web.

Application.

3. Especificaremos la ubicacin del archivo aspx (en lugar del wsdl que habamos
utilizado en el ejemplo del servicio Google).
4. Instanciaremos la clase de nuestro servicio web y podremos invocar cualquiera
de los mtodos que posea.
330

u s r .c o d e

C r e a r u n s e r v ic io w e b

P ru e b a de Servicio Web
M e t ---------------- -----------

Met'J

:-M e t2
Parmetro (stiing):

M e t4 ............

---------

Valor de retorno:

Pai metro (ni):


,

HOLA!

Parmetro (int):

ipalabral
i palabta2
j palabta3
palabra-i

;
Valor de retomo:

Valor de retorno

Valor de retorno:

jel lenguaje Cti

pasado el string ? i i! ^

.
Invocar

j
'

Invocar

Invocar

Invocai
;....................

Figura 11. Ejecutando los mtodos de nuestro servicio web.

Los archivos fuente completos de los ejemplos vistos en este captulo pueden ser
descargados desde el sitio

onweb.tectimes.com.

RESUMEN~

Los servicios web son la tecnologa de moda, y existen buenas razones para que lo sean. Mu
chas otras tecnologas persiguieron los mismos objetivos, y de hecho, fue posible conseguir
logros similares mucho antes de que los servicios web vieran la luz. Sin embargo, nunca fue
tan sencillo para el desarrollador construir y utilizar tecnologa que permitiese distribuir, tan
fcilmente, objetos por una red. Visual Studio .NET allana an ms el camino, convirtiendo en
un placer la construccin de aplicaciones distribuidas.

u s r .c o d e

331

activid ad es ;

TEST DE AUTOEVALUACIN
1 Cules son los Ires protocolos ms utilizados en los servicios web?

4 Un servicio web creado en ASP.NET puede ser utilizado desde plataformas Unix?

System.Web.Services.WebServices

1-------

NuestroWebService

2 Qu ocurre si no agregamos el atributo


WebMethod a los mlodos de un servicio?

5 Cul es la ventaja de crear aplicaciones


distribuidas?

3 Qu ventaja comporta el uso de mtodos


asincrnicos?

332

u s r .c o d e

PROGRAMACIN C#

Captulo

Sockets
Si deseamos que nuestra aplicacin
se comunique con otra por medio
de una red de datos, varias soluciones

son posibles. Una de ellas es la


programacin de sockets, que tienen
la ventaja de ser fciles de utilizar
y de poder dotar nuestras aplicaciones
de capacidades de red sin depender,
por ejemplo, de servidores web.

Qu es un socket?

334

Arquitectura de una aplicacin

SERVICIO DE ATENCIN AL LECTOR:

lectoreS@ m pedicioneS.com

de sockets
Dilogo entre un cliente
y un servidor
Sincrnico vs. Asincrnico
La clase Socket
Resumen

334
334
335
335
341

Actividades

342

PROGRAMACIN C#

QU ES UN SOCKET?
Socket es una especificacin que define una interfaz para la programacin de apli
caciones de red. Se implemento inicialmente en sistemas operativos del tipo BSD
Unix a principios de los aos ochenta. Originalmente, la librera

Berkley Sockets

ofreca una interfaz de programacin en lenguaje C; hoy en da existen muchas implementaciones. As, podemos encontrar la implementacin sobre M FC llamada

CAsyncSockets, la clase Socket en .NET,

la clase Socket en Java, etc.

Dentro de un programa que haga uso de una librera de sockets, un socket es un ex


tremo en la comunicacin de dos programas a travs de una red de comunicaciones.

Arquitectura de una aplicacin de sockets


Haciendo uso de sockets, dos aplicaciones podrn comunicarse mediante una red.
Para esto, es necesario que una de ellas oficie de servidor y comience a escuchar por
un puerto especfico, y la otra acte de cliente y se conecte a la anterior.

Figura 1. Pasos en la creacin

Figura 2. Pasos en la creacin

de un servidor.

de un cliente.

Dilogo entre un cliente y un servidor


Cuando se realiza una conexin, existe un dilogo bsico que se establece entre am
bas partes y que determina si la conexin es aceptada o no.
Una vez que la conexin est establecida, se comenzarn a intercambiar datos. El
modo en que cada parte actuar en funcin de los datos entrantes estar determi
nado por el protocolo de aplicacin que se defina.
334

usr.code

Q u e s u n s o c k e t?

Sincrnico vs. Asincrnico


La programacin de sockets puede realizarse utilizando mtodos sincrnicos o
asincrnicos, algo similar a lo que ocurra con la invocacin de mtodos de un
servicio web, y que vimos en el captulo anterior. Los llamados sincrnicos son
aquellos que esperarn a que la operacin se complete para continuar con el flu
jo de ejecucin del programa. Por ejemplo, si deseo conectarme a un servidor, in
vocar el mtodo Connect. Siendo el llamado sincrnico, en la lnea posterior a la
invocacin del mtodo el mismo habr finalizado (de modo independiente al xi
to de la operacin).

Figura 3. Mtodo sincrnico y asincrnico.

Por el contrario, los mtodos asincrnicos le indicarn a la librera qu

hacer,

pero

el hilo de ejecucin principal no se detendr ante el correspondiente llamado. Ci


tando un ejemplo similar al anterior, en este caso podramos invocar BeginConnect
y el programa pasara a la lnea siguiente sin que la operacin necesariamente haya
finalizado. Cmo saber, entonces, si se realiza o no la conexin? Por medio de un
llamado que har la librera hacia el programa utilizando un delegado.
Est claro que si utilizamos llamados asincrnicos no deberemos hacer suposiciones
sobre lo que sucede con el llamado en lneas posteriores a ia invocacin del mto
do correspondiente. De modo asincrnico podremos conectarnos a servidores,
aceptar conexiones de clientes remotos, enviar datos, recibir datos, etc.
u s r .c o d e

335

PROGRAMACIN CH

La clase Socket
La clase Socket se encuentra dentro del espacio de nombres System.Net.Sockets; pa
ra hacer uso de ella, sin utilizar el nombre completamenre calificado, agregaremos:
using System.Net.Sockets;

En este ejemplo, la aplicacin oficiar de servidor o de cliente, de modo mutuamen


te excluyeme. Esto significa que si disponemos de una sola computadora para
probarla, tendremos que ejecutarla dos veces: una como servidor y otra como cliente.

El servidor
Habamos mencionado los pasos necesarios para crear el servidor y dejarlo escu
chando sobre un puerto. Veamos el cdigo necesario para ello.
Primero deberemos crear el socket, que representar el extremo de la comunicacin
del lado servidor. El constructor de la clase Socket posee el siguiente prototipo:
public Socket(
AddreBsFamily addressFamily,
SocketType socketType,
ProtocolType protocolType

);
.'. "

. .

-. . . V'* *

...'

V /** "i

...

'

El primer parmetro, AddressFamily, seala el esquema de direccionamiento que uti


lizar el socket. En nuestro caso, siempre indicaremos AddressFamily.InterNetwork. El
segundo,

SocketType,

indica el tipo de socket que deseamos crear, que en nuestro

caso ser SocketType.Stream. Y el tercer parmetro mar el tipo de protocolo sobre


el cual crearemos nuestro socket; aqu podramos utilizar

colType.Udp.

ProtocolType.Tcp o Proto-

Para nuestro ejemplo, nos decidiremos por Tcp:

Socket connSocket = new Socket(AddressFamily.InterNetwork,


SocketType.Stream, ProtocolType.Tcp);

El segundo paso consistir en asociar el socket a un determinado endpoint. Un endrepresenta el direccionamiento a un extremo de la comunicacin, que en el

point

protocolo que estamos utilizando est dado por una direccin

IP y un puerto.

La direccin IP de nuestro servidor ser alguna de las direcciones IP de la computa


dora que oficie como tal (por ejemplo, podremos utilizar la direccin
127.0.0.1 que hace referencia siempre al servidor local).

336

IP

especial

u s r .c o d e

Q u e s u n s o c k e t?

IPAddress hostIPAddress = IPAddreas.Parse"127.0.0.1");

Respecto al puerto, fijaremos uno cualquiera; por ejemplo, el 8000:


IPEndPoint ipEndP = new IPEndPointthoatlPAddress, 8000);

Con el objeto del tipo

IPEndPoint

creado realizaremos la asociacin al socket utili

zando el mtodo Bind de la clase Socket:


connSocket.Bind(ipEndP);

Hecho esto, estamos listos para comenzar la escucha en el puerto especificado. Pa


ra ello utilizaremos el mtodo

Listen.

connSocket.Liaten(l);

El mtodo

Listen

recibe un parmetro que representa la cantidad de clientes que

pueden estar conectados de manera simultnea al servidor.


Ahora podremos elegir qu mtodos utilizar para aceptar la conexin entrante. Uno
de ellos es Accept, que es sincrnico y que bloquear nuestra aplicacin hasta reci
bir una conexin entrante, y el otro es BeginAccept, que es asincrnico y con el cual
deberemos indicarle qu mtodo (de alguna de nuestras clases) se har cargo de
aceptar o no las peticiones entrantes. Optaremos por emplear el modo asincrnico,
pues no deseamos que nuestra aplicacin quede paralizada mientras espera clientes.
connSocket.BeginAccept(new AsyncCalIback(OnAccept), connSocket);

El mtodo OnAccept ser del tipo

AsyncCallback, y le pasaremos como parmetro el

socket del servidor.


public void OnAccept(IAsyncResult ar)

{
Socket connSocket = (Socket) ar.AsyncState;
m_remoteSocket = connSocket.BndAccept(ar);

usr.code

337

PROGRAMACIN C#

// Canso el estado de la aplicacin


SetServerStatuB(BServerStatua.svr_connected);
m_remoteSocket.BeginReceive(m_receiveBuar, 0,
ajreceiveBuffer.Length, SocketFlaga.Nona, new
AayncCallback(OnReceive), o ranoteSocket)

)
La lnea de cdigo ms interesante del mtodo OnAccept es:
m remoteSocket * connSocket.BndAccept(ar);

Aqu, mediante

EndAccept

podremos acceder a otro socket, que representa el otro

extremo de la conexin que aceptamos. Antes de finalizar el mtodo, invocamos Be-

ginReceive usando el flamante socket para comenzar a aceptar datos de la conexin.


El cliente
Para el papel de cliente de nuestra aplicacin, deberemos crear un socket del mis
mo modo que lo hicimos para el senador.
El prximo paso ser conectarse al servidor, para lo cual haremos uso del mtodo

Connect de la clase Socket. Dicho mtodo recibe como parmetro un IPEndPoint, co


mo lo haca el mtodo Bind. En este caso, la direccin IP y el puerto sern arbitra
rios, y en la aplicacin resultarn elegidos mediante un TextBox.
IPAddreaa hoatIPAddreaa * IPAddres8.Parae(txtServerAddre88.Text);
IPEndPoint ipEndP = new IPEndPoint(hoatlPAddreaa,
Convert.ToInt32(txtServerPort.Text));
try

{
connSocket.Connect(ipEndP);

}
catch

{
// No es posible conectarse

)
338

...

u s r.c o d e

Q u e s u n s o c k e t?

Aqu utilizamos la versin sincrnica del mtodo, ya que el tiempo estimado de cone
xin a un servidor es bajo, y mientras tanto la aplicacin no debe realizar ninguna otra
tarea. Esto significa que, invocado el mtodo Connect, la aplicacin quedar bloquea
da durante unos instantes, mientras se est intentando la conexin. Si sta fracasa, el
mtodo arrojar una excepcin que deberemos manejar segn corresponda (en la apli
cacin de ejemplo, simplemente anunciamos dicho fracaso mediante un MessageBox).
Si la conexin fue satisfactoria, en la lnea posterior ai Connect asumiremos que existe
una conexin establecida y podremos comenzar a intercambiar datos con el servidor.

Enviar y recibir datos


El envo y recepcin de datos se realiza por medio de ios mtodos Send y Receive, respec
tivamente, ambos de la clase Socket. Los mtodos mencionados son del tipo sincrnico,
y poseen su contraparte asincrnica en BeginSend y BeginReceive. En nuestra aplicacin
de ejemplo haremos uso del envo de datos sincrnico (Send) y la recepcin de datos asin
crnica (BeginReceive). Por qu esta disparidad? Debido a que el envo de datos comien
za con una accin explcita por parte de nuestra aplicacin, pero la recepcin, no.
En concreto, los datos que intercambiar nuestra aplicacin con otra instancia de s
misma sern mensajes de texto. Si analizamos el cdigo que ejecuta esta aplicacin
cuando presionamos Enviar, veremos que lo que hace es armar un paquete de datos se
gn un protocolo de aplicacin bsico que inventamos para la ocasin, lo convierte en
un array de bytes y luego invoca el mtodo Send para enviarlos. La conversin mencio
nada tiene que ver con el tipo de dato que dicho mtodo espera como parmetro.
Nuestro paquete de informacin consta de una cabecera y una seccin datos. I ja. cabe
cera es fija y siempre son 2 bytes. El primero de ellos seala mediante un cdigo el ti
po de paquete de datos que llevar el cuerpo, y el segundo indica el tamao (en bytes).

Cdigo operacin
(1 byte)

Tamao seccin
datos
(1 byte)

Datos
(hasta 256 bytes)

Paquete

Figura 4. El paquete de datos inventado por nosotros.

Para el ejemplo, aqu slo haremos uso de un tipo de paquete (mensajes de texto),
pero se podra extender su utilizacin para otro tipo de aplicaciones.
Respecto a la recepcin de datos, ya dijimos que para manejar la operacin emplea
ramos un mtodo asincrnico. Para ello, tendremos que invocar BeginReceive y pa
sar como parmetro qu mtodo deber manejar dicha recepcin (similar a lo que
hicimos con BeginAccept). Analicemos detalladamente el prototipo del mtodo.
u s r .c o d e

339

PROGRAMACIN C#

public IAsyncResult BeginReceive(

bytell buffer,
j

int offset,
int eize,
SocketPlags sockatFlags,
AsyncCallback callback,

object atete

Mediante el primer parmetro pasamos un buffer en el cual la librera colocar los da


tos recibidos. El segundo parmetro indica un offset (desplazamiento) en bytes a par
tir del cual escribir en el buffer (usualmente colocamos 0). El tercero es el tamao
del buffer. El cuarto son flags relacionados con el socket. El quinto parmetro es el
mtodo que manejar la recepcin de datos. Y, en ltimo trmino, el sexto parmetro
es utilizado con el fin de enviar informacin propietaria al mtodo en cuestin.
Ya dentro de OnReceive, invocaremos el mtodo EndReceive, que nos retornar la
cantidad de bytes que recibi la librera (y que se encuentran en el buffer que pasa
mos como parmetro a BeginReceive).
public void OnReceive(IAsyncResult at)

{
Socket connSocket = Socket) ar.AayncState;
int read = connSocket.EndReceive(ar

II ...

);

Recibidos los datos, nuestra aplicacin los manejar de manera conveniente, y lue
go, si corresponde, antes de finalizar volver a invocar BeginReceive para seguir per
mitiendo la recepcin de datos.

Mquinas de estado
Con relacin a los datos que recibe la aplicacin y cmo Jos maneja, es frecuente
que se implemento una mquina de estados. La mquina de la aplicacin de ejem
plo es bastante sencilla, y simplemente, se encarga de conmutar entre los distintos
estados posibles del servidor y del cliente. Es importante que la aplicacin implemente un mecanismo de este tipo, debido a que la recepcin asincrnica de datos
en ocasiones torna compleja la prediccin de cmo se sucedern los hechos; por lo
tanto, para que la aplicacin se comporte consistentemente en todo momento, se
debe verificar el estado en el que se encuentra antes de realizar una accin.
340

u s r.c o d e

Q u e s u n s o c k e t?

Los sockets nos permiten crear aplicaciones de red de manera muy sencilla y eficien
te. Sin embargo, debemos destacar que no implementan ningn protocolo de apli
cacin en particular; se ser nuestro trabajo. Si deseamos comunicarnos mediante
algn protocolo de aplicacin particular

(HTTP, FTP, etc.), quiz podamos utilizar


.NET.

otras clases de mayor nivel que ofrece la librera BCL del firamework

htoU M tN
Muchsimas aplicaciones populares hacen uso de sockets para comunicarse con oirs median
te una red de datos como Internet. ste es el caso de todas las aplicaciones P2P, como eMule,
Kaaza, BitComet, BitTornado, etc. Programar con sockets es sencillo, y se trata de un recurso
que siempre hemos de tener a mano como posible solucin a requerimientos de conectividad
que podran tener nuestras futuras aplicaciones.

u s t.c o d e

341

| c 2 ACTIVIDADES

TEST DE AUTOEVALUACIN

1 E s

p osib le c o n e c ta r s e a un s e rvid o r w e b

3 R e q u ie r e

el s e rvid o r de una a p lica c i n

h a c ie n d o uso de la c la s e S o c k e t e interac-

que u tilice s o c k e ts la ex iste n cia de un s e r

t u a r c o n l?

v id o r H T T P o S M T P ?

t* E s p o sib le c r e a r un se rv id o r H T T P u tili
zando s o c k e ts ? Y un clie n te H T T P co m o
un n a v e g a d o r w e b ?

5 S e r a

p osib le co n su m ir un se rv ic io w e b

p or m ed io de una a p lica c i n que u tilice


s o c k e ts ?

Q u b e n e ficio s oto rg a la utiliz acin de los


m to d o s a s in c r n ic o s de la c la s e S o c k e t?
C u l e s la c o n tr a ?

342

u s r .c o d e

PROGRAMACIN C#

Captulo 1 3

Introduccin
a Managed
DirectX
En este captulo haremos una
introduccin a una de tas APIs
ms importantes en el mundo
de la programacin de aplicaciones
de alto rendimiento grfico y juegos.
Managed DirectX es una suma de clases
para .NET que nos permitirn hacer uso
de DirectX en su totalidad.
Managed DirectX

Qu necesitam os7
El sistema de coordenadas 3D

345

Antes de empezar

346

Inicializar Direct3D

347

Dibujar objetos

356

El mtodo ProcsVerts
de la clase Renderer

servicio oe atencin al lector:le cto res@ m pe dicio ne s.com

344

344

359

Ejecutar la aplicacin

360

Resumen

361

Actividades

362

PROGRAMACIN C#

MANAGED DIRECTX
DirectX es un conjunto de componentes creado por Microsoft para ser utilizado
en la creacin de juegos y aplicaciones multimedia de alto desempeo.

Haciendo uso de esta herramienta podremos crear grficos 2D y 3D; sonidos, m


sica y efectos; aplicaciones de red, como son los juegos multiplayer, y manejar dis
positivos de entrada como teclados, mouse, joysticks, volantes, game pads, etc.
Es posible hacer uso de l desde diversos lenguajes de programacin como C++, C#,

Delphi, Visual Basic, etc.


.NET deberemos utilizar Managed DirectX
(MDX), que consiste en un conjunto de clases organizadas en espacio de nombres, que

Ms especficamente, desde la plataforma

fue lanzada al pblico por primera vez el 20 de diciembre de 2002 y que pretende fa
cilitar el desarrollo de juegos y aplicaciones haciendo uso de esta tecnologa.

MDX es una gran API; en este captulo nos enfocaremos concretamente en su com
ponente ms popular: Direct3D.

Qu necesitamos?

Si deseamos slo ejecutar un programa MDX, necesitaremos:


El framework .NET en su versin 1.1 o superior (http://msdn.microsoft.com/
netframework). Podemos descargarlo desde el sitio de Windows Update o bien

conseguir su versin redistribuible.


Los runtimes de DirectX 9.0c o superior

(www.microsoft.com/windows/directx/default.asp).

Si deseamos desarrollar aplicaciones haciendo uso de Managed DirectX, necesitaremos:


El SDK del framework .NET 1.1o superior

(http://msdn.microsoft.com/netframework).

El SD K del DirectX 9.0c SDK o superior

(www.microsofit.com/downloads/search.aspx?displaylang=en&categoryid=2).

Tambin es recomendable contar con algn entorno de desarrollo integrado como

Microsoft Visual Studio .NET, que facilite la gestin del proyecto y su depuracin.
Existe una base terica fundamental que deberemos conocer, previamente a empe

zar a navegar por los mares de Direct3D. Comenzaremos con una breve resea que
nos ser bastante til como introduccin a dicha teora.
344

u s r .c o d e

E l s is te m a d e c o o r d e n a d a s 3 D

EL SISTEMA DE COORDENADAS 3D
Por medio de Direct3D lograremos crear una imagen en dos dimensiones a partir
de un modelo tridimensional. Esto es as, naturalmente, porque nuestro monitor
slo puede generar una imagen chata de los datos procesados.
Adems,

Direct3D

har todo esto de modo muy eficiente utilizando caractersti

cas convenientes de la placa de video cuando stas estn presentes, as como ca


ractersticas del CPU que puedan mejorar el rendimiento de nuestra aplicacin
(por ejemplo, el conjunto de instrucciones
to de instrucciones AMD 3dNow!).

Intel MMX, SSE, SSE2 o el conjun

Nuestros objetos 3D sern colocados en escena por medio de un sistema de coor


denadas de tres dimensiones. Direct3D utiliza la convencin de la mano izquierda
que dicta que el eje Z crece positivamente hacia adentro de la pantalla; por lo tan
to, un vrtice que posea en su componente Z un valor mayor se encontrar ms le
jos que otro con valor menor.
Un objeto en

Direct3D

estar constituido exclusivamente por un conjunto de

tringulos, los cuales a su vez estarn formados por un conjunto de vrtices. Cada
uno de estos vrtices poseer los tres componentes requeridos para ser colocados
dentro de un sistema de coordenadas 3D, pero cabe mencionar que podrn tener
otras propiedades en funcin de las caractersticas que deber poseer el objeto del
cual forme parte, y que, en su debido momento, analizaremos.
Cada vrtice, antes de ser mostrado en pantalla, deber pasar por una serie de trans
formaciones que dictarn si el vrtice es finalmente mostrado y en qu posicin de
la pantalla estar. Estos cambios se darn dentro del denominado

pipeline.

cuyo

diagrama podemos observar a continuacin:

Vrtices

u
Transformacin
Transformacin
de Proyeccin >
de Vista
(View)
(Projection)

Transformacin
de Mundo
(World)

Pipeline de Transformacin

Recorte
y reescalado
de Vlewport

Rasterizador

Figura 1. El pipeline fijo de transformacin.

u s r .c o d e

3 45

PROGRAMACIN C#

El pipeline se alimenta de vrtices, y cada uno ser convertido a coordenadas homo


gneas para luego poder ser multiplicado por tres matrices: la matriz de mundo, la
matriz de vista y la matriz de proyeccin. Luego, la coordenada resultante es rees
calada en funcin de puerto de visualizacin especificado (usualmente la pantalla
completa o la ventana que estamos utilizando como objetivo para el dibujado), y en
caso de quedar fuera del rea de visualizacin, se elimina. Finalmente, el vrtice es
transferido til proceso de rasterizacin, donde ser dibujado en pantalla.

La matriz de mundo
La primera matriz de mundo cs utilizada con el propsito de colocar el objeto den
tro de la escena 3D. Realiza una transformacin que va desde el espacio del mode
lo al espacio del mundo en el cual trabajamos. La transformacin de mundo puede
incluir traslaciones, rotaciones y escalamientos.

La matriz de vista
La segunda matriz, llamada matriz de vista, reubica todos los objetos en funcin de .
un punto de visualizacin especificado.

La matriz de proyeccin
La tercera matriz, denominada matriz de proyeccin, especifica principalmente es
cala y perspectiva adoptada. Esta matriz determinar tambin cunto vemos de la
escena; es decir, el volumen de visualizacin.

ANTES DE EMPEZAR
Para hacer uso del API deberemos utilizar los espacios de nombre Microsoft.DirectX

y Microsoft.DirectX.Direct3D, y si el compilador no logra encontrar estos recursos, es


posible que falte agregar las referencias a l o exista un problema en la instalacin
del SDK de DirectX

9.0c.

H U DE DIRECTX A MANAGED DIRECTX


Lo s p ro g ra m a d o re s q u e ya h an utilizado D irectX d e s c u b rir n con g ra ta s o rp re s a que M an a g e d
D irec tX e s ca si id ntico , pero con una o rg an izaci n de c la s e s m u c h o m s co n ve n ie n te , deb id o a l
uso de e s p a c io s de n o m b re s . Tam bin a p ro ve ch a m u c h a s de la s ca p a c id a d e s de la p la ta fo rm a
(co m o lo s d e le g a d o s) p a ra f a c ilita r la p ro g ram ac i n .

346

u s r .c o d e

I n i c ia li z a r D ir e c t 3 D

Establezcamos un objetivo: intentaremos crear una pequea escena compuesta de


una pirmide central, formada por cuatro tringulos, y por debajo, una plataforma
compuesta por dos tringulos.

Figura 2. Nuestro sencillo diagrama de clases.

La clase

Renderer ser la encargada de inicializar Direct3D, establecer ciertas pau-

tas para el manejo de las matrices del API y, principalmente, mantener alejadas el
resto de las clases de cdigo especfico de DirectX; por lo tanto, el da de maana
podramos realizar un cambio a otra librera, como OpenGL, sin por esto tener que
modificar cada vez todas las clases de nuestra aplicacin.
La clase Piso y la clase Pirmide representarn los objetos 3D que veremos en pan
talla. Cada una de ellas almacenar la informacin de geometra de los objetos y se
comunicar con la clase Renderer para transferrselos en el momento de tener que
colocarlos en pantalla.
La clase frmMain ser la principal de nuestra pequea aplicacin: coordinar el tra
bajo entre las otras clases y mantendr el bucle en el cual se invocarn los mtodos
necesarios de las otras clases para dibujar la escena en pantalla.

INICIALIZAR DIRECT3D
El mtodo Init ser el encargado de inicializar el API para poder comenzar a dibu

jar objetos. Para esto necesitamos hacer uso principalmente de la clase Device de Di-

rect3D

(espacio de nombres

Microsoft.DirectX.Direct3D),

que es el dispositivo de

renderizacin, y nos permitir por medio de sus mtodos controlar la iluminacin,


texturado, sombreado y dibujado de los objetos que coloquemos en la escena.

PROGRAMACIN C#

Como primer paso, nos disponemos a realizar la creacin de un objeto del tipo Device por medio del operador new y haciendo uso del constructor de la clase que po
see parmetros. Analicemos a continuacin el prototipo del mtodo:
public Devicel
int adaptador,
DeviceType tipoDispositivo,

Control vetitanaeRenderiracin,
CreateFlags PlagaDeConportamiento,
PresentParameters parmetroaDePresentacifin

);

Con el primer parmetro estaremos especificando para qu adaptador deseamos


crear el dispositivo. Recordemos que el sistema operativo Microsoft Windows pue
de manejar varios adaptadores de video simultneamente (en pocas palabras, po
dramos tener ms de un monitor conectado a la misma PC). Si en este parmetro
colocamos un cero, el objeto asumir que deseamos crear el dispositivo en el adap
tador predefinido, que es el nico o el principal.
Con el segundo parmetro especificaremos el tipo de dispositivo que deseamos
crear. Podremos optar entre las siguientes opciones:

DeviceType.Hardwaie: se crear un dispositivo de rasterizacin va hardware.


DeviceType.Reference: se crear un dispositivo de rasterizacin va software, pero
el dispositivo har uso de instrucciones extendidas de CPU cuando stas se en
cuentren disponibles.

DeviceType.Software: se crear un dispositivo de rasterizacin va software.


Lo ideal es, antes de seleccionar una opcin que tenga posibilidades de ser rechaza
da, llevar a cabo una verificacin por medio de algn mtodo de la clase Manager
del espacio de nombres Microsoft.DirectX.Direct3D o, en su defecto, atrapar la excep
cin y volver a intentar la llamada con otra opcin.
El tercer parmetro indica cul ser la ventana (o control) a la que pertenecer el
dispositivo y dnde se realizar el dibujado. En nuestro caso, aqu determinaremos
un control del tipo Panel, pero podramos haber especificado la ventana entera en
la cual estamos trabajando.
En el cuarto parmetro precisaremos distintas opciones en la creacin del dispositi
vo; algunas de las cuales son mutuamente excluyentes y otras, por el contrario, son
combinables. En la pgina siguiente, analizamos las opciones ms importantes:
348

u s r.c o d e

In ic ia liz a r D ir e c t3 D

CreateFlags.HardwareVertexProcessing: posee la funcin

de especificar el procesa

miento de verdees por medio del hardware.


CreateFlags.SoftwareVertexProcessing: es la encargarda de especificar el procesa
miento de vrtices por medio del software.
especifica el procesamiento de vrtices por

CreateFlags.MixedVertexProcessing:

medio de hardware y software de modo combinado.

CreateFlags.FpuPreserve: indica qu tipo de precisin debe usar el dispositivo: sim


ple o doble. De esce modo, seleccionaremos doble precisin, que reducir la per
formance de Direct3D, para una mayor exactitud en clculos de procesamiento.
Las opciones HardwareVertexProcessing, SoftwareVertexProcessing y MixedVertexProcessing son mutuamente excluyentes y, nuevamente, es posible que la eleccin de
una de ellas cause un fracaso en la creacin del dispositivo por falta de soporte a di
cha opcin en la plataforma de trabajo.
Por ltimo, el quinto parmetro especifica los parmetros de presentacin. Esta op
cin es, a su vez, una clase con una serie de propiedades que deberemos completar
antes de invocar el constructor de la clase Device. Veamos cmo hacerlo:
PrasentParaaetsrs didPreeentParana * new PreaentParametera

()>

ddPreaentParama.Windowad * true;
dJdPreaentParama.SwapSffeot = SwapEffect.Diacard;

En la primera lnea creamos un objeto del upo PresentParameters. Las propiedades es


pecificadas en el listado anterior son las que no deseamos dejar en su valor predefinido:

Windowed:

indica si inicializamos el dispositivo en modo ventana o en pantalla

completa. Esta opcin es muy importante, ya que el modo ventana implica una se
rie de restricciones en la determinacin de otros parmetros. Por ejemplo, no po
dremos cambiar la resolucin al haber otras aplicaciones en el mismo escritorio.
SwapEffect: existe un concepto bsico que utilizamos cuando dibujamos en panta

lla, y es que lo estamos haciendo en una superficie de memoria, que puede ser de

ELECCIN d e l tipo d e d ispo sit iv o

Existen configuraciones ms convenientes que otras respecto al tipo de dispositivo por elegir. Et
problema es que no todo el hardware existente soporta las mismas opciones. En ocasiones no que
dar otra opcin que procesar vrtices por software si deseamos que nuestra aplicacin funcione.

u s r .c o d e

34 9

PROGRAMACIN C#

video o convencional, y luego, cuando presentamos la informacin en pantalla, esa


superficie es copiada a la memoria de video que est mapeada con lo que refleja el
monitor o, en caso de ser memoria de video, se modifica el puntero que indica el
comienzo del mapeo. La superficie que no vemos, sobre la que dibujamos, es el

backbuffer, y la reflejada en pantalla se llama frontbuffer. Cuando DirectfD reali


za el intercambio entre el backbuffer y el frontbuffer, podemos indicarle que acte
de distintos modos. Nosotros seleccionaremos la opcin SwapEffect.Discard, ya que
no deseamos preservar la informacin existente en el bufler sobrescrito.
El resto de las propiedades de PresentParameters podremos dejarlas en su valor pre
determinado. Cuando avancemos en el desarrollo de nuestro ejemplo, deberemos
modificar otras propiedades de su valor predefinido.
Veamos cmo queda hasta ahora el mtodo Init de la clase Renderer que creamos:
public bool Init(Control devWin)

{
PresentParameters d3dPresentParams = new PresentParameters();
d3dPresentParams.Windowed = truej
d3dPresentParams.SwapEffect = SwapEffect.Discardj
try

{
m_device = new Device(0, DeviceType.Hardware, devWin,
CreatePlags.HardwareVertexProcessing, d3dPresentParams);

}
catch (DirectXException)

{
try

{
m d evice = new Device(0, DeviceType.Hardware, devWin,
CreateFlags.SoftwareVertexProcessing, d3dPresentParams

);

}
catch (DirectXException)

{
return falsej

}
}
return DisponerEscenaO;

350

u s r.c o d e

In ic ia liz a r D ir e c t3 t)

El mtodo Init recibe el control sobre el que se crear el dispositivo.Existen dos blo
ques try.catch anidados, ya que en
primera instancia intentamos crearundispositi
vo que procese vrtices por hardware, pero en caso de fracasar, repetimos el inten
to especificando que el procesamiento de vrtices se realice por software.
Por ltimo, el mtodo

Init realizar una llamada a otro mtodo de la misma clase

denominado DisponerEscena. Lo que har principalmente este ltimo mtodo es fi


jar los valores predeterminados a la matriz de vista y proyeccin:
public bool DisponerEscenaO

{
// Por el momento, no utilizaremos iluminacin
m_device.RenderState.Lighting = falee;
// Fijamos

el valor de

la matriz de vista por medio

del mtodo

esttico de

Matrix, LookAtLH

m_device.Transform.View o Matrix.LookAtLH( new Vector3(0.0f,


50.Of, -50.Of),
new Vector3(0.0f, O.Of, O.Of), new Vector3( O.Of, l.Of, O.Of ) );
// Fijamos el valor de la matriz de proyeccin, en perspectiva,
por medio del mtodo esttico de Matrix, PerspectiveFovLH
m_device.Tranflform.Projection * Matrix.PerspectiveFovLH! (float)
Math.PI /

4,

l.Of, -30.Of, 30.Of )>

retura true;

; )

El mtodo consiste bsicamente en tres pasos:


1. Establecemos, por el momento, que nuestra escena no posea iluminacin por

2.

medio de la propiedad RenderState.Lighting de la clase Device. La propiedad RenderState nos ser muy til en el futuro porque modifica opciones internas de Direct3D que alteran el modo en que son dibujados los objetos en pantalla.
Fijamos el valor de la matriz de vista haciendo uso del mtodo esttico LookAtLH
de la clase Matrix, que nos permite especificar, po: medio de tres parmetros, des
de qu punto deseamos mirar la escena, a qu punto deseamos mirar y, final
mente, cul es el arriba en nuestro mundo.

3. Fijamos el valor de la matriz de proyeccin por medio del mtodo esttico Pers
pectiveFovLH de la clase Matrix por medio de cuatro parmetros: campo de vi
sin (especificamos lo usual, que es el nmero PI dividido cuatro), la relacin
existente entre el alto y ancho de nuestra escena, el plano de recorte cercano y
el plano de recorte lejano. Todas estas propiedades delimitan el volumen de visualizacin de la escena que observaremos.

!
u s r .c o d e

351

PROGRAMACIN C#

Con nuestro flamante mtodo Init, veremos ahora cmo hacer uso de l por medio
de una instancia de Renderer en la clase frmMain:

- A'lt

'i:\ '

V^.A'-vv',&^ f'

static void Main()

{
// I n s t a n d o un nuevo o b je to

frmMain nn = new frmMainO;


// Muestro el formulario
frm. Show () ;
// A rra n c o l a a p l i c a c i n

frm. Arrancar ();


// M ie n tra s que

el

fo r m u la r io no sea d e s tr u id o

while(frm.Created)

{
// D ib u jo l a escena

frm.Dibujar ();
// A tie n d o eve n to s

Application.DoEvents();

}
}

Analicemos el cdigo anterior:

En

la primera lnea, lo que hicimos fue crear una instancia del formulario frmMain.

Por medio del mtodo Show, lo mostramos en pantalla; luego invocamos un mto352

u s r .c o d e

In ic ia liz a r D ir e c t3 D

do llamado Arrancar creado por nosotros y donde simplemente realizaremos la lla


mada al mtodo Init de Renderer. Tengamos en cuenta que la clase frmMain tendr
una propiedad de este tipo.
Finalmente ingresamos en un bucle, donde, mientras el formulario no sea destrui
do, invocaremos el mtodo Dibujar (que fue generado por nosotros y que aflora ve

remos qu contiene) y luego ei mtodo esttico DoEvents, de la clase Application, pa


ra que nuestra aplicacin se encuentre posibilitada de seguir atendiendo mensajes
externos a pesar de encontrarse en un bucle.
Por lo tanto, podramos expresar el diagrama del mtodo Main del siguiente modo:

Figura 4. Mientras la aplicacin se encuentre


en ejecucin, permaneceremos dentro del bucle.

u s r .c o d e

353

PROGRAMACIN CU

Prestemos especial atencin a que el comportamiento de nuestra aplicacin es dis


tinto del de una aplicacin convencional, ya que aqu estaremos dentro de un ci
clo dibujando una y otra vez, en contraposicin a la aplicacin tpica que slo redibuja atendiendo el clsico mensaje WM_PAINT que se suscita cuando existe una
actualizacin en los datos (a pedido nuestro) o cuando la ventana es sobrescrita
por algn elemento que se mueva por encima de ella.
Este modo de trabajar es muy comn en los juegos de computadora, y a dicho ci
clo se lo denomina bucle del juego (game loop), donde tambin se suelen realizar
otras tareas, como atender los dispositivos de entrada, procesar informacin referi
da a personajes manejados por la mquina, etc.
Pero qu hacemos en el mtodo Dibujar? Veamos:
El mtodo Dibujar se encargar de invocar un mtodo homnimo para cada uno de los
objetos contenidos en la escena (la pirmide y el piso), adems de invocar los mtodos
correspondientes de Renderer para que todo est listo y en forma para el dibujado.
Observemos un diagrama de secuencia para ver cmo trabajan los distintos objetos
de nuestro pequeo sistema (Figura 5).
El mtodo Limpiar de Renderer simplemente invocar el mtodo Clear de la clase
Device, que puede ser utilizado de varios modos; por el momento slo lo empleare
mos para limpiar la superficie donde estamos dibujando y especificaremos por me
dio del segundo parmetro el color con el que deseamos limpiarla.
public void Limpiar()

{
mdevice.Clear(ClearPlags.Target, System.Drawing.Color.Black,

l.O f, 0))
}

FOROS DE AYUDA

En el sitio www.dedalus-software.com.ar podrn encontrar foros especficos de programacin


C# en donde se trata acerca de Managed DirectX.

354

usr.code

In ic ia liz a r D ir e c t3 D

Figura 5. Cada objeto dibujable posee su propio mtodo Dibujar.

u s r .c o d e

355

PROGRAMACIN C#

F.l mtodo ComienzoEscena de Renderer se ocupar de invocar el mtodo BeginScene de la clase Device. Direct3D nos indica que se debe llamar a este mtodo previa
mente a la realizacin del dibujado de cualquier objeto.
public void ComienzoEscena0 { m_device.EeginScene()?}

El mtodo

FinEscena

de Renderer invocar el mtodo

EndScene

de la clase Device.

Direct3D indica que se debe llamar este mtodo cuando finalizamos el procesa
miento de vrtices relacionados con una escena.
public void FinEscenaO { m device.EndScene(); }

El mtodo Presentar de Renderer invocar el mtodo Present de la clase Device. D i


cho mtodo vuelca el contenido del backbuffer sobre el frontbuffer, refrescando lo
que vemos en pantalla.
public void Presentarf) { m_ device.Present{);}

DIBUJAR OBJETOS
Por cada objeto mostrado en pantalla deberemos poseer un array de vrtices, de!
formato seleccionado, con la informacin de geometra de ste. Por esta razn, es
conveniente crear una clase para cada uno de ellos. Luego, existir un mtodo lla
mado Dibujar en el cual le pasaremos a la clase Renderer el contenido de dicho
array para que sea procesado.
As, pues, crearemos la clase Piso con el array de vrtices correspondiente:
public class Piso

{
// Array de vrtices del piso
prvate CustomVertex.PositionColored[] m_verts =
new CuBtomVertex.Po8tionColored[6];

II ...

};

356

u s r.c o d e

D ib u ja r o b je to s

Nuestros vrtices sern del tipo CustomVertex.PositionColored, ya que esta estructu


ra tiene las propiedades que requerimos (posicin +color). Por lo tanto, llevaremos
a cabo la creacin de un array de seis elementos, pues nuestro piso estar formado
por dos tringulos compuestos del siguiente modo:

v4

v5

Figura 6. Nuestro piso estar formado por dos tringulos.

Como la informacin del piso no variar, lo nico que tendremos que rellenar se
r este array una vez. Esto no quiere decir que el piso no pueda ser movido, esca
lado o rotado en cualquier eje, porque para eso podremos modificar la matriz de
mundo, que rectificar a su vez el vrtice entrante para entonces colocarlo en la
posicin que nos plazca. En consecuencia, podremos completar la informacin
del array en el constructor de la clase Piso:
public Piso()

{
// Cara A
// Vrtice 1

m_verts[0].X = 25.Of; m verts[0] .Y = -3.Of; m_verts[0].Z = -25.Of;


m_verts[0].Color = System.Drawing.Color.SkyBlue.ToArgb{) ;
// Vrtice 2

m_verts[l].X = -25.Of; m_verts[l].Y = -3. O f ; m_verts[l].Z = -25.Of;


m verts ti] .Color = System.Drawing.Color.SlateBlue.ToArgb();

1/

Vrtice 3

m _ v e rts [2 ] .X

- 2 5 . O f;

m _ v e rts [2 ].Y

-3 . O f;

m v e rts [2 ]. Z

2 5 . O f;

m_verts[2].Color = System.Drawing.Color.SkyBlue.ToArgb();
// Cara E
// Vrtice 1

usr.code

357

PROGRAMACIN C#

m_vertfl[3] .X' -25.Of; m_verts[3] .Y = -3.Of; m_vertsI3].Z 25.Of;


m_yerts[3] .Color System.Drawing.Color.SkyBlue.ToArgb();
|

// Vrtice 2
m_vert8[4].X * 25.0; o_vert0[4].Y * -3.Of; mjrerts[41.Z * 25.Of;
m_verta{4].Color Syatea.Drawing.Color.SlateBlue.ToArgbO ;
// Vrtice 3
m_verts[5].X 25.Of; m_vertst5].Y = -3.Of; m_vert8[5].Z = -25.Of;
m_vertB[5] .Color a Syatem.Drawing.Color.SkyBlue.ToArgbO;

I }
Tal como podemos apreciar, cada uno de los vrtices posee una posicin y un color. Si
especificamos distintos colores para vrtices de un mismo tringulo, Direct3D se ocu
par de realizar una interpolacin de stos para otorgarles color a los pixeles interme
dios en el proceso de rasterizacin.
Ahora veamos el mtodo Dibujar de la misma dase:
public void Dibujar(Renderer rnd)

{
rnd.SetMatrixMode (eliatrixMode .MMJJORLD);
rnd.Loadldentity();
rnd.ProcsVertsfm verta, 6);

'

Bastante sencillo, simplemente hemos modificado la matriz de mundo y la lleva


mos a su valor identidad (una matriz identidad consiste en un elemento neutro
en la operacin producto) para tener la certeza de que no exista un valor distinto
al deseado que haya quedado por el dibujado de otro objeto previo y termine
transformando nuestro piso involuntariamente.

U U OTROS COMPONENTES DE DIRECTX


DirectX no es slo Direct3D. Con esta API, tambin podremos acceder a dispositivos de entrada
de un modo eficiente (Directinput), reproducir sonido (DirectSound y DirectMusic), reproducir vi
deo IDirectShow], etc.

358

u s r.c o d e

D ib u ja r o b je to s

Por ltimo, invocamos el mtodo ProcsVerts de la clase Renderer y le pasamos el


array junto con la cantidad de elementos que posee.
La clase Pirmide es muy similar a Piso, slo que para variar un poco el ejemplo le
colocamos algunas propiedades ms que permitan su rotacin en eje Y y su escala
miento. El mtodo Dibujar es similar al de la clase Piso, pero con unas lneas ms.
public void Dibujar(Renderer rnd)

{
m d .SetHatrixMode (eMatrixMode.MM WORLD)
rnd.LoadldentityO;
// Modifico la escala |
if (ofEscalaX 1= l.Of || m_fBscalaY != l.Of jj m_fBscalaZ != l.Of)
rnd.Scale(m fBscalaX, m_fBscalaY, mfEscalaZ);
// Modifico el ngulo de rotacin sobre el eje Y
if (mjAngleY l O.Of)
rad.RotateY(mfAngleY) ;
rnd.ProcsVerts(jverts, 12);

En primera instancia modificamos la matriz de mundo y la llevamos a su valor iden


tidad. Luego, si la propiedad m_fEscalaX o m_fEscalaY o m_fEscalaZ es distinta de
uno, invocamos el mtodo Scale de Renderer.
De modo anlogo, si la propiedad m_fAngY es distinta de cero, invocamos el mto
do RotateY de la clase Renderer.
Para concluir, invocamos el mtodo ProcsVerts para procesar los vrtices.

El mtodo ProcsVerts de la clase Renderer


public void Proc0Verts(Cu8toaVertex.PoBtionColored[] verts, int iVertCount)

(
mdevice.VertexFormat = CuatomVertex.PositionColored.Format;
mdevice.DrawDserPriBiitives (PrimitiveType .TriangleList,
iVertCount / 3, verts);

El mtodo

ProcsVerts,

que se encuentra incluido en la clase

Renderer,

tiene la

funcin de procesar los vrtices recibidos. Para ello, actualizaremos la propiedad


u s r .c o d e

35S

PROGRAMACIN C#

VertexFormat de la clase Device al formato del vrtice que nos disponemos a pro
cesar. Luego, invocamos el mtodo DrawUserPrimitives. En el primer parmetro
especificamos el tipo de primitiva, en el segundo parmetro detallamos qu can
tidad de primitivas hay que realizar y, por ltimo, pasamos el array donde se en
cuentran los vrtices de nuestro objeto.

Los tipos de primitivas


Tal como lo habamos mencionado anteriormente, Direct3D slo sabe de tringu
los; esto significa que todo objeto que deseemos dibujar deber estar formado por
esta figura geomtrica bisica.
Sin embargo, es posible indicarle que a partir de un grupo de vrtices dibuje tam
bin puntos y lneas con distintos criterios. Veamos cules son estas primitivas:
EJEMPLO
PointList

Lista de puntos, Direct3D tomar cada vrtice del grupo

vl

v3

v5

y dibujara un punto en su posicn.


v2

LineUst

v4

v6

lista de lineas, Direct3D tomar oe a dos vrtices


y los utilizar para trazar segmentos independientes.

v2 V4 v6
LineStrip

Tira de lneas, Direct3D tomar ios dos primeros vrtices del grupo
y trazar un segmento, luego tomar el siguiente elemento y trazar
otro segmento conectado coo ei antenor, y as sucesivamente. De este
modo queda formada una sucesin de segmentos conectados entre s.

Tnanglelist

Lisia de tringulos, Drect3D tomar de a tres'vrtices formando

vi

v3

v5

vi

v3

v5

tringulos independientes.

TriangleSrip

Tira de tringulos, Direct3D tomar los primeros tres vrtices


y formar un tringulo, luego tomar el siguiente vrtice y, haciendo
uso de los dos anteriores formar otro tringulo, y asi sucesivamente.

v2

TriangieFan

v4

v6

Fan de tringulos, Direct3D tomar el primer vrtice y otros


nos con los que formar un triangulo, luego tomar otros
des y junto con el primero crear otro triangulo, y asi sucesivamente

v
Tabla 1. Tipos de primitivas.

360

u i.c o d e

E j e c u t a r la a p l ic a c i n

EJECUTAR LA APLICACIN
La escena puede ser rotada en los ejes X e Y por medio del uso del mouse, y tam
bin estaremos en condiciones de modificar la escala de la pirmide en cualquiera
de sus componentes y hacerla rotar sobre su eje Y. Todo esto, sencillamente, mani
pulando las matrices de mundo y vista.

Figura 7. Nuestra aplicacin en accin.

En el sitio web

onweb.tectimes.com, se encuentra disponible para su descarga la

aplicacin de ejemplo que acompaa este captulo.

resum en

Direct3D es una API extensa y compleja, pero las posibilidades que ofrece son prcticamen
te ilimitadas. Sus usos tambin son muy variados, y no slo se utiliza en juegos de compu
tadora, sino tambin en aplicaciones de medicina, visualizacin de terrenos, grficos esta
dsticos dinmicos en 30, etc.

u s r .c o d e

361

ACTIVIDADES

TEST DE AUTOEVALUACIN
1 Se puede modificar la posicin de un obje

U Cmo pinto un tringulo Direct3D si ste

to en pantalla sin variar la posicin de sus

posee colores diferentes en cada uno de

vrtices?

sus vrtices?

2 Cmo es posible que un vrtice de tres di

mensiones se multiplique a una matriz de

5 Es posible modificar las operaciones que

se suceden dentro del pipeline?

4x4?

diUMliZftddfl
(troifswj

puodtNmu
litwxj

3 Para qu me convendra descartar vrtices

no visibles? Acaso el pipeline no los termi


na recortando en el proceso de recorte?

362

.c o d e

PROGRAMACIN C#

Apndice

[-----------------------------'

Documentacin
de cdigo
La documentacin del cdigo de un
sistema (en un formato prctico) es una
tarea ardua y tiende a quedar obsoleta
con el devenir de nuevas versiones.
Pero el cdigo de un programa
debera estar debidamente comentado
para facilitar el trabajo del
programador y evitar los errores
derivados de una mala interpretacin
de lo que debera hacer una funcin.

Cmo documentar cdigo

SERVICIO DE ATEHCIK AL LECTOR: le C to re S @ m p e d C O n e S .C O m

364

Los tags disponibles


Otras herramientas

367

Para crear documentacin

368

PROGRAMACIN C#

CMO DOCUMENTAR CDIGO


Tanto fastidio suele acarrear esta labor, que muchas veces no se realiza, o se hace s
lo en la primera versin, o se efecta parcialmente con las clases ms importantes
del sistema. Por suerte, existen herramientas que facilitan tal tarea.
Bsicamente, toman la informacin de los comentarios que insertamos en el cdi
go (con un formato especial), la procesan y generan un documento que puede
abrirse con alguna aplicacin de uso estndar. El compilador C# provee una de esas
herramientas y genera documentacin XML de nuestro cdigo.
Veamos un ejemplo de nuestro cdigo:
; ///
/,/ <summary>
/// Descripcin del namespace ProgCS

lll

</summary>

namespace ProgCS

lll
lll

<summary>
Descripcin de la ciase Classl

/,// </summary>

///
claas Classl

lll
H
lll

<summary>
Descripcin del mtodo mi
</suramary>

public void m i {)

{
}
/// <summary>

lll
lll

Descripcin del mtodo m.2


</sumnary>

public void m2()

{
}

j!
lll

<summary>
Descripcin del mtodo mi

/// </summary>

364

u t 't .c o d e

C m o d o c u m e n ta r c d ig o

/// <param natne="num" descripcin parmetro num</param>

/// <retums>Descripcin del retorno del mtoc</returns>


public bool m3(int num)

{
return true;

}
}

Si compilamos nuestro cdigo en comando de lnea, usando directamente el com


pilador (csc.exe), entonces deberemos aplicar el switch /doc del siguiente modo:
esc otrasopciones /'doc :nombre_archivo

Veamos un ejemplo para el cdigo anterior:


esc Classl.c8 /doc:docxml.xml

Hecho esto, el compilador generar (adems de la salida usual del programa com
pilado) un archivo llamado docxml.xml (podra llamarse de cualquier otro modo),
que para nuestro ejemplo poseer el siguiente contenido:
<?xml version="1.0,'?>
<doc>

<assembly>
<name>Classl</naine>
-c/assembly?
<members>
<member name="T:ProgCS.Classl">
<suinmary>
Descripcin del namespace ProgCS </summary>
</member>
cmember name="H:ProgCS.Clasel.ml">
<summary>
Descripcin del mtodo mi
c/summary?
</member>

u s r .c o d e

365

PROGRAMACIN CU

<memher

n<uae="J:ProgCS .Classl .m2K>

<aummary>
Descripcin del mtodo m2
</summary>
</member>
<member name="M:ProsCS.Claasl ,m3 (System.Int32)">

<summary>
Descripcin del mtodo m3
</summary>
<param name=',nun*>Descripcin parmetro num</param>
<returns>Descripcin del retorno del mtodo</returns>

</member>
</members>
</doc>

Si trabaja con el excelente Visual Studio .NET, no querr abandonarlo por un se


gundo. Lo mismo puede especificarse en las propiedades del proyecto, en la seccin

Configuraron Properties, subseccin Build,

y all, en XML Documentation

OocXml Property Pagos

File.

orfiguration: |ActiYt<Debug)

EJatfotm: fActvc( NET)

E3

L j Common Properte-s
G j Conbguratco Properties

jr ]

CQnfijxatJcn Manager.,.

<

Condticnal Conpjlicn Constan OE0UG; TRACE

y Cutd

Optimia Code

Debugpng
Advenced

Falte

Oreckfor Arthmetic Overfbw/l False


Altow Untale Code Blocks
Q .< * W
Warner Level

Falte
Waming level 1

Treat Warnioj As Errors

Falte

Suppress Specic Warrmgs


3 .
OutpiA Fath

b<n\Debug\

Generate Debuw^ Informado* Trut


-V i
w

: '

X M l D o c u m e n ta tio n F ie
Specfie the ame dt a We hto *hctr docimeotation comments ivtfi be
pcocessod. Path mus be relaive lo the pro)ect rectory (/doi:).

| Acepta

Cancdar

Ayuda

Figura 1. Propiedades del proyecto.

Si en lugar de un archivo XML deseamos obtener archivos HTML, navegables en cual


quier browser, es posible utilizar una facilidad de Visual Studio .NET. sta puede
ser accedida desde el men Tools, opcin Build

366

Comment Web Pages (Figura 2).

u s r.c o d e

C m o d o c u m e n ta r c d ig o

Build Comment Web Pages


(* BuM fec entiro Solution
t" Buid for sottfed Efojects;
1

i
;
;

i
i
ave Web Pages in:
| C:lprojects\DocXirACosifr:onnmeRetrt

firOWM... i

'y Fot SK iitr, disky HTML in comnent-; m ieit


T dd !o Favoie:

&

tfeip

Figura 2. Creando pgina de ayuda en formato HTML.

Presionando el botn

OK, podremos ver el resultado de la operacin en una de las

pginas abiertas por el entorno, o bien podremos abrirla con cualquier navegador.
Code Comment Web Report
UUmf |

"71

P r o g c s . c ia s s i c la s s
Dcisrce** del ivt.ii.-k frc?:s

u.

0wijvJn dl mnodo n:

Figura 3. Una de las pginas generadas por la herramienta.

Las pginas generadas se encuentran divididas de modo vertical. A la izquierda


podemos seleccionar qu espacio de nombres o clase deseamos consultar por infor
macin, y a la derecha se nos presenta la informacin respectiva.

Los tags disponibles


Todos los tags (marcas) dentro de nuestro cdigo deben ser colocados dentro de un
comentario con una barra extra:

III

> j\

' V' '

Veamos algunos de los tags ms importantes:


<summary>...</summary>: es uno de los ms importantes. Especifica un resu
men de la estructura que precede. Por ejemplo:
u s r .c o d e

367

PROGRAMACIN C#

/// <summary>
/// Descripcin del mtodo mi
III

</sununary>

public void ml()

{
}

<param = >...</param>: permite especificar y describir un parmetro.


/// <sumtnary>
III

</summary>

/// <param name="num'


>Descripcin parmetro num</param>
public bool m3(int num)

{
}

<returns>...</returns>: permite especificar qu debe devolver un mtodo.

III

<sumniary>

/// </summary>
III

<retrns>Descripcin del retorno del mtodo</returns>

public bool m4()

{
return true;

<example>...</example>:

nos permite especificar un ejemplo de uso de la clase,

mtodo, variable, etc.


<code>...</code>: nos permite especificar un trozo de cdigo (usualmente este
tag se coloca dentro del tag de example).

Otras herramientas para crear documentacin


Existe otra herramienta muy popular que trabaja de un modo similar al que vimos.

Su nombre es Doxygen y se puede descargar libremente desde www.doxygcn.org,


Doxygen genera documentacin en formato HTML, LaTeX, RTF, PostScript,
PDF y HTML comprimido (chm).

368

u s r .c o d e

PROGRAMACIN CS

Apndice B

La notacin
Hngara

*' .

La notacin Hngara es una convencin


de nombramiento de variables
y funciones. Es muy utilizada
en programacin en el lenguaje C++.
Tambin tiene una m enor incidencia
en lenguajes como C# y Java.
En este apndice veremos los conceptos
fundamentales.

La convencin
Un tipo base
Un prefijo
Un calificador

370
370
370
371

Algunos ejemplos

371

Ventajas y desventajas

servicio de atencin al lector:

lectores@mpediciones.com

de la convencin

372

PROGRAMACIN CS

LA CONVENCIN
Al nombrar las variables, dificultamos la lectura del programa. Si a una variable sim
plemente la llamamos X , luego podramos no recordar su contenido, ocasionando
errores o retrasos en la codificacin.
Los identificadores de esta notacin se dividen en tres partes.

Un tipo base
Corresponde a la variable que ser nombrada. No siempre corresponde a un tipo de
dato fundamental, sino a uno ms abstracto. Debe ser escrito en minsculas.
1 TIPO BASE H f f l H I
Short

s
h ,n
:

Int

Long

US

Usliort

ui

Uint

ul

Ulong

Char

Double

Roat

le
b

Enum
Bool

Tabla 1 .Datos de tipo base.

Un prefijo
Se especifica antes de! tipo base y describe el uso de la variable.

Array

Contador

Diferencia entre dos variables del mismo tipn

Elemento de un array

Variable global

; >
i

Handler (manejador)
ndice de un array

m_

Variable miembro

Puntero
Tabla 2. Prefijos.

370

u s r .c o d e

A lg u n o s e je m p lo s

Un calificador
Es la parte descriptiva de la variable o funcin que completa el nombre. Se reco
mienda usar nombres que tengan un significado apropiado con cada variable.
Si un calificador est compuesto por ms de una palabra, stas se escribirn juntas,
pero se colocar la primera letra de cada palabra en mayscula (no se permite la se
paracin de palabras con guiones de ningn tipo).

Lista de calificadores estndar


Debido a que cierto tipo de variables aparecen en una gran cantidad de programas,
se recomienda utilizar los nombres sugeridos por la notacin.

mn

El elemento ms pequeo de una lista o array

first

0 primer elemento de una lisia o anay

last

El ltimo elemento de una lista o array

lint

Un nmero lmite o umbral

max

El elemento mas grande de una lista o array

i, j, K, m,n

Contadores
Tabla 3. Calificadores estndar.

ALGUNOS EJEMPLOS
Veamos, finalmente, algunos ejemplos de nombramientos:

Identificador

m_iCantidad

U-Jui

i
-Calificador. Relacionado con el fin o oso de la variable.
. Tipo base. En este caso indica que el tipo de date
de la variable es un nmero entero.
. Prefijo. En este caso indica que
la variable es miembro de una clase.

Figura 1. Ejemplo de nombramientos.

Cmo nombraramos una variable que contuviera:

usr.code

371

PROGRAMACIN CU

la edad de una persona (variable local)?:


cador; no posee prefijo).

iEdad (i es el tipo base, y Edad,

la edad de una persona (propiedad de una clase)?:

el califi

m_iEdad (m_ es el prefijo que


Edad es el cali

indica que la variable es miembro de una clase, i es el tipo base y


ficador).

el resultado de una operacin (variable local)?: bRes (b es el tipo base [bool] y Res
es el calificador que abrevia la palabra resultado; no posee prefijo).
un array de nmeros flotantes que correspondiese a una lista de medidas (propie
dad de una clase)?: m_afMedidas
po arrayj,

(m_a es el prefijo [propiedad de una clase y de ti


f es el tipo base [floatj y Medidas es el calificador).

el nmero ms pequeo que se obtiene en un bucle?: min (nombre estndar).


un contador utilizado dentro de una sentencia for?: i (nombre estndar).

VENTAJAS Y DESVENTAJAS DE LA CONVENCIN


Ahora, podramos estar preguntndonos por qu deberamos utilizar esta conven
cin. En primer lugar es muy recomendable adoptar alguna convencin amplia
mente utilizada, ya que de participar en un proyecto de construccin de software
integrado por muchas personas, leer cdigo ajeno ser mucho ms sencillo.
Ventajas propias de la notacin Hngara:
Permite conocer el tipo de variable solamente viendo el identificador.
Los nombres fijados con esta convencin quedan relativamente cortos.
Es ampliamente utilizada.
Quienes no gustan de esta notacin esgrimen principalmente dos motivos:
El identificador queda ligado al tipo de dato; por lo que si queremos cambiar el
tipo de la variable, deberemos cambiar su nombre en todas las ocurrencias.
Los identificadores, en algunos casos, son difciles de leer a primera vista.
La razn por la cual la convencin en lenguajes como C'# y Java no es tan popular
radica principalmente en la evolucin de los entornos de desarrollo integrados que
ofrecen la informacin de tipos de datos y caractersticas de una variable simple
mente con posar el puntero del mouse sobre ellas.
Sin embargo, en cdigo impreso, el entorno de desarrollo no podra ser utilizado, y
en el anlisis de una gran porcin de cdigo por medio de la notacin Hngara
identificaramos las caractersticas de variables de manera inmediata.
372

usr.code

PROGRAMACIN C#

Apndice

UML
El lenguaje de modelado unificado,
tambin conocido como UML, es un
sistema notacional destinado al modelado
de aplicaciones que se basen,
principalmente, en conceptos de la
programacin orientada a objetos.

Introduccin
374
Diagramas de casos de uso "3 7 4
Diagramas de clases
'375
Diagramas de objetos
' 375
376
Diagramas de secuencia

servicio de atencin al lector:le cto res@ m pe dicio ne s.com

Diagramas de estados
Diagramas de colaboracin

377
378

Diagramas de actividad
Diagramas de componentes
Extensiones a UML

379
380
380

PROGRAMACIN C#

INTRODUCCIN
El U M L se encuentra compuesto por una serie de diagramas que nos ayudarn a di
sear y documentar los diferentes componentes del sistema.
Muchos programadores comienzan sus proyectos escribiendo cdigo, pero en proyec
tos de gran complejidad, esto es un error, sobre todo si existe un equipo de trabajo
donde muchos programadores deben trabajar en distintas piezas de un rompecabezas.
Qu ocurrira si luego de meses de ardua labor las piezas no se conectaran correcta
mente? Sera necesario un anlisis y un diseo: U M L es la herramienta para ello.
Veamos cada uno de los diagramas y los elementos que componen este sistema.

Diagramas de casos de uso


Es una visin de la comunicacin usuario/sistema. Es ms til en sistemas que po
sean un flujo de trabajo, donde distintos usuarios (actores) acceden al sistema des
de distintas interfaces. Los casos de uso describen la funcionalidad de un sistema y
su utilizacin por parte de los usuarios. Contienen los siguientes elementos:
Actores: representan a los usuarios del sistema (humanos u otros sistemas).
Caso de uso: representa una determina funcionalidad provista por el sistema a los
usuarios.

Figura 1. D iagram a de casos de uso.


u rr.c o d e

In tro d u c c i n

Diagramas de clases
Describen la estructura esttica de un sistema, crr.o se encuentra estructurado ms
que cmo se comporta. Contiene los siguientes elementos:
Clases: que representan entidades con caractersticas comunes (atributos, opera
ciones y asociaciones).
Asociaciones: que representan relaciones entre eos o ms clases.
Es uno de los ms populares. Posee distintos niveles de detalles (mostrando o no
atributos y operaciones).

cardinalidad s

Figura 2. Diagrama de clases.

Diagramas de objetos
Describen la estructura de un sistema en un determinado momento; el diagrama de
clases lo hace en todo tipo de situacin (ya que no es posible crear clases de modo
dinmico), pero la cantidad de objetos de nuestro sistema puede cambiar durante
la ejecucin.
Contiene los siguientes elementos:
Objetos: representan entidades en particular. Son instancias de clases,
usr.code

375

PROGRAMACIN CS

Enlaces: representan relaciones entre objetos. Son instancias de asociaciones.

- -

NaveOl: Sprte

Nombre
de la clase

* -

chequearCollsln =si
-----------

posicin x *=10
posicin y
=40
.
1
1

.......
relacin de
/
"composicin/

textOl: Textura

nombre - nave01.bmp
tam x -128
tamy =128 * ------

- -propiedades

Figura 3. Diagrama de objetos.

Diagramas de secuencia
Describen interacciones entre objetos. Estas interacciones se modelan como inter
cambio de mensajes. Estos diagramas se focalizan en los mensajes que se intercam
bian para mostrar determinado comportamiento o accin.
Contiene los siguientes elementos:

Roles de clases: representan las funciones que los objetos asumen en determina
das interacciones.

Lneas de vida:

representan la existencia de un objeto durante un perodo de

tiempo.

Activaciones: representan el tiempo durante el cual un objeto se encuentra reali


zando una accin especfica.

Mensajes: representan la comunicacin entre dos objetos.


Son especialmente tiles para especificar la precedencia necesaria en la invocacin
de mtodos de unos objetos en particular.

376

t:s :r.c o c le

In tro d u c c i n

objeto

objeto annimo

Figura 4. Diagrama de secuencia.

Diagramas de estados
Los objetos poseen un estado, y es posible que la accin que ejecutarn en funcin
de estmulos externos se base en el estado en el que se encuentren. El diagrama de
estados se encarga de describir cules son los posibles para un determinado objeto
y de que modo se pasa de uno a otro. Est compuesto por los siguientes elementos:
Estados: representan situaciones durante el tiempo de vida de un objeto cuando
se cumplen ciertas condiciones, se realiza o se espera la ocurrencia de un evento.
Transiciones: representan relaciones entre los diferentes estados de un objeto.
u s r .c o d e

377

PROGRAMACIN C#

estado final

Figura 5. Diagrama de estados.

Diagramas de colaboracin
Describen la interaccin entre clases y asociaciones. Estas interacciones son mode
ladas como intercambios de mensajes entre clases a travs de sus asociaciones.

direccin de los
mensajes

1. Solicita la creacin del jugador correspondiente


1.1 Crea el jugador
secuencia de mensajes

Figura 6. D iagram a de colaboracin.

378

usr.code

In tro d u c c i n

Contiene los siguientes elementos:


Roles de clases: representan las funciones que asumen los objetos.
Roles de asociacin: representan las funciones que los enlaces deben asumir en
una interaccin.
Flujo de mensajes: representan los mensajes enviados por objetos a travs de en
laces. Los enlaces implementan la distribucin de mensajes.

Diagramas de actividad
Describen la actividad de una clase determinada. Estos diagramas son similares a los
de estado y utilizan una convencin similar, slo que describen el comportamiento
de una clase en respuesta a procesos internos, y no a eventos externos.

estado
inicial

estado de
accin

Patrullar
decisin

<>"

[no se avista
enemigos)

[se avista
eriem.go]
flujo de
/ control

ry [fuera de
alcance de
vistasj
__________ /
[enemigo
muerto]

estado
final

Figura 7. D iagram a de actividad.

usr.code

379

PROGRAMACIN Cfl

Estados de accin: representan acciones atmicas (o no interrumpiles), pasos en


la ejecucin de un algoritmo.

Flujos de acciones:

representan relaciones entre diferentes estados de accin de

una entidad.

Flujos de objetos:

representar, la utilizacin de objetos por estados de accin y la

influencia de stos en otros objetos.

Diagramas de componentes
Describen la organizacin y dependencia entre los distintos componentes de soft
ware en una implementacin. Sus componentes representan unidades fsicas distribuibles, incluyendo cdigo fuente, cdigo objeto y cdigo ejecutable.

dp

Motor del juego i

CZZI

' ' Lincas que indican


dependencias
de os componentes

Figura 8. Diagrama de componentes.

Extensiones a UML
Un diagrama puede ser incapaz ce expresar una cierta arista de nuestro sistema. Por
dio U M L posee un sistema de extensin y personalizacin con el cual se puede
agregar nueva simbologa a los diagramas existentes, para que se adapten a nuestras
necesidades y poder usar nuevos estereotipos, propiedades, valores y restricciones.
380

.c e d e

PROGRAMACIN C#

Servicios
al lector
En esta seccin encontrar una completa
gua de sitios que contienen compiladores
para la plataforma .NET. Adems,
el ndice temtico, que le permitir
acceder al contenido de este manual
de forma precisa y rpida.

servicio de atencin ai lector:

lectores@mpediciones.com

Lenguajes .NET

382

ndice temtico

385

PROGRAMACIN C#

LENGUAJES .NET
En ia siguiente lista se detallan compiladores especficos que generan cdigo en

MSIL para poder ser ejecutados sobre plataforma .NET. En algunos casos son len
guajes nuevos, y en otros, compiladores basados en conocidos lenguajes que ante
ceden a .NET.
Como podr apreciar, no son pocos los emprendimientos que se sumaron a la mo

vida .NET,
1 LENGUAJE BASE

y cada da aparecen nuevos proyectos.


COMPILADOR

ENLACE A SITIO OFICIAL

A#

www.usafa.af.mil/dfcs/bios/mcc_htm/a_sharp.html

API

DyalogAPL

wyw.dyalog.com/

Basic

Visual Basic .NET

http://msdn.microsoft.com/vbasic/

i Basic

mbas

www.go-mono.com/mijas.html

c
ic

lee

www.cs.princeton.edu/software/lcc/

C1

http://msdamicrosofLcom/vcsharp/

mes

viww.go-mono.com/c-sharp.html

Ada

C#
m

o n o . .

D w nkrfdt O tK )H uphti

So m u M i O m u m M i U sa J u p

0(tfi

Con Mono podremos


ejecutar nuestros
programas creados
en C# no slo en
Windows sino
tambin en Linux,
MacOsX y otras
plataformas.

C++

Managed 0+

Caml

F#

http://research.microsoft.com/projects/ilx/fsharp.aspx

0CAMIL

www.ppsjussieu.fr/-montela/ocamil/cocumentation.html

pCaml
Coboi

http://msdn.microsoft.com/vsiudio/techinfo/articles/upgrade/inanagedexi.asp

NetCobol

www.netcobol.com/

NetExpress

www.microfocus.com/products/netexpress/

Delphi

Delphi 2005

www.borland.com/delphi/

Delphi

DeLphi.NET

http://sourceforge.net/projects/delphinet

Eiffel

Eiffel .NET

www.eiffel.com/

forth

DeLtaForth.NET

wwwdataman.ro/dforth/

fjcobof

382

usr.code

L e n g u a je s .N E T

LENGUAJEBASE

COMPILADOR

ENLACEASITIO

Fortran

FNT95

www.silverfrost.com/1l/ftn95/ftn95_fortran_95_for_wndows.asp

B B B 8

Hugs98for.NET

. http://gakKS.com/~SQf/hugs98.net/

Mondrian

www.mondrian-scriptorg/

HaskeS

HaskeH.NET

fitm://pu>.tn.ufpebr/-rasMf/h3Ske}kfetnet/

Java

Visual J# .NET

http://msdn.mlcrosoft.com/vjstiarp/

Haskell

J# es una
implementacln
particular del lenguaje
Java realizada por
Microsoft. En vez de
ejecutarse sobre una
mquina virtual de
Java, se ejecuta sobre
la plataforma .NET.
Java

IKVK1.NET

http://weblog.ikvm.net/

JavaScript

JScript .NET

www.gotdotnet.com/team/jscript/

JavaScript

JANET

hitpy/janetjs.sourciforge.net/

Lxico

Lxico

http://riosur.net/

USP

DotLisp

http://sourreforge.net/projects/dotiisp/

RDNZL

www.weitz.de/rdnzl/

USP
. LOGO
LOGO
: La
Mercuiy
Mixal

Monologo

http://monocigo^oiiicefofgejiet/

Turtlelracks

www.mech.upatras.gr/-TObgroup/logo/turtletracks/index.html

ljua.NET

www.lua.mf.puc-rio.br/luanet/

Mercury on .NET

www.cs.mu.oz.au/research/mercury/dotnet.html

Moal

http://sowceforge.net/projflcts/mixiid/

Nemerie

http://nemerle.org/

Perl

PerlSharp

http://taubz.for.net/code/pertsharp/

Perl

PeriNET

http://aspn.activestate.com/ASPN/NET

Chrome

www.chromesvritexom/

TMT.NET

www.tmt.com/neLhtm

Nemerie

i Pascal
Pascal

PHP Mono Extensin*

www.php.net/-rterting/mono/

Prolog

P#

www.dcs.ed.ac.Uk/home/jjc/psharp/psharp-l.l/dlpsharp.html

: PHP

Python

boo

http://boo.codehausrorg/

Python

IronPython

http://ironpython.com/

Python

Pythonfor .NET

http://star5hip.python.net/crew/mhammond/dotnet/

u s r .c o d e

383

PROGRAMACIN C#

1 LENGUAJE BASE
Ruby

COMPILADOR

ENLACEASITIOORCIAL

NetRuby

www.geocities.co.jp/SiliconVailey-PaloAlto/9251/ruby/nrb.html
wwwialtypicWe.com/fubydotnet/

Rutt

ftutry/.NET

Scala

Scala on .NET

http://scala.epfl.ch/index.html

Scheme

Larceny

www.ccs.neu.edu/home/will/l3fceny/

Scheme

Dot-Scheme

www.rivendell.ws/riot-scheme/

Dot-Scheme: A P L T Scheme .N E T Bridgc

Welcome
Vchme i: the dvt-KhccK weftfAft d .M d m iri; 1 i L':~. i/.r fcotet I:- tht 1 w b T raratttw . h r. Ji i c<cf<cbe:_*r.i * ;;;< lFT
s-ff-rsf rd 'Z jirJ tr*rj.i.n hxr.Jk{. rej };<: f.r UTT
t u l i r A l.y Ij ito; feuxid l'T T ud .c. i

Casi todos los

Documentation
To Ujo ax< ahtit

lenguajes que al da

v-/* <>.

C V c k a th? St oteiifffjS
A t vhetK w s rk sio
f^
6y#.c tbeMtf rayyj
P w tbf 'K
t
r
x
'jr
:. f Or m ;

de hoy mantienen

U *. i--* b
>
&
r j l : tuefii!)

cierta popularidad

Download

en la comunidad

Tu* 4n-#thB*7soee4li.T.- h-cr.- vJtt . t M Vju-oeed v| ] of Ae ."?T : -- :!

*;* f- r .- T & ta :: vl.1<A |*K

in.:al*5 n - :f clrw rm u!':

versiones para .NET.

te pxaets

lbe dt4*tcbn:it Morra m? a1/> txUMr To bol tfi-uh'rrs yw mi nr*4

poseen sus

Vmul Ctui 7 I ;t ti* frr*

Scheme no es una
excepcin.

i
1.

HotDog

http://novef.cs.northwestefn.edu/-scbeme/

Scheme

Tachy

www.kenrawlings.com/pages/Tachy

Scheme

Scheme.NET

www.cs.indian3.edu/igrinbla/index.htm

SmallTalk

#SmallTalk

www.refactoiy.com/Software/SharpSmalltalk/

SmallTalk

VMXSmallTalk

http://vmx-net.com/

SML

SML.NET

www.cl.cam.ac.uk/Research/TSG/SMLNEf/

Spiy

Spiy

httpV/spry-lang.org/

Tcl/Tk

TickleSharp

http://forge.novell.com/modules/xfmod/project/7ticklesharp

384

u sr.code

n d ic e t e m tic o

INDICE TEMATICO
A

356

Dibujar objetos

Application

221

Diccionarios

190

Archivos

256

Direct3D

367

68

Arrays

158

Do

Arrays multidimensionales

173

Documentacin de cdigo

Asincrnico

335

Double

Atributos

301
B

...

366
66

j-

'
286

Errores

36

Base de datos relacional

266

Espacios de nombres

Bases de datos

263

Estructuras

109

Boxing/Unboxing

300

Eventos

201

Excepciones

287

break

77

Bucle

66
F
File

256

66

C#

20

Float

C++

22

Flujo de ejecucin

55

Clase

8?

for

70

156

Clases abstractas

19

CLR
Colecciones

185

Comentarios

38

foreach
Formularios
Framework .NET

68, 87

Constantes

128

Constructores
Continu

77

Controles

222

Convencin

370

Hashtable

191

Herencia

116

ICollection

188
18?

Convenciones de nombramiento

61

IComparable

Convert

52

Identificadores

Coordenadas 3D

365
D

Decimal

185

lEnumerator

185

If
279
66

60

lEnumerable

55

II st

18?

Indexadores

179

Delegados

196

Int

Destructores

132

Interfaces

u s r .c o d e

19

38

Consol

DataSet

76
227

63
153

385

PROGRAMACIN C#

Managed DirectX

364

Sentencia de bucle

Manipulando archivos binarios

260

Sentencias condicionales

Manipulando archivos de texto

257

Servicios web

Mtodos

89, 137, 204

Mtodos virtuales

145

Modificadores de acceso

122

MSIL

19

Short
Sincrnico
Sintaxis
Sobrecarga de mtodos
Sobrecarga de operadores

Sockets

.NET

19

Notacin Hngara

370

SQL
Streams
switch

System.Timers.Timer

Objetos

86

Operadores

53, 60,141
Tags

P
Palabras reservadas

v .'
40

params

172

Polimorfismo

137

Tipo base
Tipo de datos

42,

Prefijo

370

UML

ProcsVerts

359

using

Propiedades

123

Punteros

313

37

Variable

39,

Variables estticas

Reflection

307

Visual Basic 6.0

Renderer

359

Visual Studio .NET

Resolucin

209

w
while
Windows.Forns

66
196

WriteLine

386

u s r .c o d e

E q u iv a le n c ia d e t rm in o s

EQUIVALENCIA DE TRMINOS
1En este libro
Acceso dial up

Otras formas

T En ingls

Acceso de marcacin

Actualizacin

Update, Upgrade

Actualizar

Refresh
Bandwidth

Ancho de banda
Archivos

Filas, Ficheros, Archivos electrnicos

Files

Archivos adjuntos

Archivos anexados o anexos

Attach, Attachment

Backup

Copia de respaldo, Copia de seguridad

Balde de pintura

Bote de pintura
Database

Base de datos
Booteo

Inicio/Arranque

Boot

Buscador

Search enghe

Captura de pantalla

Snapshot
Folder

Carpeta
Casilla de correo

Buzn de correo

CD-ROM

Disco compacto

Compact disk

Chequear

Checar, Verificar, Revisar

Check

Chip

Pastilla

Cibercaf

Caf de Internet

Clipboard

Portapapeles

Cliquear

Pinchar

Colgar

Trabar

Tilt

Controlador

Adaptador

Driver
E-Mail,

Correo electrnico

Electronic Mail, Mail


Descargar programas

Bajar programas, Telecargar programas

Download
Defrag

Desfragmentar
Destornillador

Desarmador

Disco de inicio

Disco de arranque

Disco rgido

Disco duro, Disco fijo

Hard disk

Disquete

Disco flexible

Floppy drive

Firewall

Cortafuego

Startup disk

Formatear

Format

Fuente

Font

Gabinete

Chasis, Cubierta

Grabadora de CD

Quemadora de CD

Grupo de noticias

CD Burn
Newsgroup

PROGRAMACIN CU

E n este libro

Otras formas

Handheld

Computadora de mano

En ingls

HyperText

Hipertexto
Hospedaje de sitios

Alojamientc de sitios

Hub

Concentrador

Hosting

Impresora

Printer

Inalmbrico

Wireless
E-Book

Libro electrnico
Lista de correo

Lista de distribucin

Motherboard

Placa madre. Placa base

Mouse

Ratn
Browser

Navegador
Notebook

Mailing list

Computadora de mano,
Computadora porttil

Offline

Fuera de lnea

Online

En linea

Pgina de inicio

Home page

Panel de control

Control panel

Parlantes

Bocinas, Altavoces

PC

Computador, Ordenador, Computadora

Personal Computer

Personal, Equipo de cmputo


Pestaa

Ficha, Solapa

Pila

Batera

Plug & Play

Battery
Soundboard

Placa de sonido
Enchufar y usar

Por defecto

Por predefinicin

By default

Programas

Aplicacin, Utilitarios

Software, Applications

Protector de pantalla

Screensaver

Proveedor de acceso

Internet Service

a Internet

Provider

Puente

Bridge

Puerto Serial

Serial Port

Ranura

Slot

Red

Net, Network

Servidor

Server

Sistema operativo

SO

Sitio web

Site

Tarjeta de video

Placa de video

Tipear

Teclear, Escribir, Ingresar, Digitar

Vinculo

Liga, Enlace, Hipervnculo, Hiperenlace

38

Operating System IOS)

Link

u s r.c o d e

A b r e v ia tu r a s c o m n m e n te u tiliz a d a s

ABREVIATURAS COMNMENTE UTILIZADAS


V

Abreviatura

Definicin

ADSL

Asymmetric Digital Subscriber Une o Lnea de abonado digital asimtrica

AGP

Accelerated Graphic Port o Puerto acelerado para grficos

ANSI

American National Standards Institute

ASCII

American Standard Code of Information Interchange


o Cdigo americano estndar para el intercambio de informacin

BASIC

Beginner's All-Purpose Symbolic Instrudion Code

BIOS

Basic Input/Output System

Bit

Binary digit (Dgito binario)

Bps

Bits por segundo

CD

Compact Disk

CGI

Common Gateway Interface

CPU

Central Processing Unit o Unidad central de proceso

CRC

Cyclic Redundancy Checking

DNS

Domain ame System o Sistema de nombres de dominios

DPI

Dots per inch o puntos por pulgada

DVD

Digital Versalile Disc

FTP

File Transfer Protocol o Protocolo de transferencia de archivos

GB

Gigabyte

HTML

HyperText Mark-up Language

HTTP

HyperText Transfer Protocol

IDE

Integrated Device Electronic

IEEE

Institute of Electrical and Electronics Engineers

IP

Internet Protocol

IR

Infra Red

IRC

Internet Relay Chat

IRQ

Interrupt Request Line o Lnea de peticin de interrupcin

ISO

International Organization Standard u Organizacin de Estndares


Internacionales

ISP

Internet Service Provider o Proveedor de acceso a Internet

KB

Kilobyte

LAN

Local Area Nctwork o Red de rea local

LCD

Liquid Crystal Display o Pantalla de cristal lquido

LPT

Une Print Terminal

MB

Megabyte

MBR

Master Boot Record

MHz

Megahertz

u s r .c o d e

389

PROGRAMACIN CA

1 A breviatura

Y Definicin

NETBEUI

Network Basic Extended User Interface o Interfaz de usuario extendida

OEM

Original Equipment Manufacturer

OS

Operative System

NETBios

OSI

Open Systems Interconnection o Interconexin de sistemas abiertos

PCMCIA

Personal Computer Memory Card International Association

PDA

Personal Digital Assistant

PDF

Portable Document Format

Perl

Practical Extraction and Report Language

PGP

Pretty Good Privacy

PHP

Personal Home Page Tools, ahora llamado PHP Hypertext Preprocessor

P0P3

Post Office Protocol 3 o versin 3 del Protocolo de oficina de correo

PPP

Point to Point Protocol o Protocolo punto a punto

RAM

Random Access Memory

ROM

Read Only Memory

SMTP

Simple Mail Transport Protocol o Protocolo simple

SPX/IPX

Sequence Packet eXchange/Internetwork Packet eXchange o Intercambio

SQL

Structured Query Language

de transferencia de correo

de paquetes secuenciales/lntercambio de paquetes entre redes

SSL

Secure Socket Layer

TCP/IP

Transfer Control Protocol / Internet Protocol o Protocolo de control de


transferencia / Protocolo de Internet

UML

Lenguaje de Modelado Unificado

UDP

User Datagram Protocol

UPS

Uninterruptible Power Supply

URL

Uniform Resource Locator

USB

Universal Serial Bus

VGA

Video Graphic Array

WAN

Wide Area Network o Red de rea extensa

WAP

Wireless Application Protocol

WWW

World Wide Web

XML

Extensible Markup Language

390

u s r .c o d e

CLAVES PARA COMPRAR


UN LIBRO DE
COMPUTACIN

Sobre el autor
y la editorial

Revise que haya un cuadro


"sobre el autor", en el que se
informe sobre su experiencia
en el tema. En cuanto a la
editorial, es conveniente que
sea especializada en
computacin.

atencin
diseo
2 alPreste

Compruebe que el libro tenga


guas visuales, explicaciones
paso a paso, recuadros con
informacin adicional y gran
cantidad de pantallas. Su
lectura ser ms gil y
atractiva que la de un libro
de puro texto.

Compare
precios

Suele haber grandes


diferencias de precio entre
libros del mismo tema; si no
tiene el valor en la tapa,
pregunte y compare.

Tiene valores
agregados?

Desde un sitio exclusivo en la


Red hasta un CD-ROM, desde
un Servicio de Atencin al
Lector hasta la posibilidad de
leer el sumario en la Web
para evaluar con tranquilidad
la compra, o la presencia de
buenos ndices temticos,
todo suma al valor de un
buen libro.

Visite

nuestro

sitio web

Utilice nuestro sitio o nweb.tectim es.com :


Vea informacin ms detallada sobre cada libro de este catlogo.
Obtenga un capitulo gratuito para evaluar la posible compra
de un ejemplar.
Conozca qu opinaron otros lectores.
Compre los libros sin moverse de su casa y con importantes
descuentos.

. jf

Publique su comentario sobre el libro que ley.


Mantngase informado acerca de las ltimas novedades
y los prximos lanzamientos.
> Tambin puede conseguir nuestros libros en kioscos
o puestos de peridicos, libreras, cadenas comerciales,
supermercados y casas de computacin.

Verifique
el idioma

No slo el del texto; tambin


revise que las pantallas
incluidas en el libro estn en
el mismo idioma del
programa que usted utiliza.

onweb.tectimes.com

Revise la fecha
de publicacin

Est en letra pequea en las


primeras pginas; si es un libro
traducido, la que vale es la
fecha de la edicin original.

Compra Directa! usershop.tectimes.com

Conctese con nosotros y obtenga beneficios exclusivos:

ARGENTINA (OTI) 4959-5000 / (011) 4954-1791 > usershoD@mpediciones.com


MEXICO (55) 560M815 / (55) 5635-0037 / 01-800-0055-800 > usefshoomx@mped)ciones.ia)m
CHILE 562-335-74-77 / 562-335-75-45 > usershDDcl@mDediciflnes.com

You might also like