Sunteți pe pagina 1din 835

k.

rr ::::

G#

La biblia de

C#

Jeff Ferguson, Brian Patterson, Jason Beres, Pierre Boutquin y Meeta Gupta

Todos los nombres propios de programas, sistemas operativos, equipos hardware, etc. que aparecen en este libro son marcas registradas de sus respectivas compaas u organizaciones.

R e s e r v a d o s t od os los d e r e c h o s de esta ob ra esta

K1 c o n t e n i d o

p r o t e g i d o p o r la l e v . q u e

establece penas de prisin v o multas, a d e m a s de las c o r r e s p o n d i e n t e s i n d e m n i z a c i o n e s p o r daos v perjuicios, para quienes reprodujeren, plagiaren, distribuveren o c o m u n ic a s e n publi c a m e n t e . en to d o o en parte, u n a o b ra literaria, artstica cualquier o cientfica, tipo de o su transformacin, o comunicada a in te rp reta c i n o e j e c u c i n artstica lijada en soporte t r a v s d e c u a l q u i e r m e d i o , s i n la p r e c e p t i v a autorizacin

Copyright < ' 2003 by Anaya Multimedia. Original English language edition copyright ( 2002 by Hungry Minds. Inc. All rights reserved including the right o f reproduction in whole or in part in any form. This edition published by arrangement with the original publisher. Hungry Minds. Inc. Edicin espaola: ( E DI C IO NE S A NA YA M U L T I M E D I A ( G R U P O ANAYA. S . A ) . 200 Juan Ignacio Luca de Tena. 15. 2X027 Madrid Depsito legal: M. 3.033 - 2003 ISBN: 84-415-14X4-4 Printed in Spain Imprime: Imprime Artes Grfi cas Guemo. S.L. Febrero. 32. 2X022 Madrid.

Para mi fam ilia y amigos. J e f f h'erguson liste libro est dedicado a mi to, Brian Weslon, al que no pareci tarle cuando fui de visita v pa se todo el da con su TRS-HO Moda! II. Brian Patterson A N itin , que fue la motivacin. M eeta ( iupta

Agradecimientos
Jeff Ferguson: Pocos libros de este t amao y extensin son el fruto de un
solo individuo y ste no es una excepcin. Estoy en deuda con mu ch a gente por su ayuda y apoyo mientras escriba este libro. En primer lugar, debo dar las g r a cias a mis padres por la educacin que recib. Sin sus paternales consejos no me habra convertido en la persona que soy y no habra podido compl et ar ninguno de mis trabajos. Siempre os estar agradecido, no slo a vosotros, sino a toda la familia por el amo r y apoyo que siempre he recibido. Me gu st ar a dar las gracias a todo el mundo de Wiley por su direccin en la elaboracin de este material. Gracias. Andrea Boucher, Sharon Cox. Eric Nevvman y Chris Webb. por gui arme por el intimidador mundo de la publicacin de libros tcnicos. Gra ci as tambin a Rol f Crozier. que discuti conmigo este proyecto en primer lugar en sus primeros das. Debo dar las gracias especialmente a mi colega Bob k n u ts o n. que revis los borr adores del material de este libro. Graci as a Greg Frankenfield y a Paul Fridman por crear una excelente o rg an i zacin consultora bas ada en Microsoft que me permite t raba jar en los provectos de mis clientes j un to en los mos. El crecimiento tcnico que he ex peri ment ado durante mi estancia en Magenic ha sido incalculable. Esto es par a que contine el xito de Magenic. Graci as a todo el mundo de las listas de correo y grupos de noticias de D O T N E T en Internet. Estoy aprendiendo mucho sobre N E T Framcvvork y C# simplemente leyendo vuestros correos. Los envos de ac para all del banter me han dado una mayor comprensin de c mo encajan todas estas nuevas piezas.

Brian Patterson: Me gust ar a dar las gracias a mi esposa. Aimee. por p er do narme todas esas horas que pas escondido en el ordenador par a que pudiera completar este libro. Un agradecimiento especial a Steve Cisco por su duro t r a b a jo en este libro, que abri camino par a el resto de nosotros; a Sharon Cox. la editora de adquisiciones, que siempre me mant uvo en el buen camino; al editor de proyecto. Eric Nevvman. por a gua nt ar todos mis regates; y al editor de la serie. Michael Lae Th omas . que revis todos y cada uno de los captulos, haciendo algunas sugerencias muy buenas y propor ci onando una apreciable comprensin de Microsoft y N E T Framcvvork Pierre Boutquin: Se necesit mucho t rabajo p ar a crear este libro v no slo de la gente que aparece en la portada. Debo dar las graci as especialmente al equipo de Wiley por su tremendo esmero por producir un libro de calidad. Los revisores se merecen casi todo el crdito por hacerme parecer un escritor competente. Por ltimo, este trabaj o no h abr a sido posible sin el apoyo de mi familia y amigos: Sandra. Andrea. Jennifer y Paul. Tindy y Doel. Marcel y Diana Ban. Mar garet Fekete. y John y Nadine Marshall. Meeta Gupta: Agradezco a Anita que me diera la oportunidad. Pero mi mavor
agradecimiento es par a Nitin por. bueno, por todo.

Sobre los autores


Jeff Ferguson es consejero superior de Magenic Technologies, una c o m p a a consul tora de software dedicada a resolver probl emas empresariales usando exclusivamente herramientas y tecnologa de Microsoft. Ha sido p ro g ra ma do r de software profesional desde 1989 y ha desarrollado software par a Unix. DOS y W i n d o w s e m p l e a n d o C. C + + y C#. P u e d e e n v i a r un e - m a i l a J e f f en JeffF <7 mageni c.com (no olv ide incluir las tres "F" en el nombre de la direccin). Brian Patterson actualmente t rabaj a par a Affna. Inc.. como jefe del equipo tcnico, donde suele t raba jar con C ++ en H P -UX o en el desarrollo de Wi ndows con cualqui er versin de los lenguajes de Visual Studio. Brian ha estado es cri biendo par a varias publicaciones sobre Visual Basic desde 1994 y ha co-escrito varios libros relacionados con NET. incluy 'cndo Mi g r a t m g lo Visual Basic .N E T y N E T Ent erpri se De vel opme nl wilh VB.NET. Puede encontr rsele g e ne r al mente contri buyendo en los grupos de noticias de M S D N o puede ponerse en contacto con el por e-mail en BrianDPattersonY/ msn.com. Jason Beres ha sido p ro gr a ma do r de software durante 10 aos. Actualmente es asesor en Florida del Sur y trabaja exclusivamente con tecnologa de Microsoft. Jas on tiene los certificados MCT. M C S D y M C D B A de Microsoft. C uando no est enseando, as es orando o escribiendo, esta for mateando su disco duro, i nsta lando los ltimos productos beta de Microsoft y ponindose al da de los ltimos episodios de "Star T re k" . Pierre Boutquin es arquitecto superior de software en la tesorera de uno de los principales bancos canadienses, donde ayuda a desarrol lar software puntero par a la prev encin de riesgos de mercado. Tiene ms de una d cada de experi en cia introduciendo sistemas comput er izados basados en el PC con un exhaustivo conocimiento del diseo de si stemas distribuidos, al mac enami en to de datos. Vi sual Basic. Visual C ++ y SQL. Ha co-escrito muchos libros sobre programacin y ha contribuido con material sobre VB. C O M + . X M L y SQL a otros libros. Koshka y Sasha. sus dos adorables gatos de Birmania, ocupan casi todo el tiempo libre de Pierre. Mientras los acaricia, suele pensar en lo hermoso que sera e ncon trar ms tiempo par a volver al ajedrez o mantenerse informado sobre Blgica, su pas natal. Puede cont act ar con l en boutquinc/ hotmail.com. Meeta Gupta tiene una licenciatura en ingeniera informtica. Los sistemas de
redes son lo que ms le gusta. Actualmente t rabaj a en NII T Ltd.. donde disea, desarrolla y escribe libros sobre temas muy diversos. Ha co-escrito libros sobre TCP/ I P. A+ Certification. A S P . N E T y PHP. Tambi n tiene una a mplia experien cia diseando y desarrollando v arias ILT. Aparte de escribir. Meeta ha realizado cursos sobre C++. Sybase. Wi ndows NT. Unix y H T M L par a una audiencia div ersa, desde estudiantes hasta clientes corporativ os.

NIIT es una compa a de soluciones globales TI que produce productos de enseanza multimedia personal izados y tiene ms de 2. 000 centros de enseanza por todo el mundo. NII T tiene ms de 4. 000 empleados en 37 pases y tiene acuerdos estratgicos con varias de las principales corporaciones, incluidos Microsoft y AT&T.

Sobre el editor de la serie


Michael Lae Thomas es un activo p r o g r a m a d o r de c omuni dade s y un analista de la industria informtica que actualmente pasa la mayor parte de su tiempo difundiendo el evangelio de Microsoft . NET par a Microsoft. Mientras t r a b a j ab a con ms de media docena de editoriales. Michael ha escrito numerosos artculos tcnicos y ha escrito o participado en casi 20 libros sobre numerosos temas tcnicos, incluyendo Visual Basic. Visual C ++ y tecnologas N E T Es un prolfico defensor de la certificacin de p rog ramas de Microsoft y ya ha con se guido su MCSD. MCSE+I. MCT. M C P + S B y M C D B A Ademas de sus escritos tcnicos, tambin puede es cuchar a Michael en las ondas de vez en cuando, incluidos dos p rog ra ma s de radio s emanales en las c a d e nas Entercom (http://wvvvv.entercom.com/) y mas a menudo en la ciudad de k a n s a s en News Radio C ) 8 0 K M B Z (http://vvvvvv.kmbz.com/). Tambi n puede encontrarse con el en Internet haciendo un MS D N We b ca st (http://wwvv.microsoft.com/usa/ webeasts/) debatiendo sobre NET. la nueva generacin de tecnologas aplicadas a la Red. Michael empez su tray ectoria tcnica en su poca universitaria en la University o f Kansas. donde gan sus galones y un par de ttulos. Tras un breve trabajo como tcnico y asesor comercial p ar a Global Online Japan. con base en Tokio, regreso a los Estados Unidos para ascender por la escalera corporativa. Ha o c u pado puestos v ariados. incluyendo el de encargado de la IT. ingeniero de campo, instructor, consultor independiente e incluso un breve trabajo como C I O interino de una exitosa punto-com. aunque l cree que su actual papel como evangelista de N E T p ar a Microsoft es el mejor del lote. Puede c ont act ar con l va e-mail en mi thomas a nncrosoft.com.

ndice

A g r a d e c i m i e n t o s .................................................................................................................... Sobre los a u t o r e s ................................................................................................................... Sobre el editor de la s e r i e .................................................................................................... I n t r o d u c c i n ........................................................................................................................... Quin debera leer este l i b r o ............................................................................................. Cmo est organizado este l i b r o ...................................................................................... Parte 1: Fundament os del lenguaje C # .............................................................. Parte 11: Programacin orientada a objetos con C# .................................... Parte III: C# a v a n z a d o ........................................................................................... Parte IV: Desarrollando soluciones N E T usando C # ................................. Parte V: C# y N E T Framcwork ......................................................................... Parte VI: Apndices ................................................................................................ Cmo usar este l i b r o ............................................................................................................ Normas usadas en este libro ............................................................................................. P a r t e I. F u n d a m e n t o s del l e n g u a j e C # .................................................................. 1. I n t r o d u c c i n a C # ......................................................................................................... N E T Framework .................................................................................................................. Desarrollo W e b ...................................................................................................................... Desarrollo de a p l i ca c io ne s........................................................................................... Entorno comn de ejecucin ............................................................................................. Bibliotecas de clase N E T ...........................................................................................

6 7 K 29 30 30 30 31 31 31 31 31 32 32 35 37 38 38 3^ 40 41

Lenguajes de progr amaci n N E T ............................................................................. E n t o r n o A S P . N E T ........................................................................................................... Historia de C. C ++ y C # ..................................................................................................... Introduccin a ( '*'.................................................................................................................. Caract er st icas del l e n g u a j e ......................................................................................... C l a s e s ............................................................................................................................ Tipos de d a t o s ............................................................................................................. F u n c i o n e s ..................................................................................................................... Variables ...................................................................................................................... Inter faces ..................................................................................................................... A t r i b u t o s ...................................................................................................................... Cmo compi lar C # .......................................................................................................... Lenguaje intermedio de Microsoft (MS IL) ...................................................... M e t a d a t o s ..................................................................................................................... E n s a m b l a d o s ............................................................................................................... R e s u m e n ................................................................................................................................... 2. E s c r i b i r su p r i m e r p r o g r a m a en C # ....................................................................... Cmo escoger un e d i t o r ....................................................................................................... La aplicacin I lello W o r l d ................................................................................................. Como const rui r una clase ............................................................................................. El mtodo Mai n() ............................................................................................................ Cmo escribir en la c o n s o l a ......................................................................................... Compilacin y ejecucin del p r o g r a m a .......................................................................... Las p al abr as clave y los i d e n t i fi ca do r es ................................................................. Uso de espacios en b l a n c o ........................................................................................... Cmo iniciar progr amas con la funcin M a i n ( ) ......................................................... Corno comentar el c d i g o .................................................................................................... Cmo usar comentarios de una lnea ....................................................................... Usar comentarios regulares ......................................................................................... Como generar documentacin X M L a partir de c om e n t a r i o s ........................... < c > ................................................................................................................................. code ........................................' .................................................................................. example - ................................................................................................................... exception ................................................................................................................ list .............................................................................................................................. param ........................................................................................................................ paramre' - .................................................................................................................. permission .............................................................................................................. remarks .................................................................................................................... returns ..................................................................................................................... see .............................................................................................................................. secaIso .....................................................................................................................

42 43 43 45 45 45 46 47 47 4X 49 49 49 51 51 52 55 55 56 56 57 57 58 59 61 62 64 64 64 65 67 68 68 68 69 70 70 71 71 71 71 72

10

s ummary .................................................................................................................. < v a l u c > ......................................................................................................................... R e s u m e n .................................................................................................................................... 3. T r a b a j a r con v a r i a b l e s .................................................................................................. Cmo dar nombre a sus v a r i a b l e s ................................................................................... Asignacin de un tipo a una v a r i a b l e ............................................................................. Cmo aplicar t amao a sus v a r i a b l e s ...................................................................... Como declarar sus v a r i a b l e s .............................................................................................. Uso de valores por defecto en las v a r i a b l e s .................................................................. Asignacin de valores a v a r i a b l e s ................................................................................... Uso de matrices de v a r i a b l e s ............................................................................................. Declaracin de matrices u n i d i m e ns io na l es ............................................................. Como trabaj ar con los valores de las matrices u ni d ime ns iona les ............. Inicializacin de valores de elementos de m a t r i z ........................................... Declaracin de matrices mul ti di mens ional es ......................................................... Uso de matrices r e c t a n g u l a r e s ............................................................................... Definicin de matrices e s c a l o n a d a s .................................................................... Tip os de valor y de referencia .......................................................................................... Como convertir tipos de variable ..................................................................................... Conversiones i m p l c i t a s ................................................................................................ Conv ersiones expl ci t as ................................................................................................. Como trabajar con c a d e n a s ................................................................................................ Uso de caracteres especiales en c a d e n a s .................................................................. Desactivacin de los caracteres especiales en c a d e n a s ....................................... Como acceder a caracteres individuales en la c a d e n a ........................................ Declaracin de e n u m er a ci o ne s .......................................................................................... R e s u m e n .................................................................................................................................... 4. E x p r e s i o n e s ........................................................................................................................ Como usar los o p e r a d o r e s ................................................................................................... Uso de expresiones p r i m a r i a s ............................................................................................ Como usar los li teral es.................................................................................................. Literales b o o l e an os .................................................................................................... Como usar los literales enteros en notaciones decimales y hexadecimales ............................................................................................. Como usar los literales reales para v alores de coma f l o t a n t e .................... Como usar los literales de carcter para asignar valores de c a r a c t e r .... Como usar los literales de cadena para incrustar c a d e n a s .......................... Como usar los literales n u i l ................................................................................... Uso de i d e nt i f i c ad o r es .................................................................................................... Expresiones entre p a r n t e s i s ........................................................................................ C omo llamar a mtodos con expresiones de acceso a m i e m b r o s ....................

73 73 73 75 75 76 78 78 79 XI XI 82 83 84 85 85 87 88 89 89 90 92 92 94 95 95 96 99 99 100 100 101 101 103 104 104 104 105 105 106

11

Como l lamar a mtodos con expresiones de i n v o c a c i n ........................... Cmo especi fi car elementos de mat ri z con expresiones de acceso a elementos ................................................................................................... Cmo acceder a objetos con la pal abr a clave this ....................................... Cmo acceder a objetos con la p al ab ra clave b a s e ..................................... Cmo us ar los o per adores postfijo de incremento y de d e c r c m e n t o ...... Creacin de nuevos tipos de referencia con el op er ad or n c w ................... Cmo devolver i nformacin sobre el tipo con el op er ador t y p e o f ......... C mo us ar oper adores ehccked y unchecked ................................................ Las expresiones u a r a s .............................................................................................. Cmo devolver valores de operando con el oper ado r unario m s .......... Cmo devolver valores de oper ando con el oper ad or unario m e n o s ...... Expresiones negativas booleanas con el oper ad or de negacin lgica .. El oper ad or de compl ement o bit a b i t .............................................................. C mo prefijar oper adores de incremento y d e c r e m e n t o ............................. Los operadores a r i t m t i c o s ........................................................................................ Cmo a si gnar nuevos valores con el oper ador de a s i g n a c i n ................. Uso del o pe r ad or m u lt ip l ic ac i n ........................................................................ Uso del o per ador di \ i s i o n .................................................................................... Uso del oper ador r e s t o .......................................................................................... Uso del oper ador s u m a .......................................................................................... Uso del oper ador resta .......................................................................................... Los operadores de d e s p l a z a m i e n t o .......................................................................... Cmo mover bits con el operador de desplazamiento a la izquierda .... Cmo mover bits con el operador de desplazamiento a la d e r e c h a ...... Cmo c o m p a r a r expresiones con operadores r e l a c i n a l e s ...................... Cmo c om p r o b a r la igualdad con el oper ador de igualdad ...................... Como c o m p r o b a r la desigualdad con el oper ad or de d e s i g u a l d a d ......... Cmo c om p r o b a r valores con el oper ador menor que .............................. Como c om p r o b a r v alores con el operador mayor que .............................. Cmo c om p r o b a r v alores con el o per ador menor o igual q u e ................ Como c om p r o b a r v alores con el operador mayor o igual q u e ................ Op eradores lgicos e n t e r o s ....................................................................................... Cmo calcul ar valores booleanos con el oper ad or A N D .......................... Como calcul ar valores booleanos con el oper ador exclusivo OR ......... Como ca lcul ar valores booleanos con el operador O R ............................. Op eradores condicionales l g i c o s ........................................................................... C ompar ac in de valores booleanos con el oper ador A N D condicional Co mp ar ac i n de valores booleanos con el o per ador OR condicional ... Co mp ar ac i n de v alores booleanos con el oper ado r lgico c o nd i ci o na l ..................................................................................................... El orden de las operaciones ....................................................................................... R e s u m e n ...........................................................................................................................

106 107 108 109 109

1 10
110

110
113 113 113 113 114 114 115 116 116 117 118 118 119

120
120 121 122 122

122
123 123 124 124 124 125 125 126 126 126 127 127 127 129

12

5. C m o c o n t r o l a r el flujo del c d i g o ...................................................................... Instrucciones de C# ............................................................................................................. Instrucciones par a declarar variables l o c a l e s ....................................................... Como usar instrucciones de seleccin par a seleccionar la ruta del cdigo La instruccin i f ......................................................................................................... La instruccin s w i t c h ............................................................................................... Cmo usar instrucciones de iteracin para ejecutar instrucciones i n c r u s t a d a s ............................................................................................................. La instruccin vvhile................................................................................................. La instruccin d o ....................................................................................................... La instruccin f o r ...................................................................................................... La instruccin f o r e a c h ............................................................................................. Instrueeiones de salto para moverse por el c o d i g o .............................................. La instruccin break ................................................................................................ La instruccin c o n t i n u ............................................................................................ La instruccin goto ................................................................................................... Cmo usar instrucciones par a realizar clculos matemticos con s e g u r i d a d ......................................................................................................... R e s u m e n .................................................................................................................................... 6. C m o t r a b a j a r con m t o d o s ....................................................................................... La estructura de un mtodo ............................................................................................... Tipo d e v u e l t o .................................................................................................................... Nombre del mtodo ........................................................................................................ Lista de p a r m e t r o s ........................................................................................................ Cuerpo del m t o d o ........................................................................................................... Como llamar a un m t o d o ................................................................................................... Tipos de p a r m e t r o s ............................................................................................................. Parmetros de e n t r a d a .................................................................................................... Parmetros de s a l i d a ...................................................................................................... Parmetros de r e fer enci a............................................................................................... Matrices de p a r m e t r o s ................................................................................................. Sobrecarga de m t o d o s ........................................................................................................ Mtodos v i r t u a l e s .................................................................................................................. Mtodos s o b r e c a r g a d o s ................................................................................................. R e s u m e n ................................................................................................................................... 7. A g r u p a c i n de d a t o s u s a n d o e s t r u c t u r a s ........................................................ Cmo declarar una e s t r u c t u r a .......................................................................................... Cmo usar estructuras en el c d i g o ................................................................................ Cmo definir mtodos en e s t r u c t u r a s ............................................................................ Cmo usar mtodos c o n s t r u c t o r e s ............................................................................ Como llamar a mtodos desde estructuras ............................................................

131 131 132 133 134 13? 137 138 13X 139 142 142 H3 113 144 145 14^ 149 *49 1?** 1 1 1? I 1^1 1?? 1-^5 1^6 1 160 162 163 164 166 169 170 171 173 174 177

13

Cmo definir propiedades en e s t r u c t u r a s ..................................................................... Cmo definir indizadores en e s t r u c t u r a s ...................................................................... Cmo definir interfaces en e s t r u c t u r a s ........................................................................ Cmo usar los tipos simples de C# como e s t r u c t u r a s ............................................. R e s u m e n ................................................................................................................................... P a r t e I I . P r o g r a m a c i n o r i e n t a d a a o b j e t o s con C # ....................................... 8... E s c r i b i r cdi go o r i e n t a d o a o b j e t o s ................................................................... Clases y o b j e t o s ..................................................................................................................... Terminologa del diseo de s oftware orientado a objetos ...................................... A b s t r a c c i n ....................................................................................................................... Tipos de datos abstractos ............................................................................................ E n c a p s u l a c i n ................................................................................................................... H e r e n c i a ............................................................................................................................. He renci a s i m p l e ......................................................................................................... Herencia m l t i p l e ...................................................................................................... P o li m o r f i sm o ..................................................................................................................... R e s u m e n ................................................................................................................................... 9. C l a s e s de 0 ...................................................................................................................

178 179 181 182 185 187 1 89 192 192 193 193 195 197 197 198 199 202 205 205 206 207 207 209 209 210 212 212 215 216 216 217 217 222 222 223 226 226 228 228 230

Como declarar una c l a s e ................................................................................................... El mtodo M a i n ...................................................................................................................... Como u sar ar gument os de lnea de c o m a n d o s ...................................................... Cm o devol ver valores ................................................................................................. El cuerpo de la c l a s e ............................................................................................................ Cmo usar c o n s t a n t e s ................................................................................................... Como usar c a m p o s ......................................................................................................... Como us ar mtodos ....................................................................................................... Cmo usar propiedades ................................................................................................ Descri pt ores de acceso g e t ................................................................................... Descriptores de acceso s e t ................................................................................... Propiedades de slo lectura y de slo e s c r i t u r a ............................................ C mo us ar e x e n t o s ......................................................................................................... Como usar i n d i / a d o r e s .................................................................................................. Como us ar o p e r a d o r e s .................................................................................................. Como usar c o n s t r u c t o r e s .............................................................................................. Como usar d e s t r u c t o r e s ................................................................................................ Como usar los tipos de c l a s e ....................................................................................... Como us ar la pal ab ra clave this como identificado!'................................................. El modificador static ............................................................................................................ Cmo usar campos e s t t i c o s ....................................................................................... Como usar constantes e s t a t i c a s .................................................................................

14

Como usar mtodos e s t t i c o s .......................................................................................... 230 R e s u m e n ................................................................................................................................... .... 232 10. C m o s o b r e c a r g a r o p e r a d o r e s ........................................................................... 237

Operadores na n o s s o b r e c a r g a b l e s .................................................................................... 238 Cmo sobre carga r el unario m s ................................................................................... 238 Cmo so br ecar ga r el unario m e n o s .............................................................................. 240 Como s obre carg ar complementos bit a b i t ................................................................. 242 C mo s ob re c ar ga r el incremento p r e f i j o ................................................................ .... 244 Cmo s ob re car ga r el decrcmento p r e f i j o ............................................................... ....245 Cmo sobre carga r los operadores truc y tal s e .........................................................246 Operadores binarios s o b r e c a r g a b l e s ...................................................................................248 Ope radorcs de conversin s obrecargabl es ......................................................................25 1 Operadores que no pueden s o b r e c a r g a r s e .......................................................................253 R e s u m e n ................................................................................................................................... ....253 11. H e r e n c i a de c l a s e ...................................................................................................... ....2 5 7 Cmo c ompilar con clases m l t i p l e s .............................................................................. ....258 Cmo especificar una clase base en C # ...................................................................... ....259 m b i t o ....................................................................................................................................... ....260 C mo reutilizar identificadores de mi embros en las clases d e r i v a d a s ............... ....261 C mo t raba jar con mtodos h e r e d a d o s .............................................................................263 Mtodos virtuales y de r e e m p l a z o ............................................................................ ....263 P o li m or f is m o........................................................................................................................... ....265 Mtodos a b s t r a c t o s ........................................................................................................ ....267 Clases base: Cmo t raba jar con propiedades e mdizadores h e r e d a d o s .................268 Cmo usar la pal ab ra clave b a s e ...................................................................................269 Como acceder a campos de clase base con la p al ab ra clave base ..................270 Clases selladas ...........................................................................................................................270 Cont enci n y d e l e g a c i n .........................................................................................................270 La clase de objeto . N E T ..................................................................................................... ....277 Cmo usar boxing y unboxi ng par a convertir a tipo object y desde el tipo o b j e c t ............................................................................................................... ....279 R e s u m e n ................................................................................................................................... ....281 P a r t e I I I . C # a v a n z a d o ...................................................................................................... ... 283 12..C m o t r a b a j a r con e sp aci os de n o m b r e ............................................................. ... 285 C mo declarar un espacio de n o m b r e ............................................................................ ....286 Como declarar un espacio de nombre en varios archiv os f u e n t e ..............................287 C omo u sar clases en un espacio de n o m b r e ......................................................................288 C omo ayu da r a los espacios de nombre mediante la p al ab ra clave u s i n g ......... ... 290 Cmo crear alias de nombres de clase con la p al abr a clave u s i n g ................ ... 290

15

Cmo declarar directivas de espacio de nombre con la pal ab ra clave u s i n g ............................................................................................................. Un rpido recorrido por los espacios de nombre de N E T .................................... R e s u m e n ................................................................................................................................... 13. I n t e r f a c e s ....................................................................................................................... Cmo definir una i n t e r f a z .................................................................................................. Cmo definir mtodos de i n t e r f a z ............................................................................. Cmo definir propiedades de i n t e r f a z ...................................................................... Cmo definir indizadores de i n t e r f a z ....................................................................... Cmo definir eventos de i n t e r f a z .............................................................................. Cmo derivar a partir de interfaces b a s e ..................................................................... Cmo usar la palabra clave new para reutilizar i dentificadores........................... Cmo implementar interfaces en clases y e s t r u c t u r a s ............................................ Cmo i mplementar mtodos de interfaz con el mismo n o m b r e ............................ Cmo acceder a miembros de i n t e r f a z .......................................................................... Consultar a un objeto por una interfaz .................................................................... Cmo acceder a una interfaz en un o b j e t o ............................................................. Declaraciones de interfaz y pal abr as clave de m b i t o ....................................... Cmo implementar interfaces definidas por N E T Framework ........................... Cmo implementar foreach mediante IEnumerable I E n u m e r a t o r ................. Cmo implement ar l impieza mediante [ D i s p o s a b l e ............................................ R e s u m e n ................................................................................................................................... 14. E n u m e r a c i o n e s ........................................................................................................... Cmo declarar una enumeraci n .................................................................................... Cmo usar una e n u m e r a c i n ............................................................................................. Cmo usar operadores en valores de e n u m e r a c i n .................................................. Cmo usar la clase N E T S y s t e m . E n u m ...................................................................... Cmo recuperar nombres de e n u m e r a c i n ............................................................ Como c o mp ar a r valores de e n u m e r a c i n ............................................................... Como descubri r el tipo subyacente en tiempo de e j e c u c i n ............................ Como recuperar todos los valores de enumeracin ........................................... Anlisis de cadenas par a recuperar valores de e n u m e r a c i n ........................ R e s u m e n .................................................................................................................................... 15. E v e n t o s y d e l e g a d o s ................................................................................................. Como C mo Cmo Como Cmo Cmo definir d e l e g a d o s ....................................................................................................... definir ev e n t o s ........................................................................................................... instalar ev e n t o s .......................................................................................................... d es encad enar ev e n t o s ............................................................................................. unirlo todo ................................................................................................................... es tan da ri zar un diseo de e v e n t o .......................................................................

293 295 298 301 303 303 304 304 305 305 307 308 310 311 311 314 316 317 317 322 325 329 331 333 335 337 337 339 341 341 342 343 345 346 346 347 348 348 350

16

Como us ar descriptores de acceso de e v e n t o s ........................................................... Como us ar modificadores de e v e n t o s ............................................................................ Eventos e s t t i c o s ............................................................................................................. Eventos \ i r t u a l e s ............................................................................................................. Eventos de r e e m p l a z o .................................................................................................... Eventos a b s t r a c t o s .......................................................................................................... R e s u m e n .................................................................................................................................... 16. C o n t r o l de e x c e p c i o n e s ......................................................................................... Como especificar el procesamiento de e x c e p c i o n e s ................................................ Como ca ptur ar e x c e p c i o n e s .............................................................................................. Cmo usar la palabra clave t r y .................................................................................. Como at r ap ar clases especficas de e x c e p c i o n e s ............................................... Como liberar recursos despus de una excepcin .............................................. La clase exception ................................................................................................................ Introduccin a las excepciones definidas por N E T Framework Out O fMemory Except ion .............................................................................................. StackOverflow E x c e p t i o n .............................................................................................. N u l l R e f er e nc e Ex ce pt i on ............................................................................................... TypelnitializationException.......................................................................................... ln\ alidCast E xpre ss ion.................................................................................................... ArrayTx pcMi smat eh Except ion .................................................................................. I ndcxOut OfRange Except ion ....................................................................................... Di vi deByZer oExcept ion................................................................................................ Overflow E x c e p t i o n ........................................................................................................ Cmo trabajar con sus propias e x c e p c i o n e s ............................................................... Cmo definir sus propias e xc e p c i on e s ........................................................................... Cmo iniciar sus e x c e p c i o n e s .................................................................................... Cmo usar excepciones en constructores y p r o p i e d a d e s ................................. R e s u m e n ................................................................................................................................... 17. C m o t r a b a j a r con a t r i b u t o s ................................................................................ At r ibut os ................................................................................................................................... Como trabajar con atributos de N E T F r a m e w o r k .................................................... S\ stem Diagnostics Conditional A t t r i b u t e ............................................................... System.SerializableAttribute c l a s s ............................................................................ System. Obsolete Attribute c l a s s ................................................................................. Como escribir sus propias clases de a t r i b u t o .............................................................. Cmo restringir el uso de a t r i b u t o s ........................................................................... Cmo permitir multiples valores de a t r i b u t o .......................................................... Cmo asignar parmetros de a t r i b u t o ...................................................................... Ejemplo explicativo de las clases de a t r i b u t o ........................................................ R e s u m e n ...................................................................................................................................

353 354 354 355 355 3^5 359 361 362 362 362 364 365 365 366 366 367 368 368 369 369 370 370 371 372 373 374 376 379 380 383 384 386 388 390 390 391 392 394 396

17

18. C m o u t i l i z a r v e r s i o n e s en sus c l a s e s ........................................................... El probl ema de las v e r s i o n e s ............................................................................................ C omo sol uci onar el probl ema de las v e r s i o n e s .......................................................... Mediante el mo di fi cador nevv..................................................................................... Mediante el modi fi cador o v e r r i d e ............................................................................. R e s u m e n ................................................................................................................................... 19. C m o t r a b a j a r con cdi go no s e g u r o .............................................................. Conceptos bsicos de los punteros ................................................................................. Tipos de p u n t e r o .............................................................................................................. Como compilar cdigo no s e g u r o .................................................................................... Cmo especificar punteros en modo no s e g u r o ................................................... Como acceder a los v alores de los miembros mediante p u n t e r o s ................. Cmo usar punteros par a fijar variables a una direccin e s p e ci f i c a.................. Sintaxis del elemento de matriz p u n t e r o ................................................................. Como compar ar punteros ............................................................................................ Clculo con p u n t e r o s ...................................................................................................... Cmo usar el operador s i z e o f ..................................................................................... Cmo asignar espacio de la pila para la m e m o r i a ..................................................... R e s u m e n ................................................................................................................................... 20. C o n s t r u c t o r e s a v a n z a d o s de C # ........................................................................ Operadores implcitos y conv ersiones no vlidas ...................................................... Inicializacin de estructuras .............................................................................................. Cmo inicializar estructuras ........................................................................................ Cmo resolver los problemas con la inicializacin .............................................. Clases d e r i v a d a s .................................................................................................................... Cmo pasar clases d e r i v a d a s ..................................................................................... Como resolver problemas que surgen cuando se pasan clases derivadas .. Cmo usar no enteros como elementos de m a t r i z ..................................................... R e s u m e n ................................................................................................................................... P a r t e IV. C m o d e s a r r o l l a r soluciones . N E T u s a n d o C # ............................ 21... C m o c o n s t r u i r a p l i c a c i o n e s W i n d o w s F o r m s ............................................ Arqui tect ura de W i n d o w s F o r m s ....................................................................................... La clase F o r m ................................................................................................................... La clase A p p l i c a t i o n ....................................................................................................... Cmo crear la primera aplicacin W i n d o w s F o r m s ................................................... Como compilar una aplicacin Wi nd o ws Fo rm s ......................................................... Ensamblados: cmo aadir informacin de versin a las aplicaciones W i n d o w s F o r m s ........................................................................................................... Assemblv T i t l e ...................................................................................................................

399 399 402 402 404 406 409 410 411 412 413 414 415 416 41 7 417 418 419 419 423 424 425 426 427 429 429 430 431 434 435 437 438 438 438 439 440 441 442

18

AssembK D e s c r i p t i o n ..................................................................................................... As semb lyC on f gu rat i on................................................................................................. AssembK C o m p a n y .......................................................................................................... AsscmbK P r o d u c t ............................................................................................................ AssembK Copy r i g h t ........................................................................................................ As scmbK T r a d c m a r k ...................................................................................................... A s s c m b K C u l t u r e ............................................................................................................. As semb K V e r s i n ............................................................................................................. El objeto Application con mas d e t a l l e ............................................................................ Eventos A p p l i c a t i o n ........................................................................................................ Cmo t raba jar con eventos en el c d i g o ................................................................ Propiedades Application ............................................................................................... AllovvQuit..................................................................................................................... C o m m o n A p p D a t a R e g i s t r y .................................................................................... C o m m o n A p p D a t a P a t h ............................................................................................. Company a m e ........................................................................................................... C u rr e nt Cu l tu re ............................................................................................................ C u r r e n t l n p u t L a n g u a g e ............................................................................................. E x e c u t a b l e P a t h ........................................................................................................... l.ocall s e r A p p D a t a P a t h ......................................................................................... Mes sagc Loop ............................................................................................................. P r o d u c t N a m e .............................................................................................................. P r o d u ct V e rs i o n ........................................................................................................... SafeTopLev e l Ca p t i o n F o r ma t ................................................................................. S t a r t u p P a t h .................................................................................................................. I sei A p p D a t a P a t h .................................................................................................... r ser App Data Registry ............................................................................................. Mtodos A pp li cat ion....................................................................................................... AddM e s s a g e F i l t e r ..................................................................................................... DoEvents ..................................................................................................................... E x i t ................................................................................................................................. E x i t T h r e a d ................................................................................................................... O l e R e q u i r e d ................................................................................................................. O n T h r e a d E x c e p t i o n ................................................................................................. Remov e M c s s a g c F i l t e r ............................................................................................. R u n ................................................................................................................................. Como aadir controles al f o r m u l a r i o ............................................................................... Jerarqua de las clases de c o n t r o l ............................................................................. Como trabajar con controles en un f o r m u l a r i o ..................................................... Como trabajar con r e c u r s o s .............................................................................................. Como trabajar con recursos de c a d e n a ................................................................... Cmo trabajar con recursos b i n a r i o s ........................................................................ R e s u m e n ...................................................................................................................................

443 443 443 443 444 444 444 44.^ 447 447 448 449 450 450 450 4M 4^1 45 1 452 452 4^2 45.' 453 453 453 453 4M 454 454 457 457 457 457 458 460 461 461 462 462 465 465 468 468

19

22. C m o c r e a r apl icaci ones W e b con W e b F o r m s .......................................... Fundament os de las aplicaciones ASP.NET W e b ...................................................... Nuevas caractersticas de A S P . N E T ....................................................................... Ejecucin en el entorno N E T F r a m e w o r k ...................................................... Presentacin de WebForms .................................................................................. Integracin con Visual Studio . N E T ................................................................... Presentacin de los controles de s e r v i d o r ........................................................ Controles de usuario y c o m p u e s t o s .................................................................... Controles ms usados en W e b F o r m s ....................................................................... Control L a b e l .............................................................................................................. Control T e x t B o x ........................................................................................................ Controles ChcckBox y C h e c k B o x L i s t ............................................................... Controles RadioButton y R a d i o B u tt o n L i s t ....................................................... Control L i s t B o x ......................................................................................................... Control D r o p D o w n l . i s t ........................................................................................... Control H y p c r L i n k .................................................................................................... Controles Table. Tabl eRow y T a b l e C e l l ............................................................ Control I m a g e Bu t to n................................................................................................ Controles Button y LinkButton ............................................................................ Cmo crear y configurar una aplicacin W e b ............................................................. Como crear un nuevo p r o y e c t o .................................................................................. Cmo agregar controles al W e b F o r m ...................................................................... Cmo controlar e v e n t o s ................................................................................................ Viajes de ida y v u e l t a ............................................................................................... Controladores de e x e n t o s ....................................................................................... Cmo controlar la devolucin de datos ............................................................. Cmo usar el estado de v i s t a ................................................................................ R e s u m e n ................................................................................................................................... 23. P r o g r a m a c i n de bases de d at o s con A D O . N E T ...................................... Clases Dataset y otras clases r e l a c i o n a d a s ................................................................ Compatibilidad con OLE DB SQL S e r v e r .................................................................... Operaciones de bases de datos comunes mediante A D O . N E T ........................... Operaciones que no devuelven filas ......................................................................... Operaciones de datos que devuelven entidades de fila nica ........................ Ope raciones de datos que afectan a las entidades de fila n i c a .................... Ope raciones de introduccin de datos que afectan a las entidades de fila n i c a ..................................................................................................... Operaciones de actualizacin que afectan a entidades de fila n i c a ..................................................................................................... Operaciones de borrado que afectan a las entidades de fila nica .......... Operaci ones de datos que devuelven conjuntos de f i l a s .................................... Operaciones de datos que afectan a conjuntos de f i l a s .......................................

471 472 472 472 472 473 473 474 474 474 475 475 476 477 477 477 478 479 479 479 480 483 487 487 489 491 491 492 495 496 497 499 500 504 509 509 514 5 15 517 520

20

Op eraci ones que no devuelven datos jerrquicos ............................................... R e s u m e n ................................................................................................................................... 24. C m o t r a b a j a r con a r c h i v o s y con el r e g i s t r o de W i n d o w s ................. C omo acceder a a r c h i v o s ................................................................................................... Acceso b i n a r i o .................................................................................................................. B i n a r y W r i t e r ............................................................................................................... B i n a r y R e a d e r ............................................................................................................. C omo super visar los cambi os de a r c h i v o ............................................................... Como usar la supervisin de a r c h i v o s ............................................................... Como codificar FileSv s t e m W a t c h e r ................................................................... Corno manipular a r c h i v o s ............................................................................................. Cmo copiar a r c h i v o s .............................................................................................. Como eliminar a r c h i v o s .......................................................................................... Cmo t rasladar a r c h i v o s ......................................................................................... Como acceder al r e g is t ro .................................................................................................... Como leer claves del r e g i s t r o ...................................................................................... Como escribir clav es de registro .............................................................................. Como enumerar claves del r e g i s t r o .......................................................................... R e s u m e n ................................................................................................................................... 25. C m o a c c e d e r a s ec ue nc i as de d a t o s ............................................................. Jerarqua de clases de E/S de d a t o s ............................................................................... Como usar s e c u e n c i a s ................................................................................................... Como usar e s c r i t o r e s ..................................................................................................... Como usar l e c t o r e s ........................................................................................................ Cmo trabajar con secuencias ......................................................................................... E/S s i n c r n i c a ................................................................................................................... E/S a s i n c r n i c a ................................................................................................................. Como leer de forma a s i n c r n i c a .......................................................................... Como escribir de forma a s i n c r n i c a ................................................................... Escritores y lectores ............................................................................................................ Cmo escribir secuencias con B i na ry Wr i te r ......................................................... Cmo leer de secuencias con B i n a r y R e a d e r ........................................................ Como escribir X ML con un formato correcto mediante la secuencia X m l W r i t e r .................................................................................................................... R e s u m e n ................................................................................................................................... 26. C m o d i b u j a r con G D I + ......................................................................................... Como trabajar Como trabajar Cmo trabajar Como usar con g r f i c o s ............................................................................................... con Image en G D 1 + ................................................................................ con lpices y p i n c e l e s ............................................................................ la clase P e n ................................................................................................

522 527 529 529 530 530 531 533 534 538 539 539 540 >-+2 -"'44 -"'44 546 549 551 555 555 556 557 557 558 558 563 564 568 570 570 572 573 575 577 577 586 591 591

21

Cmo us ar la clase B r u s h ............................................................................................ R e s u m e n ................................................................................................................................... 27. C m o c o n s t r u i r servicios W e b ........................................................................... F uncionamiento de los servicios W e b ............................................................................ Servicios Web y Visual Studio N E T ............................................................................. Lenguaje de descripcin de serv icio Web ( W S D L ) ................................................. Como usar el Protocolo de acceso simple a objetos ( S O A P ) .............................. C omo crear servicios Web con Visual Studio . NET ................................................ Como us ar Visual Studio N E T para acceder a un servicio Web ....................... R e s u m e n ................................................................................................................................... 28. C m o u s a r C# en A S P . N E T ................................................................................. Como crear un serv icio W e b ............................................................................................. Cmo crear una base de datos par a un servicio W e b ........................................ Concept os del sistema de gestin de bases de datos r e l a c i n a l e s .......... Tipos de datos de S QL S e r v e r ............................................................................. Como crear bases de datos y t a b l a s ................................................................... Como recuperar d a t o s ............................................................................................ Cmo insertar, actualizar y eliminar datos ....................................................... Como usar procedimientos a l m a c e n a d o s ......................................................... Como crear la estructura de la base de d a t o s ................................................ Cmo usar la plantilla Servicio Web A S P . N E T ..................................................... Cmo agregar controles de datos al serv icio W e b .............................................. Como codificar el servicio W e b ................................................................................. Como crear un cliente de serv icio W e b ......................................................................... Como crear un nuevo provecto de aplicacin Web A S P . N E T ....................... Como agregar una referencia Web .................................................................... C omo i mple me nt ar los mtodos del serv icio Web ............................................... Como implementar la aplicacin ..................................................................................... Implementacion de provectos en Visual Studio N E T ........................................ Cmo usar un prov ecto de implementacion para implementar una aplicacin ...................................................................................................... Como implementar un prov ecto usando la opcion Copi ar prov e c t o .............. R e s u m e n ................................................................................................................................... 29. C m o c o n s t r u i r c o nt r ol e s p e r s o n a l i z a d o s .......................................................... Biblioteca de control de W i n d o w s ................................................................................... P r o p i e d a d e s ........................................................................................................................ M t o d o s ............................................................................................................................... C a m p o s ................................................................................................................................ E v e n t o s ................................................................................................................................ Aprender con un ejemplo ....................................................................................................

593 597 599 600 602 605 607 609 612 614 617 61 X 618 619 619 620 621 621 621 622 623 624 627 629 630 63 1 632 635 635 635 637 637 641 641 642 644 645 645 646

22

Como crear un tempori zador de cuenta a t r s ....................................................... C mo crear una p rue ba de carga C o u n t D o w n ..................................................... Como usar una biblioteca de c l a s e s ................................................................................ C mo crear una clase par a calcul ar el efecto de v i e n t o ................................... R e s u m e n .................................................................................................................................... 30. C m o c o n s t r u i r a p l i c a c i o n e s m v i l e s ............................................................. La red inalmbrica ................................................................................................................ Introduccin al Mobile Internet Toolkit ................................................................... Emuladores ........................................................................................................................ N o k i a .............................................................................................................................. Pocket P C .................................................................................................................... Microsoft Mobile E x p l o r e r ..................................................................................... Cmo crear un calculador de edades ............................................................................ Funciones de los dispositivos m v i l e s ............................................................................ Funcionamiento de los controles mviles ..................................................................... Cmo usar el control C a l e n d a r .................................................................................. Cmo usar el control I m a g e ........................................................................................ Paginacin en dispositivos m v i le s .................................................................................. R e s u m e n .................................................................................................................................... P a r t e V. C# y . N E T F r a m e w o r k ................................................................................. 31. C m o t r a b a j a r con e n s a m b l a d o s ........................................................................ Ensamblados ........................................................................................................................... Cmo encontrar ensamblados c a r g a d o s .................................................................. Nombres seguros de e n s a m b l a d o ............................................................................. Cmo asignar la informacin de v e r s i n ........................................................... Cmo asignar la informacin de referencia cultural .................................... Cmo as ignar la informacin de c l a v e .............................................................. Cmo t rab aj ar con la clase A s s e m b l y ..................................................................... Cmo e ncontr ar la informacin de ubicacin del ens amb la do ................. Como encontr ar puntos de ent rada del ens ambl ado .................................... Como c argar e n s a m b l a d o s .................................................................................... Cmo trabaj ar con informacin de tipo de e n s a m b l a d o .............................. C omo g enerar cdigo nativo par a e n s a m b l a d o s ......................................................... R e s u m e n ................................................................................................................................... 32. R e f l e x i n ........................................................................................................................ La clase Typc ......................................................................................................................... Cmo recuperar informacin de t i p o ....................................................................... Cmo recuperar tipos mediante el n o m b r e ...................................................... Cmo recuper ar tipos mediante instancias ......................................................

646 651 653 653 656 659 659 660 660 660 660 661 661 666 667 667 668 670 672 6 73 675 675 676 678 680 681 682 682 682 683 684 688 689 691 693 694 694 694 695

23

C mo recuper ar tipos en un e n s a m b l a d o ......................................................... Cmo interrogar a objetos ........................................................................................... Cmo generar cdigo dinmico mediante la reflexin ...................................... R e s u m e n ................................................................................................................................... 33. S u b p r o c e s a m i e n t o en C # ....................................................................................... S ub p r o c e s a m i e n t o .................................................................................................................. Multitarea p r e f e r e n t e ..................................................................................................... Prioridades de s ubproc es o y b l o q u e o ...................................................................... Multiprocesamiento s i m tr ic o..................................................................................... Cmo usar los recursos: cuantos ms. m e j o r ........................................................ Dominios de aplicacin ................................................................................................. Ventajas de las aplicaciones de varios s u b p r o c e s o s ........................................... Aplicaciones con procesos l a r g o s ....................................................................... Aplicaciones de sondeo y e s c u c h a ..................................................................... Botn C a n c e l a r ........................................................................................................... Como crear aplicaciones m u l t i p r o c e s o .......................................................................... Cmo crear nuevos s u b p r o c e s o s .............................................................................. Prioridad de los s u b p r o c e s o s ....................................................................................... Estado del s u b p r o c e s o .................................................................................................. Cmo unir s u b p r o c e s o s ........................................................................................... Cmo sincronizar s u b p r o c e s o s ............................................................................. Sondeo y e s c u c h a .................................................................................................................. R e s u m e n ................................................................................................................................... 34. C m o t r a b a j a r con C O M ....................................................................................... Introduccin al Contenedor al que se puede llamar en tiempo de ejecucin .... Cmo crear ensamblados N E T a partir de componentes COM ........................ Cmo usar la utilidad T l b i m p ....................................................................................... C omo crear un component e C O M ...................................................................... Cmo u sar el ensamblado de intcroperabilidad desde C # .......................... Cmo hacer referencia a la DLL COM desde C # ............................................. Cmo manej ar errores de i n t c r o p e r a b i l i d a d ................................................................ Cmo usar la invocacin de p l a t a f o r m a ....................................................................... R e s u m e n ................................................................................................................................... 35. C m o t r a b a j a r con servicios C O M + .............................................................. El espacio de nombres S y s t e m. En t er pr i se Se r vi ce s .................................................. La clase Ser\ i c e d C o m p o n e n t ........................................................................................... Cmo registrar clases con C O M + .................................................................................. Cmo usar atributos para clases C O M + ...................................................................... Application A c c e s s C o n t r o l ........................................................................................... ApplicationActivation.....................................................................................................

696 697 700 702 705 705 706 707 707 708 709 710 710 710 710 711 712 7 15 716 719 72 1 722 723 727 728 729 729 731 735 739 740 743 744 747 748 752 754 756 757 757

24

App li cat i on ID.................................................................................................................... A p p l i c a t i o n N a m e ............................................................................................................. Ap pl i cat i onQu eui ng........................................................................................................ A u t o C o m p I c t c ................................................................................................................... C o mp on e nt A c c es s C ' o nt r o l........................................................................................... ConstructionEnabled ...................................................................................................... JustlnTimeActivation ..................................................................................................... L oa dB al a nci ngSuppor t ed.............................................................................................. Sceurit\ Role ..................................................................................................................... Como procesar transacciones .......................................................................................... Propiedades A C ' I D .......................................................................................................... Como escribir componentes de t r a n s a c c i o n e s ............................................................ Como acceder al contexto de o b j e t o s ............................................................................ R e s u m e n ................................................................................................................................... 36. C m o t r a b a j a r con los servicios re m o t o s de . N E T ................................. Introduccin al entorno remoto ........................................................................................ Como crear un ensambl ado de servidor r e m o t o ........................................................ Como crear un servidor r e m o t o ....................................................................................... Como especificar canales y p u e r t o s ......................................................................... Como especificar un formato de c a n a l .................................................................... Espacio de nombres S v s te m . R u n ti m e. R e m o t mg . C h a n n e ls . T c p ....... ....... Espacio de nombres S y s t e m . R u n t i m e . R e m o t i n g C h a n n e l s . H t t p .............. C omo acti var el objeto r e m o t o ................................................................................... Como registrar objetos con RegisterW e l l k n o w n S e r v i c e T y p e ................. C omo registrar objetos con el mtodo C o n f i g u r e .......................................... Como escribir el cliente remoto ....................................................................................... R e s u m e n ................................................................................................................................... 37. C # y s e g u r i d a d . N E T ............................................................................................... S e g u n d a d de e o d i g o ............................................................................................................. Directiva de seguridad de c o d i g o .............................................................................. Permisos de c o d i g o ........................................................................................................ S e g un da d de u s u a r i o ............................................................................................................ Seguridad NE T y basada en funciones ....................................................................... Como asignar las funciones Window s ..................................................................... Pri nci pal es.......................................................................................................................... Permisos de acceso a c o d i g o ........................................................................................... Como crear una sencilla solicitud de codigo de p e r m i s o ................................... Denegacin de p e r m i s o s ............................................................................................... Como usar permisos basados en a t r i b u t o s ............................................................. Directiva de s e g u r i d a d ........................................................................................................ Niveles de directiva de s e g u n d a d .............................................................................

7^8 758 758 759 759 759 760 760 761 761 762 763 7o 768 771 771 773 775 777 778 779 779 78 1 783 785 790 794 79 7 798 79c ) 799 800 802 802 806 806 807 809 810 811 811

25

Gr up os de c o d i g o ............................................................................................................. Conj untos de permisos con n o m b r e .......................................................................... Cmo alterar directivas de s e g u r i d a d ...................................................................... R e s u m e n ................................................................................................................................... P a r t e VI. A p n d i c e s .......................................................................................................... A p n di c e A. M a n u a l de X M L ...................................................................................... Obj etivos de diseo de X M L ............................................................................................. Objetiv o 1: X M L debe ser fcilmente utilizable en I n t e r n e t ............................ Objetivo 2: X ML debe admitir una amplia variedad de a p l i c a c i o n e s ........... Objetivo 3: XML debe ser compatible con S G M L .............................................. Objetivo 4: Debe ser sencillo escribir pr og ramas que procesen documentos X M L ................................................................................................ Objetivo 5: El numero de caractersticas opcionales en X ML debe mantenerse al mnimo, preferentemente a cero .............................. Objetivo 6: Los document os X M L deben ser legibles para las personas y razonablemente c l a r o s ................................................ Objetiv o 7: El diseo de X ML debe ser pre para do rpidamente .................... Objetivo 8: El diseo de XML debe ser formal y c o n c i s o ................................. Objetivo 9: Los documentos X ML deben ser fciles de c r e a r .......................... Objetivo 10: La concisin del mar cado X M L es de mnima importancia .... Brev e leccin de H T M L ...................................................................................................... XML - H T M L con etiquetas definidas por el usuario ............................................ Definiciones de tipo de d o c u m e n t o .................................................................................. Esquemas X M L ..................................................................................................................... Espacios de nombre X M L .................................................................................................. A p n d i c e B. C o n t e n i d o del C D - R O M ................................................................... I n di ce a l f a b t i c o .................................................................................................................

812 812 813 814 817 819 819 821 82 1 821 822 822 822 822 823 823 823 823 827 829 831 834 839 841

26

Introduccin

La iniciativa N E T F ramework de Microsoft supone el cambi o mas i mpo rt an te en la metodologa del desarrollo de s oftware par a un sistema operativo de Microsoft desde la introduccin de Windows. Este entorno est construido u s a n do una arquit ect ura que permite a los lenguajes de software t r ab aj ar juntos, c o m partiendo recursos y cdigo, para p r o p o r c i on ar a los programadores las avanzadas herrami ent as necesarias par a construir la siguiente generacin de aplicaciones de escritorio y de Internet. Visual Studio N E T de Microsoft incluye nuevas ver siones de sus productos de compilador Visual Basic y C++ dirigidas al desarrollo de NET. al igual que un lenguaje compl et ament e nuevo llamado CU. Este libro le mo st rar como escribir cdigo us ando este novsimo lenguaje. Todos los trminos de lenguaje tales como declaraciones, variables, bucles de control y clases, son tratados con detalle. Adems, el libro le enseara a usar CU par a p ro gr a ma r tareas con las que los pro gr amado re s suelen enfrentarse en el mundo real. La ultima parte del libro explica cmo usar CU p ar a desarrollar paginas Web, acceder a bases de datos, t rabaj ar con objetos C'OM y C O M + heredados, desarrollar aplicaciones de escritorio para Windows, t raba jar con v a n o s conceptos de N E T F ramework y mucho ms. El principal objetivo de este libro es el desarrollo N E T usando CU como el lenguaje de implementacin y el comp il ado r de lnea de comand os CU de N E T Framework como la principal her ramienta de desarrollo. El desarrollo de CU

29

empleando la her ramienta Visual Studio N E T no se trata en este libro, aunque es algo que se puede domi nar fcilmente una vez que se compre ndan bien los f u n damentos del desarrollo N E T usando CU.

Quin debera leer este libro


Este libro fue escrito teniendo en mente a los pr ogr amad or es novatos v los expertos. Si no conoce a bs olutamente nada sobre las bases del desarrollo de s of t ware. este libro le iniciar en sus fundamentos, mostrndole como funcionan las variables, los bucles de control y las clases. El libro tambin est dirigido a los progr amadore s de cualquier nivel, mostrndoles las herramientas N E T di sponi bles para el desarrollo en CU y proporcionndoles trucos par a hacer que sus propias aplicaciones en CU funcionen perfectamente dentro de las directrices de desarrollo de N E T Framework. Si ya esta introducido en el mundo de la creacin de aplicaciones N ET . e n contrar en este libro un recurso muy til porque cubre casi todos los aspectos del desarrollo N E T exhaustivamente. Las primeras tres partes del libro sirven de punto de referencia ilustrativo p ar a usar las caractersticas del lenguaje CU. En cambio, las dos ltimas partes estn dedicadas a mos trar C# como pl at aforma de desarrollo de aplicaciones, ilustrando el papel de CU en aplicaciones de es cri torio. Web. bases de datos y basa das en componentes. En este libro se asume que es la pri mera vez que utiliza C# y pretende propor ci onar u na comprensin del lenguaje sin exigir un conocimiento previo. Sin e mbargo, el libro tambin supone que el lector est familiarizado con los entornos de aplicaciones usados en c on juncin con sus aplicaciones C#. Las ltimas partes del libro abor dan el uso de CU con aplicaciones de e scri to rio. Web. bases de datos y b as ad as en componentes, pero no explica esas p l a t a formas con detalle. En su lugar, el libro supone que el lector tiene un conocimiento prctico de esas plataformas.

Cmo est organizado este libro


Este libro est organizado en seis partes:

Parte I: Fundamentos del lenguaje C#


Esta primera parte del libro p roporci ona una breve visin general de la familia de lenguajes de programaci n C y pas a a trat ar los aspectos sintcticos bsicos de CU. Variables, declaraciones, bucles de control de flujo y llamadas de mtodo, todas son tratadas. Los p rogr amadore s principiantes tambin encontrarn m at e rial explicativo sobre el uso de estos elementos sintcticos y a prendern a e l abo rar cdigo con estos conceptos.

30

Parte II: Programacin orientada a objetos con C#


Los captulos de esta segunda parte t ratan de la nocin de clase en C#. La clase es la unidad fundament al de cdigo en una aplicacin C'# y comprender las clases es clave p ar a construir una aplicacin C# que funcione. Ademas esta parte se ocupa de temas como el diseo de clases, clases bsicas, clases derivadas y s obrecarga de operadores.

Parte III: C# avanzado


La tercera parte del libro se concentra en rasgos de lenguaje especficos e m pleados por aplicaciones C# ms avanzadas. Se a bordan temas como el control de excepciones, la implcmentacin de interfaces. los espacios de nombre, los a t ri b u tos y el cdigo no seguro, todos son tratados. El ultimo captulo de esta parte esta dedicado a present ar algunos problemas de progr amaci n complicados y solucio nes aplicadas usando C#.

Parte IV: Desarrollando soluciones .NET usando C#


La parte IV muestra cmo usar C# en aplicaciones que utilizan x a n a s partes de N E T Framexvork. Esta parte del libro se separa de las otras secciones, que estn dedicadas a la presentacin de las caractersticas del lenguaje C#. La parte IV usa C# para construir aplicaciones usando x a n a s plataformas de la aplicacin NET. desde formularios de Windoxvs hasta Web Forms y aplicaciones A S P . N E T y acceso a bases de datos. Tambi n echaremos un vistazo al t rabajo con algunas tecnologas . NET axa nzada s usando C'#. incluyendo s ubprocesami ent os. e n s a m blados y reflexin.

Parte V: C# y .NET Framework


La ultima parte del libro describe como se puede usar C# par a t raba jar con el propio N E T Framexvork. Se explican conceptos de Framexvork tales como e n samblados. reflexin, subprocesamiento e mteroperabilidad de componentes COM C O M + . Ca da captulo explica el concepto de Framexxork a pr opia do v tambin ensea a a pr ove cha r la tecnologa usando C# como lenguaje de i mplementacin.

Parte VI: Apndices


La ltima seccin del libro consta de dos apndices. El pri mero ofrece una introduccin al Lenguaje de m ar cad o extensible ( X ML ) y de qu maner a los progr amadores pueden apr ovecha r este leguaje p ar a describir datos de una m a nera estandarizada. Muchos proyectos N E T usan X M L de una forma u otra y varios archixos de configuracin N E T estn basados en la infraestructura XML. El segundo apndice incluve una descripcin del contenido del C D - R O M que a c ompa a al libro.

31

Cmo usar este libro


Los lectores que sean compl et ament e novatos en el desarrollo de software (quizs los administradores Web) aprov echarn mejor este libro leyendo primero las partes I v II para conseguir una mejor comprensin de cmo funcionan los mecani smos de una aplicacin de software. Puede ser i mportante que los nuev os pro gr amado re s comprendan las bases del desarrollo de software y como encajan todas las piezas para construir una aplicacin C# completa. A los lectores que se acerquen a C# con un conocimiento previo de C'++. el nuevo lenguaje les resultara muy familiar. C# fue construido pensando en C y C h y la sintaxis se parece a la de estos lenguajes ms antiguos. Estos lectores quizas deseen exami nar las partes I y II para ac os tu mbra rs e a las v a na n te s de sintaxis v luego quizas deseen lanzarse de lleno a la parte III par a c omprender las avanzadas caractersticas del lenguaje. Muchos de los aspectos de la parte III profundizan en los conceptos que distinguen CU de sus predecesores. Los progr amadore s que ya esten familiarizados con CU encontraran bastante material til. Las partes IV y V muestran el uso de CU en varias aplicaciones para la p l at a f o r m a . N E T y presentan v arios ejemplos que explican el cdigo CU que puede usarse para realizar tareas variadas. Estas dos ultimas partes trasladan el libro del nivel teorico al nivel practico y son ideales para los pr og ramad or es de cualqui er nivel que deseen co mprender cmo puede usarse CU para i mplementar varias aplicaciones.

Normas usadas en este libro


A lo largo del libro encontrara unos rectngulos s ombreados que resaltan la informacin especial o importante, estos son los siguientes:

ADVERTENCIA: Indica un procedimiento que, en teora, podra causar dificultades o incluso la prdida de datos; preste especial atencin a los iconos de advertencia para evitar los errores de programacin ms comunes y los que no lo son tanto.

NOTA: Resalta la informacin interesante o adicional y suele contener pequeos trozos extra de informacin tcnica sobre un tema.

TRUCO: Llaman la atencin sobre hbiles sugerencias, pistas recomen dables y consejos tiles.

32

Adems en este libro se usan las siguientes convenciones tipogrficas: Los cdigos de ejemplo aparecen en un tipo de letra Courier. Las opciones de mens se indican en orden jerrquico, con cada i ns truc cin de men s eparada por el signo "mayor que" y en un tipo de letra Anal. Por ejemplo. Archvo>Abrir quiere decir hacer clic en el c om and o A rchi vo en la b a r ra de men y luego seleccionar Abrir. Las combi naciones de teclas se indican de esta forma. C o n t r o l - C . Al final de cada captulo encontrar un resumen de lo que debera haber a p r e n dido al t erminar de leer el captulo.

33

Parte I

Fundamentos del lenguaje C#

35

Introduccin aC#

Durante los ltimos 20 aos. C y C++ han sido los lenguajes elegidos para desarrol lar aplicaciones comerciales y de negocios. Estos lenguajes p r op o rc io nan un altsimo grado de control al pr ogr a ma dor permitindole el uso de punteros y muchas funciones de bajo nivel. Sin embargo, cuando se co mpar an lenguajes, como Microsoft Visual Basic con C/ C++. uno se da cuenta de que aunque C y C ++ son lenguajes mucho ms potentes, se necesita mucho ms tiempo para desarrollar una aplicacin con ellos. Muchos progr amadores de C / C + + han t emi do la idea de c ambi ar a lenguajes como Visual Basic porque podrian perder gran parte del control de bajo nivel al que estaban acostumbrados. Lo que la comuni dad de p ro gr amad or es necesitaba era un lenguaje que es tu viera entre los dos. Un lenguaje que ayu da ra a desarrollar aplicaciones rpidas pero que tambin permitiese un gran control y un lenguaje que se integrase bien con el desarrollo de aplicaciones Web. X M L y muchas de las t ecnologas em er gentes. Facilitar la transicin para los progr amadores de C / C++ existentes y p r o p o r cionar a la vez un lenguaje sencillo de a pr ender par a los pr og ramador es i nexper tos son slo dos de las ventajas del nuevo lenguaje del barrio. C#. Microsoft present C# al pblico en la Prof essi onal Devel oper 's Conf erencc en Orlando. Florida, en el verano del 2000. C# combi na las mejores ideas de lenguajes como C. C++ y Java con las mejoras de productividad de N E T Framework de Microsoft

37

y brinda una experiencia de codificacin muy producti va tanto par a los nuevos p rogr amadore s como par a los veteranos. Este captulo profundiza en los cuatro componentes que constituyen la pl at af orma N E T ademas de analizar la c om pat i bilidad para las tecnologas Web emergentes. A continuacin, se analizan muchas de las funciones del lenguaje C# y se c ompar an con otros lenguajes populares.

.NET Framework
Microsoft dise C# desde su base par a ap ro vech ar el nuevo entorno N E T Framework. C omo C# forma parte de este nuevo mundo N ET . deber c o mp re n der perfectamente lo que proporciona N E T Framework y de que manera aumenta su productiv idad. N E T Framework se compone de cuatro partes, como se muestra en la figura 1 .1: el entorno comn de ejecucin, un conjunto de bibliotecas de clases, un grupo de lenguajes de progr amaci n y el entorno A S P . N ET . N E T Framework fue dise ado con tres objetivos en mente. Primero, deba lograr aplicaciones Wi nd ows mucho mas estables, aunque tambin deba p ropor ci onar una aplicacin con un mayor grado de seguridad. En segundo lugar, deba simplificar el desarrollo de aplicaciones y servicios Web que no slo funcionen en pl at af ormas tradicionales, sino tambin en dispositivos mviles. Por ultimo, el entorno fue diseado para propor ci onar un solo g rup o de bibliotecas que pudieran t raba jar con v arios len guajes. Las siguientes secciones analizan cada uno de los componentes de N E T Framework.
C o m m o n L a n g u a g e R untim e B ib lio te c a s de C lase L e n g u a je s de P ro g ra m a ci n (C #, V C + + , BV.NET, J S c rip t.N E T ) A S P .N E T

Figura 1.1. Los cuatro com ponentes de NET Framework

Desarrollo Web
N E T F ramework fue diseado con una idea en mente: potenciar el desarrollo de Internet. Este nuev o incentivo par a el desarrollo de Internet se llama s e r v a i o s Web. Puede pensar en los servicios Web como en una pgi na We b que interactua con progr amas en lugar de con gente. En lugar de enviar paginas Web. un servicio Web recibe una solicitud en formato XML. realiza una funcin en concreto \ luego devuelve una respuesta al solicitante en forma de mensaje XML.

38

NOTA: XML o el Lenguaje de marcado extensible es un lenguaje autodescriptivo muy parecido a HTML. Por otra parte, XML no consta de etiquetas predefinidas, lo que le concede una gran flexibilidad para repre sentar una amplia variedad de objetos.
Una tpica aplicacin par a un servicio We b podra ser corno c apa situada en lo alto de un sistema de f acturacin de una empresa. Cu and o un usuario que navega por la red compra los productos de una p gina Web. la informacin de la compra es enviada al servicio Web. que calcula el precio de todos los productos, aade una lnea a la base de datos de existencias y devuelve una respuest a con una confirmacin de pedido. Este servicio We b no slo puede int eract uar con pginas Web, puede i nt eract uar con otros servicios Web. como un sistema de cuentas de pago de una empresa. Para que el modelo de servicio We b s obreviva a la evolucin natural de los lenguajes de programacin, debe incluir muchas ms cosas que un simple interfaz para la Web. El modelo de servicio Web tambin incluye protocolos que permiten que las aplicaciones encuentren serv icios Web disponibles en una red interna o en Internet. Este protocolo tambin permite a la aplicacin expl orar el servicio Web y decidir cmo comuni carse con l y cmo i nt ercambiar informacin. Para per mi tir el descubri mi ento de serv icios We b se estableci la Descripcin, d es c ub ri miento e integracin universal (UDDI). Esta permite que los servicios We b sean registrados y consultados, b as ndos e en datos clav e como el nombre de la c o m paa. el tipo de servicio y su localizacin geogrfica.

Desarrollo de aplicaciones
Aparte del desarrollo Web. con N E T Framevvork tambin puede construir las t r adi ci ona le s a pl i ca c io ne s W i nd ow s. Es tas a pl i ca c io ne s c r e a d a s con N E T Framevvork se basan en Windows Forms. Wi ndows Forms es una especie de cruce entre los formularios de Visual Basic 6 y los formularios de Visual C++. Aunque los formularios parecen iguales a sus predecesores, estn completamente ori ent a dos a objetos y basados en clases, de forma muy parecida a los formularios obje to de Microsoft Foundation Class. Estos nuevos Wi ndows Forms ahora admiten muchos de los controles clsicos que aparecan en Visual Studio. como Button. Te:-:tBox y Labe 1 . junto a los controles ActiveX. Aparte de los controles tradicionales, tambin admite nuevos c o m p o n e n t e s co mo P r i n t P r e v i e w . LinkLabel. C o l o r D i a l o g y

OpenFileDialog.
La creacin de aplicaciones con N E T tambin brinda muchas mejoras no disponibles en otros lenguajes, como la seguridad. Estas medidas de seguridad pueden determinar si una aplicacin puede escribir o leer un archivo de disco. Tambi n permiten insertar firmas digitales en la aplicacin par a asegurarse de

39

que la aplicacin fue escrita por una fuente de confianza. N E T Framework tambic'n permite incluir informacin de componentes, y de versin, dentro del cdigo real. E s t o h a c e p o s i b l e qu e el s o f t w a r e se i n s t a l e c u a n d o se lo p i d a n , aut omt icame nte o sin la intervencin del usuario. Juntas, todas estas funciones reducen los costes asistencia par a la empresa.

Entorno comn de ejecucin


Los lenguajes de p ro gr amaci n suelen componer se de un compi lador y un entorno de ejecucin. El comp il ado r convierte el cdigo que escribe en codigo ejecutable que puede ser ejecutado por los usuarios. El entorno de ejecucin p r o porciona al cdigo ejecutable un conjunto de servicios de sistema operativo. Estos servicios estn integrados en una ca pa de ejecucin de modo que el cdigo no necesite p re ocu par se de los detalles de bajo nivel de f uncionamiento con el siste ma operativo. Operaci ones como la gestin de memori a y la entrada y salida de archivos son buenos ejemplos de servicios realizados por un entorno de ej ec u cin. Antes de que se desarrollara NET. cada lenguaje c onstaba de su propio ent or no de ej ecuci n. Vi sual Basi c c o n s t a de un t i e m po de ej ec uci n l l am ad o M S V B V M 6 0 DLL Visual C ++ utiliza una DLL llamada M S V C R T . D L L . Cada uno de estos mdulos de e ntorno de ejecucin p ro po rci onaba un conjunto de s er vicios de bajo nivel par a codificar lo que los progr amadore s escriban. Los p r o g ra ma do res escriban codigo y luego lo compi laban con el apr opi ado tiempo de ejecucin en mente. El cdigo ejecutable incluira su propio tiempo de ejecucin, que puede ser instalado en el equipo del usuario si an no est aba presente. El principal probl ema que presentan estos entornos de ejecucin es que e st a ban diseados para usar un solo lenguaje. El tiempo de ejecucin de Visual Basic propor ci onaba algunas funciones estupendas par a operaciones como t rab aj ar con memori a e iniciar objetos C O M . pero estas funciones estaban disponibles solo para los usuarios de Visual Basic. Los programadores que usaban Visual C ++ no podan u sar las funciones del tiempo de ejecucin de Visual Basic. Los usuarios de Visual C ++ tenan su propio tiempo de ejecucin, con su propia larga lista de funciones, pero esas funciones no estaban disponibles p ar a los usuarios de Visual Basic. Este enfoque de "tiempos de ejecucin separados" impeda que los l engua jes pudiesen funcionar conjuntamente sin problemas. No es posible, por ejemplo, t omar algo de memoria en un fr agmento de cdigo en Visual Basic y luego p a s r selo a una parte de cdigo en Visual C++. lo que liberara la memoria. Los diferentes tiempos de ejecucin implementan su propio conjunto de funciones a su manera. Los conjuntos de funciones de los diferentes tiempos de ejecucin son inconsistentes. Incluso las funciones que se encuent ran en ms de un tiempo de ejecucin se implementan de diferentes formas, haciendo imposible que dos f r a g mentos de cdigo escritos en diferentes lenguajes trabajen juntos.

40

Uno de los objetivos de diseo de N E T Framework era unificar los motores de ejecucin par a que todos los pro gr amado re s pudieran t raba jar con un solo conjunto de servicios de ejecucin. La solucin de N E T Framework se llama Entorno comn de ejecucin (CLR). El C L R propor ci ona funciones como la g es tin de memoria, la seguridad y un slido sistema de control de errores, a c ua l quier lenguaje que se integre en N E T Framework. Graci as al CLR. todos los lenguajes N E T pueden u s ar varios servicios de ejecucin sin que los pro gr amadores tengan que p re ocupar se de si su lenguaje p ar ti cular admite una funcin de ejecucin. El C LR tambin permite a los lenguajes intcractuar entre s. La memoria puede asignarse mediante cdigo escrito en un lenguaje (Visual Basic NET. por ejemplo) y puede ser liberada con cdigo escrito en otro (por ejemplo. CU). Del mismo modo, los errores pueden ser detectados en un lenguaje y procesados en otro.

Bibliotecas de clase .NET


A los p rogr amadore s les gusta t rab aj ar con codigo que ya ha sido probado y ha demost rado que funciona, como el API Wi n32 y la biblioteca de clase MFC. La reutilizacin del cdigo lleva mucho tiempo siendo el objetivo de la comunidad de des a bo ll a do re s de software. Sin embargo, la posibilidad de reutilizar el codigo no ha estado a la altura de las expectativas. Muchos lenguajes han tenido acceso a cuerpos de codigo previamente c o m probados y listos p ar a ser ejecutado. Visual C++ se ha beneficiado de las biblio tecas de clase, como las Clases de fundacin Microsoft (MFC), que permiti a los p rogr amadore s de C + + crear aplicaciones Wi ndows rpidamente, y la Biblio teca activa de plantillas (ATL). que proporci ona ayuda para crear objetos COM. No obstante, la nat uraleza especfica del lenguaje de estas bibliotecas las ha hecho inservibles par a ser usadas en otros lenguajes Los p rogr amadore s de Vi sual Basic tienen vetado el uso de A T L p a r a crear sus objetos COM. N E T Framework p roporciona muchas clases que ayudan a los programadores a reutilizar el codigo. Las bibliotecas de clase N E T contienen cdigo para p r o g r a ma r subprocesos. entrada y salida de archiv os, compatibilidad para bases de datos, anlisis X M L y est ructuras de datos, como pilas y colas. Y lo mejor de todo, toda esta biblioteca de clase est disponible para cualqui er lenguaje de progr amaci n compatible con N E T Framework. Graci as al CLR. cualquier len guaje N E T puede us ar cualquier clase de la biblioteca NET. Como ahora todos los lenguajes admiten los mismos tiempos de ejecucin, pueden reutilizar cu a l quier clase que funcione con N E T Framework. Esto significa que cualquier funcionalidad disponible par a un lenguaje tambin estar disponible par a cu a l quier otro lenguaje NET. El c u a d r o de re ut il i zac in de b i b l io t ec a s de cl as es d i b u j a d o p or N E T F ramework se vuelve an mejor cuando se da cuenta de que la reutilizacin se extiende a su cdigo, no slo al cdigo que Microsoft lanza con NET. El cdigo

41

de Microsoft solo es cdigo que fue escrito usando un lenguaje que N E T admita y se compi laba usando una herramienta de desarrollo NET. Esto significa que Microsoft est usando las mismas herramientas que us ar a par a escribir su cdi go. Puede escribir cdigo ca paz de ser usado en otros lenguajes NET. e x a c t a mente lo mismo que Microsoft con su biblioteca de clase. N E T Framework permite escribir cdigo en C#. por ejemplo, y envirselo a progr amadores en Visual Basic NET. que pueden usar ese cdigo que compilo en sus aplicaciones. La figura 1 2 ilustra una visin muy general de las bibliotecas de clase NET.
System .W eb Services Description Discovery Protocols [ [ System Runtime InteropServices Remoting Serialization Collections C onfiguration System.Xm l Diagnostics XSLT Reflection Caching XPath_______ I ( ______ Security Serialization C onfiguration ( ServiceProcess Text Threading (~ SessionState Globalization Imaging System . W indow s. Forms I_______ Design_____ [~ C om ponentM odes IO Net R esources Printing SQL System .Data ADO

Design

SQL Types

U l
[ ( H tmIControls W ebC ontrols ~ | )

~ ~ j

Security

System .Drawing Drawing2D

Text

Figura 1.2. Las bibliotecas de clase NET Framework

Lenguajes de programacin .NET


N E T F ramework p ropor ci ona un conjunto de herramientas que le ayudan a el aborar cdigo que funciona con N E T Framework. Microsoft propor ci ona un conjunto de lenguajes que ya son "compatibles con NET" . C# es uno de estos lenguajes. Tambi n se han creado nuevas versiones de Visual Basic y Visual C++ para apr ovechar las ventajas de N E T Framework y hay una versin de J scr ipt . NET en camino.

42

El desarrollo de lenguajes compatibles N E T no se limita a Microsoft. El g r u po N E T de Microsoft ha publicado documentacin que muest ra cmo los prov ee dores pueden hacer que sus lenguajes funcionen con NET. y estos proveedores estn haciendo lenguajes como C O B O L y Perl compatibles con N E T Framevvork Actualmente, una tercera parte de los prov eedores e instituciones estn p r e p a r a n do ms de 20 lenguajes capaces de integrarse en . NET Framevvork.

Entorno ASP.NET
Internet fue concebida en un principio para enviar contenido esttico a los clientes Web Estas pginas Web nunca cambi aban y eran las mismas para todos los usuarios que navegaban hasta esa localizacin. Microsoft lanzo servidores activ os para permitir la creacin de pginas dinmicas bas adas en la aportacin e interaccin del usuario con una pgina Web. Esto se consigui mediante el uso de secuencias de comandos que funcionaban por detras de la pagina Web. g en er al mente escritas en VB Script. C uando los usuarios visitaban una pagina Web. se les poda pedir que verificasen la i nformacin (manual mente o con una cookie). y luego la secuencia de comandos poda generar una pgina Web que le era devuel ta al usuario. A S P . N E T mejora al original AS P propor ci onando "codigo detrs". En ASP. H T M L y las secuencias de comando se mezclaban en un documento. C on A SP .NET y su "cdigo detrs'', se puede s eparar el codigo y HT M L. Ahora, cuando la lgica de una pagina We b necesite cambiar, no hace falta bu sca r por cientos o miles de lneas de H T M L par a localizar la secuencia de comandos que necesita modificarse. De forma parecida a Windows Forms. ASP N E T admite Web Forms Los Web Forms permiten ar r as t ra r y colocar controles en sus formularios y codificarlos como hara en cualquier tpica aplicacin Windows. Como A S P . N E T usa N E T Framevvork. tambin usa el compilador Justo a tiempo (JIT) Las paginas ASP tradicionales se ejecutaban muy lentamente p o r que el codigo era interpretado. A S P . N E T compila el codigo cuando es instalado en el servidor o la pri mera v ez que es necesario, lo que aument a enormement e la velocidad.

Historia de C, C++ y C#
El lenguaje de pro gr amaci n C# fue creado con el mismo espritu que los lenguajes C y C++. Esto explica sus poderosas prestaciones y su fcil curva de aprendizaje. No se puede decir lo mismo de C y C++. pero como C# fue creado desde cero. Microsoft se tom la libertad de eliminar algunas de las prestaciones mas pesadas (cmo los punteros). Esta seccin echa un vistazo a los lenguajes C v C++. siguiendo su ev olucin hasta C#.

43

El lenguaje de p rogr amaci n C fue diseado en un principio p ar a ser usado en el sistema operativo UNIX. C se us par a crear muchas aplicaciones UNIX, incluyendo un compi lador de C. y a la l arga se us par a escribir el mismo UNIX. Su ampl ia aceptacin en el mundo acadmi co se ampli al mundo comercial v los proveedores de software como Microsoft y Borland publ icaron compi ladores C p ar a los ordenadores personales. El API original par a Wi ndo ws fue diseado par a t raba jar con cdigo Wi ndows escrito en C y el ltimo conjunto de API bsicos del sistema operativo Wi ndows sigue siendo compatible con C hoy en da. Desde el punto de vista del diseo. C careca de un detalle que ya ofrecan otros lenguajes como Smalltalk: el concepto de objeto. Piense en un objeto como en una coleccin de datos y un conjunto de operaciones que pueden ser realizadas sobre esos datos La codificacin con objetos se puede lograr usando C. pero la nocin de objeto no era obligatoria p ar a el lenguaje. Si quera es tru ct ur ar su codigo para que simulara un objeto, perfecto. Si no. perfecto tambin. En realidad a C no le importaba. Los objetos no eran una parte fundamental del lenguaje, por lo que mucha gente no prest mucha atencin a este es tndar de programaci n. Una vez que el concepto de orientacin a objetos empez a g ana r aceptacin, se hizo ev idente que C necesitaba ser d epur ado p ar a ado pt ar este nuevo modo de considerar al codigo C ++ fue creado p ar a encarnar esta depuracin. Fue di sea do par a ser compatible con el anterior C (de maner a que todos los prog ramas escritos en C pudieran ser tambin progr amas C ++ y pudieran ser compilados con un compi lador de C++). La principal aportacin a C ++ fue la compatibilidad par a el nuevo concepto de objeto. C ++ i ncorpor compatibilidad par a clases (que son "plantillas" de objetos) y permiti que toda una generacin de p rogr amadores de C pensaran en trminos de objetos y su comportamiento. El lenguaje C + + es una mejora de C. pero an as presenta algunas des v nta las C y C + + pueden ser difciles de manejar. A diferencia de lenguajes fciles de us ar como Visual Basic. C y C ++ son lenguajes de muy "bajo nivel" y exigen que mucho cdigo par a f uncionar correctamente. Tiene que escribir su propio codigo par a manej ar aspectos como la gestin de memori a y el control de errores. C y C ++ pueden dar como resultado aplicaciones muy potentes, pero debe asegurarse de que el cdigo funciona bien. Un error en la escritura del p ro g ra ma puede hacer que toda la aplicacin falle o se c omport e de f or ma inesperada. Como el objetiv o al disear C++ era retener la compatibilidad con el anterior C. C++ fue incapaz de e sc ap ar de la nat ural eza de bajo nivel de C. Microsoft diseo CU de modo que retuviera casi toda la sintaxis de C y C++. Los progr amadores que esten familiarizados con esos lenguajes pueden escoger el cdigo CU v empezar a p ro gr a ma r de f orma relativamente rpida. Sin embargo, la gran v entaja de CU consiste en que sus diseadores decidieron no hacerlo c o m p a tible con los anteriores C y C++. Aunque esto puede parecer un mal asunto, en realidad es una buena noticia. CU elimina las cosas que hacan que fuese difcil t rab aj ar con C y C++. Como todo el cdigo C es tambin cdigo C++. C ++ tena que mant ener todas las rarezas y deficiencias de C. CU parte de cero y sin ningn

44

requisito de compatibilidad, as que puede mant ener los puntos fuertes de sus predecesores y des cart ar las debilidades que compl icaban las cosas a los p r o g r a madores de C y C++.

Introduccin a C#
C#. el nuevo lenguaje presentado en N E T Framework. procede de C++. Sin embargo. C# es un lenguaje orientado a objetos (desde el principio), moderno y seguro.

Caractersticas del lenguaje


Las siguientes secciones hacen un rpido repaso a algunas de las caracter st i cas de C#. Si no est familiarizado con al guno de estos conceptos, no se p r e o cu pe. Todos sern t rat ados con detalle en captulos posteriores.

Clases
Tod o el cdigo y los datos en C# deben ser incluidos en una clase. No puede definir una variable fuera de una clase y no puede escribir ningn cdigo que no est en una clase. Las clases pueden tener constructores, que se ejecutan c u a n do se crea un objeto de la clase, y un destructor, que se ejecuta cuando un objeto de la clase es destruido. Las clases admiten herencias simples y todas las clases derivan al final de una clase base llamada objeto. C# admite tcnicas de versio nes par a a yu da r a que sus clases evolucionen con el tiempo mientras mantienen la compatibilidad con cdigo que use versiones anteriores de sus clases. Por ejemplo, observe la clase llamada Family. Esta clase contiene los dos ca mpos estticos que incluyen el nombre y el apellido de un mi embro de la fa mi lia junto con un mtodo que devuelve el no mbr e compl et o del mi embro de la familia.
class Cassi public public public string FirstName; string Lastame; string F u l l N a m e ( ) FirstName + LastName;

{
return

NOTA: La herencia simple significa que una clase de C# slo se puede


derivar de una clase base.

45

C# le permite a gr u pa r sus clases en una coleccin de clases llamada espacio de nombre. Los espacios de nombre tienen nombres y pueden servir de ayuda para or ganizar colecciones de clases en agr upaci ones lgicas. A medida que empieza a apr ender C#. des cubri r que todos los espacios de nombre relevantes par a N E T Framevvork empi ezan con el trmino S y s t e m . Microsoft tambin ha decidido incluir algunas clases que a yudan a la c omp at i bi lidad con versiones anteriores y al acceso a los API. Estas clases se incluven en el espacio de nombre Microsoft.

Tipos de datos
C# permite t raba jar con dos tipos de datos: de valor y de referencia. Los de valor contienen valores reales. Los de referencia contienen referencias a valores al macenados en algn lugar de la memoria. Los tipos primitivos como char. int y float. junt o con los valores y est ructuras comentados, son tipos de valor. Los tipos de referencia tienen variables que tratan con objetos y matrices. C# viene con tipos de referencia predefinidos (object y string). junto con tipos de valor predefinidos (sbyte. short. int. long. byte. ushort. uint. ulong. float. double. bool. char y decimal). Tamb in puede definir en el cdigo sus propios tipos de v alor y referencia. Todos los tipos de v alor v de referencia derivan en ultima instancia de un tipo base llamado object. C# le permite convertir un valor de un tipo en un valor de otro tipo. Puede t rab aj ar con conversiones implcitas y explcitas. Las conversiones implcitas siempre funcionan y nunca pierden informacin (por ejemplo, puede convertir un int en un long sin perder ningn dato porque un long es mayor que un int). Las conversiones explcitas pueden producir perdidas de datos (por ejemplo, c on vertir un long en un int puede producir perdida de datos porque un long puede contener valores mayores que un int). Debe escribir un operador cast en el cdigo par a que se produz ca una conversin explicita. En C# puede t raba jar con matrices unidimensionales y multidimensionales. Las matrices multidimensionales pueden ser rectangulares, en las que cada una de las matrices tiene las mismas dimensiones, o escalonadas, en las que cada una de las matrices puede tener diferentes dimensiones. Las clases y las est ructuras pueden tener miembros de datos llamados p r o p i e dades y c a m p o s . Los campos son variables que estn asociadas a la clase o est ructura a la que pertenecen. Por ejemplo, puede definir una estructura llamada Empleado que tenga un ca mp o llamado Nombre. Si define una variable de tipo Empleado llamada Emplead o Actual, puede r ecuper ar el nombre del e m pleado escribiendo EmpleadoActual .Nombre. Las propiedades son como los campos, pero permiten escribir codigo que especifique lo que debera ocurrir c uando el codigo acceda al valor. Si el nombre del empleado debe leerse de una base de datos, por ejemplo, puede escribir cdigo que diga "cuando alguien p r e gunte el valor de la propiedad Nombre, lee el nombre de la base de datos v devuelve el nombre como una cadena".

46

Funciones
Lina funcin es un fragment o de cdigo que puede ser i nvocado y que puede o no devolver un valor al cdigo que lo invoc en un principio. Un ejemplo de una funcin podra ser la funcin Ful 1Name mos trada anteriormente en este c a p t u lo. en la clase Family. Una funcin suele asociarse a fragmentes de cdigo que devuelven informacin, mientras que un mtodo no suele devolver informacin. Sin embargo, par a nuestros propsitos, generalizamos y nos referimos a las dos como funciones. Las funciones pueden tener cuatr o tipos de parmetros. Parmet ros de entrada, tienen valores que son enviados a la funcin, pero la funcin no puede ca mbi ar esos v alores. Parmet ros de salida: no tienen valor cuando son enviados a la funcin, pero la funcin puede darles un valor y enviar el valor de v uelta al invocador. Parmet ros de referencia: introducen una referencia en otro valor. Tienen un valor de ent rada p a r a la funcin y ese valor puede ser c ambi ado dentro de la funcin. Parmet ros Params: definen un numero variable de argument os en una lista. CU y el C L R t rabajan junt os par a brindar gestin de memoria automtica. No necesita escribir cdigo que diga "asigna suficiente memori a p ar a un numero entero" o "libera la memori a que est us ando este objeto". El C L R monitoriza el uso de memori a y recupera aut omt icame nte ms cuando la necesita. Tambi n libera memoria automticamente cuando detecta que ya no est siendo usada (esto tambin se conoce como recoleccin de objetos no utilizados). CU propor ci ona varios operadores que le permiten escribir expresiones m a t e m t icas y de bits. Mu ch os (pero no todos) de estos o per ad or es pueden ser redefinidos, permitindole c a mb i ar la forma en que trabajan estos operadores. CU admite una larga lista de expresiones que le permiten definir varias rutas de ejecucin dentro del cdigo. Las instrucciones de flujo de control que usan p a l a bras clave como if. switch. while. for. break y continu permiten al cdigo bi furcarse por caminos diferentes, dependiendo de los v alores de sus v a riables. Las clases pueden contener cdigo y datos. Cada mi embro de una clase tiene algo llamado mbi to de accesibilidad, que define la visibilidad del miembro con respecto a otros objetos. CU admite los mbitos de accesibilidad publ ic. protected. internal. protected internal y private.

Variables
Las variables pueden ser definidas como constantes. Las constantes tienen valores que no pueden ca mb ia r durante la ejecucin del cdigo. Por ejemplo, el

47

valor de pi es una buena muest ra de una constante porque el valor no cambi a a medida que el codigo se ejecuta. Las declaraciones de tipo de e numer aci n e s p e cifican un nombre de tipo par a un gru po de constantes relacionadas. Por ejemplo, puede definir una enumeracin de planetas con valores de Mercurio. Venus. T i e rra. Marte. Jpiter. Saturno. Urano. Neptuno y Plutn. y usar estos nombres en el cdigo. Usando los nombres de enumeraciones en el cdigo hace que sea ms fcil leerlo que si usara un nmero para representar a cada planeta. CU incorpora un mecani smo par a definir y procesar eventos. Si escribe una clase que realiza una operacin muy larga, quizs quiera invocar un evento c u a n do la operacion se complete. Los clientes pueden suscribirse a ese evento e in cluirlo en el codigo. lo que permite que se les pueda av isar cuando haya ac ab ad o su operacion. El mecani smo de control de eventos en C# us a delegados, que son variables que se refieren a una funcin.

NOTA: Un controlador de eventos es un procedimiento en el cdigo que determina las acciones que deben llevarse a cabo cuando ocurra un evento, como que el usuario pulse un botn.
Si la clase contiene un conjunto de valores, los clientes quizs quieran acceder a los valores como si la clase fuera una matriz. Puede conseguirlo escribiendo un fr agment o de codigo conocido como indexador. Sup ong a que escribe una clase llamada Arcolris. por ejemplo, que contenga el conjunto de los colores del arco iris. Los visitantes querrn escribir Mi Arcolris [ 0 ] par a recuperar el primer color del arco iris. Puede escribir un indexador en la clase Arcolris p ar a definir lo que se debe devolver cuando el visitante acceda a esa clase, como si fuera una matriz de valores.

Interfaces
C# admite interfaces. que son grupos de propiedades, mtodos y eventos que especifican un conjunto de funcionalidad. Las clases C# pueden i mplementar interfaces. que informan a los usuarios de que la clase admite el conjunto de funcionalidades documentado por la interfaz. Puede desarrollar implementaciones de interfaces sin interferir con ningn cdigo existente Una vez que la interfaz ha sido publicada, no se puede modificar, pero puede evolucionar mediante herencia Las clases CU pueden i mplementar muchas interfaces. aunque las clases solo pueden derivarse de una clase base. Veamos un ejemplo de la vida real que puede beneficiarse del uso de interfaces par a ilustrar su papel ext remadament e positivo en CU. Mucha s de las apl icaci o nes disponibles hoy en da admiten mdulos compl ement ari os. S up on g am os que tiene un editor de cdigo p ar a escribir aplicaciones. Este editor, al ejecutarse, puede c a r g ar mdulos complementarios. Para ello, el mdulo compl ement ari o debe seguir unas cuantas reglas. El mdul o compl ement ari o de DLL debe e x p o r

48

tar una funcin llamada CEEntry v el nombre de la DLL debe empez ar por CEd. Cuand o ejecutamos nuestro editor de codigo. este b us ca en su directorio de trabaj o todas las DLL que empiecen por CEd. C uando encuentra una. la abre y a continuacin utiliza GetProcAddress para localizar la funcin CEEntry dentro de la DLL. verificando asi que ha seguido todas las reglas exigidas para crear un mdulo complementario. Este mtodo de creacin y a pert ura de mdulos compl ement ar ios es muy pesado porque sobre carg a al editor de codigo con mas tareas de verificacin de las necesarias. Si us r amo s una interfaz en este caso, la DLL del mdulo complementario podra haber i mplementado una interfaz. g a r a n tizando asi que todos los mtodos necesarios, propiedades y eventos esten pres en tes en la propi a DLL y que funciona como especifica la documentacin.

Atributos
Los atributos aportan informacin adicional sobre su clase al C L R Antes, si quera que la clase fuera autodescriptiva. tena que seguir un enfoque sin c o nexin. en el que la document aci n fuera al ma c en ad a en archivos externos como un archivo IDL o incluso archivos H TM L. Los atributos solucionan este probl e ma permitiendo al p r og r am ad o r vincular informacin a las clases (cualquier tipo de informacin). Por ejemplo, puede us ar un atributo para insertar informacin de documentacin en una clase, explicando cmo debe ac tua r al ser usada. Las posibilidades son infinitas y sa es la razn por la que Microsoft i ncl i ne tantos atributos predefinidos en N E T Framework.

Cmo compilar C#
Ejecutar el cdigo C# con el compi lador de C# produce dos i mportantes co n j unt os de informacin: el cdigo y los metadatos. Las siguientes secciones d escri ben estos dos elementos y luego terminan e xami nando el componente esencial del cdigo NET: el ensamblado.

Lenguaje intermedio de Microsoft (MSIL)


El cdigo generado por el compi lador de C# est escrito en un lenguaje l lama do Lenguaje intermedio de Microsoft, o MSIL. MSIL se c ompone de un conjunto especfico de instrucciones que especifican cmo debe ser ej ecut ado el codigo. Contiene instrucciones p ar a operaciones como la inicializacion de variables, los mtodos de llamada a objetos y el control de errores, por citar solo unos pocos. C# no es el nico lenguaje cuyo cdigo fuente se t rans fo rma en MS IL durante el proceso de compilacin. Todos los lenguajes compatibles con NET. incluido Vi sual Basic N E T y C ++ gestionado, producen MS IL cuando se compila su cdigo fuente. Como todos los lenguajes N E T se compilan en el mi smo conjunto de instrucciones MSIL. \ como todos los lenguajes N E T usan el mismo tiempo de ejecucin, los cdigos de diferentes lenguajes y de diferentes compi ladores p u e den funcionar juntos fcilmente.

49

MS IL no es un conjunto de instrucciones especficas par a una CPU fsica. MSIL no sabe nada de la CPU de su equipo y su equipo no conoce nada de MSIL Entonces, cmo se ejecuta el codigo NET. si su CPU no lo puede interpretar'.'1 La respuesta es que el codigo MSIL se convierte en cdigo especfico de CPU cuando se ejecuta por p ri mera vez. Este proceso se llama compilacin "Justo a tiempo" o JIT. El t rabajo de un compi lador JIT es convertir el codigo genrico M SI L en codigo que su equipo pueda ejecutar en su CPU. Quizas se est preguntando por lo que parece ser un paso innecesario en el proceso. <,Por que generar MS IL cuando un compi lador podra generar di rect a mente cdigo especfico p ar a la CPU Despus de todo, los compi ladores siempre lo han hecho en el pasado. Hay un p ar de razones que lo explican. En primer lugar. MSIL permite que el codigo compilado se transfiera fcilmente a har dware diferente. Suponga que ha escrito algo de codigo C# y le g us tar a ejecutarlo en su ordenador personal y en su dispositivo porttil. Es muy probable que estos dos equipos tengan diferentes CPU. Si slo tiene un compi lador de C# p ar a una CPU especfica, entonces nece sita dos compiladores de C#: uno par a la CPU de su ordenador personal v otro par a la CPU de su dispositivo porttil. Tendra que compilar el cdigo dos veces, as egurndos e de poner el codigo adecuado par a cada equipo. Con MSIL. solo se compila una vez. Al instalar NET Framework en su ordenador personal se incluy e un compilador JIT que convierte el MS IL en cdigo especfico par a la CPU de su ordenador personal. Al instalar N E T Framework en su ordenador porttil se incluye un compi lador J IT que conv ierte el mismo MS IL en cdigo especfico p ar a la CPU de su dispositivo porttil. Ahora tiene un solo cdigo base MSIL que puede eje cutarse en cualquier equipo que tenga un compi lador JIT NET. El compilador JIT en ese equipo se o cu pa de hacer que el cdigo se ejecute. Ot ra razn par a que el compi lador use MS IL es que el conjunto de inst rucci o nes puede leerse fcilmente por un proceso de verificacin. Parte del t rabajo del compi lador J IT es verificar el cdigo par a a segurars e de que resulte lo mas claro posible. El proceso de verificacin as egura que el cdigo accede a la memori a correctamente y de que est usando los tipos de variable correctos al llamar a mtodos que esperan un tipo especfico. Estos procesos de verificacin se a s e g u ran de que el codigo no ejecute ninguna instruccin que origine un fallo. El c on j unt o de instrucciones MS IL fue diseado par a hacer este proceso de verificacin relativamente sencillo. Los conjuntos de instrucciones especficos par a cada CPU estn opt imi zados para la rpida ejecucin del cdigo, pero producen cdigo que puede ser difcil de leer y. por tanto, de v erificar. Tener un compi lador de C# que produce directamente codigo especfico par a C PU puede hacer difcil la v erifica cin del codigo. o incluso imposible. Al permitir al compi lador JIT de N E T Framework que verifique el cdigo se asegura de que el cdigo acceda a la m e m o ria en un modo libre de fallos y que los tipos de variable sean usados c or r ec ta mente.

50

Metadatos
El proceso de compilacin tambin produce metadatos. lo que es una parte importante de la historia de como se compart e el codigo .NET. Tan to si usa CU para construir una aplicacin para un usuario final como si lo usa para construir una biblioteca de clases que sera usada por la aplicacin de alguna otra persona, querr usar codigo N E T ya compilado. Ese codigo puede ser propor ci onado por Microsoft como parte de N E T Framework. o por un usuario a travs de Internet. La clave par a usar este codigo externo es hacer que el compi lador de CU sepa que clases y variables estn en el otro codigo base par a que pueda c o m pa r ar el codigo fuente que ha escrito con el codigo que ap arece en el codigo base precompi lado con el que esta trabajando. Piense en los metadatos como en "tablas de contenidos" para el codigo c o mp i lado. El compi lador de CU coloca met adatos en el codigo compi lado j unt o al MS IL generado. Este metadato describe con exactitud todas las clases que escri ba y como estn estructuradas. Todos los mtodos y variables de las clases estn completamente descritos en los metadatos. listos para ser leidos por otras apl i ca ciones. Visual Basic NET. por ejemplo, puede leer los met adatos para que una biblioteca N E T proporcione la funcin Intel 1iSense de listar todos los mtodos disponibles para una clase en concreto. Si al guna vez ha t rabaj ado con C O M (Modelo de objetos componentes), q ui zas este familiarizado con las bibliotecas de t i p o s . Las bibliotecas de tipos tratan de propor ci onar una funcionalidad "de tabla de contenidos" similar par a objetos C O M Sin embargo, las bibliotecas de tipos presentaban algunas limitaciones, una de las cuales consista en que no se incluan todos los datos importantes relacionados con el objeto. Los met adatos d e . N E T no presentan este inconxeniente. Tod a la informacin necesaria par a describir una clase en un codigo esta situada en el metadato. Los metadatos tienen todas las ventajas de las bibliotecas de tipos C OM . pero sin sus limitaciones.

Ensamblados
A veces usara CU para construir una aplicacin para un usuario final. Estas aplicaciones se presentan como archivos ejecutables con extensin EXE. Windows siempre ha t rabaj ado con archivos EXE como p rogr amas de aplicacin y CU admite a la perfeccin la construccin de archivos EXE. Sin embargo, puede h aber ocasiones en las que no quiera construir una ap li ca cin completa. Quizas quiera construir en su lugar una biblioteca de codigo que pueda ser usada por otras personas. Quizas tambin quiera construir algunas clases de utilidad, por ejemplo, y luego transferir el codigo a un p ro g ra ma do r de Visual Basic NET. que usara sus clases en una aplicacin de Visual Basic NET En casos como este, no construir una aplicacin, sino un ensamblado. Un ensambl ado es un paquete de codigo y metadatos. Cuand o utiliza un c on j unt o de clases en un ensamblado, esta usando las clases como una unidad y estas clases compar ten el mismo niv el de control de v ersin, informacin de s eg u n d a d

51

y requisitos de activacin. Imagine un ensambl ado como una "DLL lgica". Si no est familiarizado con Microsoft Transact ion Server o C O M + , puede imaginar un ens ambl ado como el equivalente N E T de un paquete. Hay dos tipos de ensamblados: ensamblados privados y ensamblados globales Al construir el ensamblado, no necesita especificar si quiere construir un e n s a m blado privado o global. La diferencia es ostensible cuando se implcmenta el e n samblado. Con un ens ambl ado privado, hace que el cdigo est disponible par a una sola aplicacin. El ensambl ado se empaquet a como una DLL y se instala en el mismo directorio que la aplicacin que lo est usando. Con el uso de un e n s a m blado privado, la nica aplicacin que puede u sar el cdigo es el ejecutable s i tu a do en el mi smo directorio que el ensamblado. Si quiere compartir el cdigo con varias aplicaciones, quizs quiera considerar el uso del codigo como e ns ambl ado global. Los ensambl ados globales pueden ser usados por cualquier aplicacin N E T en el sistema, sin i mport ar el directorio en el que este instalada. Microsoft incorpora ensambl ados en N E T F ramework y cada uno de los ensambl ados de Mi crosoft se instala como e ns ambl ado global. N E T Fr amewor k contiene una lista de ensambl ados globales en un servicio lla mado cach de ens ambl ado g l oba l y el S DK de N E T Microsoft Framework incluye utilidades p ar a instalar y eliminar ensambl ados de la cach de e n s a m b l a do global.

Resumen
En este captulo se han explicado las bases de N E T Framework. Tra s seguir la evolucin desde C a C + + y hasta C#. se han exami nado los puntos fuertes de la lista de pr e st ac io ne s de C'#. T a m b i n se ha i nves ti gado el p r od u ct o del compi lador de C#. el cdigo MS IL y los metadatos. y se ha revisado el uso de ens ambl ados como los bloques de const rucci n esenciales del cdigo N E T c o m pilado.

52

Escribir su primer programa en C#


wm

Este captulo le gua a travs del desarrollo de una sencilla aplicacin de C#. Tambi n aprender cmo estn es tructur adas las aplicaciones C# ms sencillas y cmo i nvocar al c ompi lador de C# p a r a convertir el cdigo fuente en cdigo que puede ser ejecutado por N E T Framcwork. Finalmente, apr ender a a d o cu men tar el cdigo empl eando coment ari os de cdigo fuente y cmo convertir aut omt i came nt e sus comentarios en un document o XML.

Cmo escoger un editor


A la hora de escribir cdigo p ar a N E T F ramcwork en C# tiene varias opci o nes. La eleccin ms lgica es us ar Visual Studio NET. Usando Visual Studio. dispone de todas las ventajas de la tecnologa IntelliSense. el m ar cado de sintaxis y muchas otras herramientas que aument an la productividad. Muchos editores de terceros intentan a u na r en un paquete las herramientas de produccin de Visual Studio. Algunas de estas herramientas pueden ser de sc a rg a das como Shareware y otras son de libre distribucin. Los ejemplos de este ca p tulo usan sencillamente el Bloc de notas de Windows. Al usar el Bloc de notas, no slo demostramos que se puede u sar cualquier editor de texto para escribir ap li ca

55

ciones en C'#. sino que tambin servir par a aprender las bases necesarias para compilar aplicaciones. Ademas, el uso del Bloc de notas servir par a demostrarle que no necesita confiar en ningn asistente par a generar el cdigo. Puede simplemente co nc e n trarse en el lenguaje mismo, sin tener que aprender los detalles de un IDE. Sin embargo, tenga en cuenta que p ar a las aplicaciones ms grandes quizs prefiera usar un editor que muestre los nmeros de lnea, lo que puede ser muv til cuando se est bus ca ndo codigo defectuoso.

La aplicacin Helio World


El codigo que se muestra en el listado 2.1 es una aplicacin de C# completa. Se ejecuta desde una ventana de la consola y present a el mensaje Helio W o r l d 1en la pantalla. Las siguientes secciones siguen este cdigo lnea a lnea.
Listado 2.1. Cmo escribir en la consola class H e l 1oWorld static void M a i n ( ) World! " ) ;

{
public

{
System.Console.WriteLine ("Helio

} }

Cmo construir una clase


La pri mera lnea del pro gr ama C# define una clase. Una clase es un recipiente par a todo el cdigo de la aplicacin. A diferencia de C y C++. todo el cdigo debe estar contenido en una clase, con escasas excepciones. Estas excepciones a la regla son la instruccin using. las declaraciones de est ructur as y la declaracin namespace. Cual qui er intento de escribir codigo que no este contenido en una clase da como resultado un error de compilacin. La primera lnea de la aplicacin Helio World empieza con la p al abr a clave c l a s s y. a continuacin, la pal abr a H e l l o W o r l d . H e l / o W o r l d es el nombre de la clase que el cdigo est creando. Cada clase debe tener asignado un nombre nico par a que luego pueda referirse a ellas. Inmediatamente despus de la declaracin de clase se debe abrir una llave. La llave de apert ura se usa para abrir el cuerpo de la clase del cdigo. Todo el cdigo que escriba en la clase debe incluirse despus de esta llave de apertura. Ademas de la llave de apert ura, tambin debe haber una llave de cierre, como la que aparece en la ultima lnea de la aplicacin Helio World. Asegrese de que toda su pr ogr amaci n este entre estas dos llaves.

56

El mtodo Main()
Tod as las aplicaciones escritas en C# deben const ar de un mtodo llamado Main ( ) . Un mtodo es un conjunto de instrucciones que realizan una accin. Este mtodo puede devolver i nformacin a la seccin de cdigo que lo llam pero en determinadas ci rcunstanci as no es necesario que lo haga.

NOTA: Los trminos mtodo y funcin suelen usarse de forma indistinta, pero hay una diferencia. Un mtodo es una funcin contenida en una clase. Una funcin suele ser un grupo de instrucciones que no est contenido en una clase y que suele estar en un lenguaje, como C o C++. Como en C# no se puede aadir cdigo fuera de una clase, nunca tendr una funcin.
La palabra clave p u b l i c en la declaraci n del mtodo M a i n ( ) tambin contiene la palabra p u b l i c . que informa al compilador de que el mtodo M a i n () debe ser pbl icament e accesible. El mtodo M a i n ( ) no slo es accesible por otros mtodos desde dentro de la aplicacin, sino tambin ext ernament e por otras aplicaciones. Al d eclarar el mtodo M a i n ( ) como pblico, est creando un p u n to de ent rada p ar a que Wi ndows inicie la aplicacin cuando un us uar io lo desee. C uando un usuario haga doble clic sobre el icono de la a p l i c a c i n HelIoWorki . Wi ndows expl orar el ejecutable en busca de un punto de entrada con ese nombre. Si no encuentra una entrada, la aplicacin no podr ejecutarse. La pal abra Static en la declaracin del mtodo significa que el compi lador slo debe permitir que exista en memori a una c opia del mtodo por vez. C omo el mt odo Main ( ) es el punto de entrada a la aplicacin, sera catastrfico permitir que el punto de entrada se abriese ms de una vez ya que permitira ms de una copia de la aplicacin en memori a e, indudablemente, algunos errores graves. Justo antes de la pal abra Main, ver la palabra Void. Void es lo que la funcin principal devuelve cuando ha compl et ado su ejecucin. Significa que la aplicacin no devuelve ningn valor despus de haberse completado. Esta apl ica cin de ejemplo no es muy avanzad a, as que no necesita devolver ningn valor. Sin embargo, en circunstancias normales, la funcin Main ( ) devolvera un valor entero reemplazando la pal ab ra void por i n t . Valores de devolucin vlidos son cualquier tipo de dato simple definido en . NET Framework. De for ma muy pareci da a una declaracin de clase, cualquier mtodo que defina debe tambin contener una llave de a pe rt ur a y otra de cierre entre las que se debe colocar todo el cdigo del mtodo. Puede ver las llaves de a pe r tu ra y de cierre p a r a el mtodo Main ( ) en las lneas 4 y 6 en el listado 2.1.

Cmo escribir en la consola


La lnea 5 del listado 2.1 contiene una llamada al mtodo WriteLine. Este mtodo est contenido en N E T Framework v escribe una cadena en la consola. Si

57

se ejecuta desde una ventana de la consola, el texto debera aparecer en la p a n t a lla. Si ejecuta este c omando desde un entorno de Visual Studio. cualquier result a do que pr oduzca aparecer en la ventana de salida. Ya hemos aprendido que todas las funciones de CU deben ser definidas d en tro de una clase. Las funciones de N E T F ramework no son una excepcin. La funcin WriteLine ( ) se encuentra en una clase llamada Consol. La p al a bra clave Consol, usada justo antes de la llamada a la funcin WriteLine (). indica al compi lador que la funcin WriteLine ( ) se encuentra en una clase llamada Consol. La clase Consol es una de las muchas clases de N E T Framework y la funcin WriteLine ( ) es un mi embro de la clase Consol. El nombre de la clase est s eparado del nombre de la funcin que se invoca por medio de un punto. El nombre System a p a r e c e i nm ed i at am en t e antes del n om br e de clase Consol. Las clases de . NET Framework estn organizadas en grupos l lama dos espacios de nombre. Los espacios de nombre se explican con mas detalle en un captulo posterior. Por ahora, piense en los nombres de espacios como en una coleccin de clase. La clase Consol se encuentra en un espacio de nombre de N E T F ramework llamado System y debe escribir el nombre de este espacio de n ombre en el codigo. El c om pi l ado r de CU necesita en con tr ar el cdigo de WriteLine ( ) para que la aplicacin se ejecute correctamente y debe dar al c ompi lador suficiente i nformacin sobre los espacios de nombre y las clases a n tes de enc ont rar el cdigo de WriteLine () . El texto que se i ncl ine dentro de los parntesis de WriteLine ( ) es una cadena. Una cadena en CU es una coleccin de caracteres encerrados entre c omi llas y g u ar dado s juntos como unidad. Al colocar la cadena entre los parntesis se indica al compi lador que queremos pas ar la cadena como par met ro de la funcin WriteLine ( ) . La funcin WriteLine ( ) escribe una cadena en la consola \ el par met ro de la funcin indica a WriteLine ( ) qu cadena debe escribirse. La lnea 5 incluye una gran cantidad de informacin que puede interpretarse de la siguiente forma: " Compi lador C#. quiero llamar a WriteLine ( ) con el p ar met ro de cadena 'Helio W o r k l r La funcin WriteLine ( ) se incluye en una clase llamada Consol y la clase Consol se i nc li ne en un espaci o de nombre llamado System. La lnea 5 termina con un punto y coma. Todas las instrucciones deben t erminar con un punto y coma. El punto y la coma separan una instruccin de otra en C#.

Compilacin y ejecucin del programa


Ahora que ya ha revisado el codigo del listado 2.1, es hora de ejecutarlo. Escriba el cdigo del listado 2.1 en su editor de texto favorito y gurdelo como un archivo llamado listado 2.1. es. La extensin es es la extensin de todos los archivos que contienen codigo CU.

58

NOTA: Antes de compilar el ejemplo en C#, debe asegurarse de que el compilador de C# est en su Path. La aplicacin csc.exe generalmente est en la carpeta C: \W in d o ws \ M ic ro so ft .N ET \F ra me wo rk \ v i . 0 . x x x x (reemplace Vl.O.Xxxx con su versin de .NET Framework), lo que puede comprobar buscndola en Windows. Para aadir entradas a su ruta, busque en la Ayuda de Windows la palabra Path.
A continuacin abr a un smbolo de comandos y dirjase a la carpet a en la que guar d el archivo HelloWorld.es. Una vez all, puede escribir el siguiente comando:
ese HelloWorld.es

El c omando ese invoca al compi lador C# de N E T Framework. Al ejecutar este c omando se genera un ejecutable llamado HelloWorId .eze. que puede ser ejecutado exactamente igual que cualquier aplicacin de Windows. Si ejecuta mos este archivo, se escribir texto en la ventana de la consola tal y como se muestra en la figura 2.1.

Figura 2.1. La ventana emergente de co m a n d o muestra la aplicacin Helio W orld en accin.

jEnhorabuena! A cab a de escribir su pri mera aplicacin de C#.

Las palabras clave y los identificadores


La aplicacin de C# del listado 2.1 contiene muchas palabras, separadas por espacios. En ella, se utilizan dos tipos de nombres: palabras clave e identificadores. Esta seccin describe las diferencias entre estos dos tipos de nombres. Las pal abr as clave son p al abr as que tienen un significado especial en el len guaje C#. Estas pal abr as han sido reservadas en C# y nos referimos a ellas como

59

p a la b ra s r e s e r v a d a s . Las palabras class. static y void son las palabras reservadas del listado 2.1. Ca da pal ab ra clave posee en el lenguaje C# un signifi cado especial. La siguiente lista contiene todas las p al abr as clave definidas en C#.
abs tract as base bool br ea k b yte ca se ca 1 0 h char 0h e 0 ked c lass 00 n s t continue d ecimal de fault delegate do doub 1 e else en um event e xp li c it extern false fi nally f ix e d f 10at for fore a 0 h a01 0 1f 1m p l i ci t in int i nt erf ace in ter nal is lock long namespace new null ob j e c t o p er a t or out 0 ve r ride pa rams p r i vat e p r0 1 e c :t e d publi c r ea do n ly ref return sby t e s ea led short sizeof stackalloc static string s truc t switch this th row true try t ypeo f u 1111 ulong unchecked un sa f e u sh 0 rt us ing vi rt ual vo i d whi 1 e

Los identifcadores son los nombres que se usan en las aplicaciones. C# 110 reserv a nombres de dcntificadores. Los identificadores son palabras que designan objetos en el codigo CU. Su clase necesita un nombre y se ha usado el nombre Hel loWor ld para su clase. Esto convierte al nombre HeUoWorld en un identificado!'. Su mtodo tambin necesita un nombre y se ha usado el nombre M a m para su funcin. Esto convierte al nombre M a m en un identificador. El compilador de C# no permite normalmente usar ninguna de las palabras clave reservadas como n o m bres de identifcador. Obtendr un error si. por ejemplo, intenta aplicar el nombre static a una clase. Sin embargo, si realmente necesita usar el nombre de una palabra clave como identifcador. puede poner delante del identificador el smbolo a . Esto invalida el error del compilador y permite usar una palabra clav e como identifcador. El listado 2.2 muestra como hacerlo. Es una modificacin del cdigo del listado 2 1 y define la palabra virtual como el nombre de la clase.

60

Listad o 2.2. C m o usar la palabra clave virtual como identificador de clase class @virtual

{
static void M a m ( ) W o r l d ! ");

{
System.Consol.WriteLine("Helio

Sin el precedente smbolo a,, obtendra un error del compilador, como el que se muestra en la figura 2.2.

Figura 2.2. Si olvida el sm bolo @ el com pila dor generar errores.

Uso de espacios en blanco


El texto de las aplicaciones C# puede incluir espacios, tabulaciones y c a ra c te res de retorno. Estos caracteres son llamados caracteres de espacio en blanco. Los caracteres de espacio en blanco, que pueden ser colocados en cualquier lugar excepto en medio de una p al ab ra clave o un identificador. ayudan a mej orar la legibilidad del cdigo. El compi lador de C # p a s a por alto la colocacin de espacios en blanco cuando compila un progr ama. Esto significa que puede colocar cualquier ca rcter de espacio en blanco en cualquier lugar donde el compi lador acepte un carcter de espacio en blanco. El compi lador p a sa p or alto el uso de caracteres de retorno, t abulaciones y espacios. Puede u sar cualquier combinacin de espacios en blanco que desee en su cdigo. Los listados de este libro mues tran estilos personales de colocacin de e s p a cios en blanco: los retornos estn colocados antes y despus de las llaves de ape rt ura y cierre, y el cdigo est s angrado a partir de las llaves. Sin embargo, no es obligatoria esta disposicin en las aplicaciones C#. El listado 2.3 muest ra una

61

disposicin alternativa del codigo usando caracteres de espacio en blanco dife rentes. No tema experi ment ar con el estilo que ms le guste.
Listado 2.3. Una disposicin de espacios en blanco alternativa C 1a s s
H e ! 1oWo r 1d

I
stat ic voi c M a in ()

I
Jy.stem. Consol e .WriteLi ne "Helio W o r l d !" ) ;

} } Si compila y ejecuta el listado 2.3. ver que se c omport a exactamente igual que el codigo del listado 2.1: produce la cadena "Helio W o r ld 1 " . La nueva d is po sicin de espaci os en bl anco no tiene ningn efecto en el comport ami ent o del codigo que se ejecuta en el tiempo de ejecucin.

Cmo iniciar programas con la funcin Main()


La aplicacin que se muestra en el listado 2.1 define una clase con una funcin llamada Main(). La funcin M a i n ( ) es una parte importante de las aplicaciones CU. va que es donde comienza a ejecutarse nuestro programa. Todas las ap li ca ciones escritas en CU deben tener una clase con una funcin llamada M a i n ( ) . La funcin Ma m ( ) es conocida como el punto de entrada de sus aplicaciones v la ejecucin de sus aplicaciones CU empieza con el codigo en Mal n ( ) . Si el codigo contiene mas de una clase, solo una de ellas puede tener una funcin llamada Ma i n ) . Si olvida definir una funcin Ma i n ( ) . recibir varios m e n s a jes de error por parte del compilador, como se muest ra en la figura 2.3.

C:\>csc HelloWoi-ld.cs Compilador de Microsoft <R> Uisual C# .NET versin 7.00.9466 para Microsoft <R> .NET Framework versin 1.0.3705 <C> M icrosoft Microsoft Corporation 2001. Reservados todos los derechos. HelloUorId.es<35> : error CS1520: Una clase, una estructura o un mtodo de interfaz debe tener un tipo de ualor devuelto

Figura 2.3. La ausencia de una funcin Main () produce errores de compilacin

62

La funcin Main ( ) definida en el listado 2.1 no devuelve nada (de ahi la palabra clave void) y no toma argument os (de ah los parntesis vacos). El compi lador C#. de hecho, acepta cualquiera de las c uatro posibles construcciones de la funcin Main ( ) :

pubiic public

static static static static

void void

Main( ) M a i n (s t r i n g [] Arguments)

public public

int M a i n ( ) int M a m (string [ ] Arguments)

La primera variante, public static void Main ( ) . es la forma usada en el listado 2.1. La segunda, public static void Main ( string [ ] Arguments). no devuelve un valor al que la llama. Sin embargo, toma una matriz de cadenas. Ca d a cadena de la matriz se corresponde a un ar gument o de la lnea de comando suministrado al ejecutar el programa. Por ejemplo, suponga que modifica el codigo del listado 2.1 par a que el mtodo Main ( ) acepte una matriz de cadenas como ar gumento. Adems, s uponga que ejecuta ese cdigo y sumi nist ra algunos ar gument os de lnea de comandos:
Listing2-l.exe Paraml Param2 Param3

En este caso, la matriz de cadenas que se pas a a la funcin Main ( ) tiene los siguientes contenidos:
Arguments [0] : Paraml Arguments [1 ] : Param2 Arguments [2] : Param3

La tercera variante, public static int Main (). devuelve un valor entero. Que el valor que se devuelve sea entero se especifica mediante la pal ab ra clave int de la declaracin. Los valores enteros dev ueltos por Main ( ) se usan como cdigos de fin de programa. Por ejemplo, s uponga que desea disear sus aplicaciones par a que devuelvan un valor ( supongamos 0) si la operacin resulta satisfactoria y otro valor ( supongamos 1) si la operacin no se cumple. Si ejecuta la aplicacin N E T desde un entorno que puede leer este cdigo de terminacin de programa, tiene suficiente informacin par a determinar si el pr og r am a se ejecuto satisfactoriamente. La ltima variante de la funcin Main ( ) ,public static int Main (string [] Arguments ). especifica una funcin que p r o po r ciona ar gument os de lnea de comando en una matriz de cadenas y permite a la funcin devolver un cdigo de terminacin de programa. Debe tener presente algunas cosas cuando trabaje con la funcin Main ( ) : Las formas de devolucin void de la funcin Main ( ) siempre tienen un cdigo de terminacin de p r o gr a ma de 0.

63

La palabra clave s t a t i c es necesaria en todas las variantes de la f un cin M a i n ( ) . Cuand o se ejecuta una aplicacin de C#. el usuario siempre propor ci ona los argument os de la lnea de comando. Sin embargo, si la aplicacin de C# esta escrita con una de las variantes de la funcin M a i n ( ) que no toma argumentos, la aplicacin sera incapaz de leerlos. Est permitido que el usuario especifique argument os en una aplicacin de C# que no fue escrita para admitirlos (aunque no sera muy til).

Cmo comentar el cdigo


C omen tar el codigo le permite aadir notas a sus archiv os fuente de C#. Estas notas pueden ayudarle a do cu ment ar el diseo y el funcionamiento de la a p l i c a cin. Puede colocar comentarios en cualquier parte del cdigo fuente de C# donde sea posible usar espacios en blanco.

Cmo usar comentarios de una lnea


Los comentarios de una lnea empiezan con dos bar ras inclinadas y afecta al resto de la lnea:
{ // esto es una llave de apertura System.Console.WriteLine ("C#"j ; // cali } // esto es una llave de crerre WriteLme ( )

Usar comentarios regulares


Los comentarios regulares empiezan con una b ar r a inclinada seguida de un asterisco y su efecto per manece hasta que encuentra un asterisco seguido por una barra inclinada. Los comentarios regulares pueden extenderse por varias lneas: /*
Esto es un comentario regular de C# . Contiene varias lineas de texto, Separadas por caracteres N e w L i n e .

V El compi lador de C# no permite incrustar un comentario regular en otro: /*


comentario externo interno comentario externo

/*
comentario

*/
mas texto de

*/

64

No puede i ncrust ar un coment ari o regular en otro porque el compi lador e n cuentra los primeros caracteres */ y da por hecho que ha al ca nzado el final del coment ari o de varias lneas. A continuacin, supone que el siguiente texto segui do por los caracteres es cdigo fuente de C# c intenta interpretarlo como tal. Sin embargo, puede i ncrust ar un coment ari o de una sola lnea en un c o me nt a rio regular: /*
comentario externo // comentario interno mas texto de comentario externo

*/

Cmo generar documentacin XML a partir de comentarios


Una caracter st ica interesante del compi lador de C# es que puede leer c om en tarios en un formato especial y generar document aci n X M L a partir de los c o mentarios. Puede entonces colocar este X M L en la We b par a facilitar un nivel extra de documentacin a los p rogr amadore s que necesiten comprender la es t ruc tura de sus aplicaciones. Par a usar esta funcin, debe hacer dos cosas: Usar tres barras inclinadas par a los comentarios. El compi lador de C# no genera ni nguna d ocument aci n X M L p a r a ningn document o que no e m piece con tres barras. T a m po c o genera documentacin X M L p a r a c om en tarios regulares de varias lneas. Use la opcin / d o c del compi lador de C# par a especificar el nombre del archivo que debera contener la d ocument aci n X M L generada.

El listado 2.4 muest ra la aplicacin H elio W o r ld ! con coment ari os de d o c u mentacin XML.
Listado 2.4. La aplicacin Helio W orld! con comentarios XML /// La clase HelloWorld es la nica clase de la /// clase "HelloWorld". La clase implementa la funcin /// Main ( ) de la aplicacin. La clase no contiene otras /// f u n c io ne s. class HelloWorld sta es la funcin Main ( ) para la clase del listado 2.4. No devuelve un valor y no toma ningn argumento. Escribe el texto "Helio World!" en la consola y luego sale.

{
/// /// /// ///

65

static void M a m ()

{
System. Consol. W r i t e L m e ("Helio World! ") ;

} } Puede compi lar esta aplicacin con la opcin / d o c par a generar d o cu ment a cin X M L p ar a el cdigo fuente:
ese /d o c :He 11o Wor Id .xml HelloWorld.es

El compi lador produce un H e l l o W o r l d . e x e como era de esperar y t a m bin un archivo llamado HelloWorld.xml. Este archi vo contiene un document o X M L con sus comentarios de document aci n X M L i ncrustados en l. El listado 2.5 mues tra el document o X M L que se genera cuando se compila con la opcin / d o c el cdigo del listado 2.4.
Listado 2.5. Docum ento X ML generado para el cdigo del listado 2.4 <?xml v e rs io n= "1.O "?> <doc> < a s s e mb 1 y > < a m e > H e 11oWo r 1d < /ame > < / a s s e mb 1 y > < membe r s > <membe r name = "T :H e 1loWorId"> La clase HelloWorld es la nica clase de la clase "HelloWorld". La clase implementa la funcin Main () de la aplicacin. La clase no contiene otras funciones. </membe r > ''membe r name= "M :He 11 oWor Id .Ma m "> Esta es la funcin Main ( ) para la clase del listado 2.4. No devuelve un valor y no toma ningn argumento. Escribe el texto " HelloWorld!" en la consola y luego sale. < /me mb e r > </membe rs > < /doc >

Ahora puede escribir una hoja de estilo par a este document o en X ML y m o s trarlo en una pgi na Web. propor ci onando a los dems usuarios documentacin actual izada de su cdigo. La principal porcin del document o X M L est en el elemento < m e m b e r s > . Este elemento contiene una etiqueta < m e m b e r > p ar a cada objeto document ado en el codigo fuente. La etiqueta < m e m b e r > contiene un atributo, a m e , que designa al mi embro documentado. El valor del at ri but o a m e empieza con un prefijo de una letra que describe el tipo de i nformacin en cuestin. La tabla 2.1 describe los posibles valores del at ri but o del nombre y su significado.

66

Tabla 2.1. Prefijos de atributo <m em ber> " a m e -

P r e fijo

S ig n ific a d o

E F M N P T

El elemento proporciona documentacin de un evento. El elemento proporciona documentacin de un campo. El elemento proporciona documentacin de un mtodo. El elemento proporciona documentacin de un nombre de espacio. El elemento proporciona documentacin de una propiedad. El elemento proporciona documentacin de un tipo defini do por el usuario. ste puede ser una clase, una interfaz, una estructura, una enumeracin o un delegado. El compilador C# encontr un error y no pudo determinar el prefijo correcto de este miembro.
Tras el prefijo se colocan dos puntos y el nombre del miembro. El atributo

name= indica el nombre de la clase p ar a los miembros de tipo. Para los m ie m bros de mtodo, el atributo name = indica el n ombre de la clase que contiene el
mtodo, seguida p or un punt o y a continuacin el nombre del mtodo. Sus comentarios de do cument aci n X M L pueden incluir cualqui er elemento X M L vlido par a ayudarle en su tarea de documentacin. La document aci n de N E T F ramework recomienda un conjunto de elementos X ML que puede us ar en su documentacin. El resto de esta seccin exami na cada uno de estos elementos. Recuerde que debe emplear X M L vlido en sus comentarios, lo que significa que cada elemento debe contener su elemento final cor respondiente en al guna par te de sus c o me nt a rios.

NOTA: El trmino etiqueta se refiere a cualquier elemento descriptivo con tenido en el XML. Las etiquetas siempre estn entre los smbolos < y >.

<c>
Puede usar la etiqueta <c> p a r a indicar que una pequea parte del comentario debe ser t rat ada como cdigo. Las hojas de estilo pueden u sar este elemento par a mos trar la porcin de cdigo del comentario con una fuente de t amao fijo, como Courier:
/// sta es la funcin <c>Main ( ) </c> para la /// clase HelloWorld.

67

<code>
Puede us ar la etiqueta <code> par a indicar que varias lneas de texto de sus comentarios deben ser t rat adas como cdigo:
/// /// /// /// /// /// /// /// Llamar a esta aplicacin con tres argumentos hara gue la matriz de cadenas suministrada a M a i n ( ) contenga tres elementos: ^ code > A r g u m e n t [0]: command line argument 1 A r g u m e n t [1]: command line argument 2 A r g u m e n t [2]: command line argument 3 </code>

<example>
Puede us ar la etiqueta < example > par a indicar un ejemplo de cmo usar las clases que desarrolle a otros progr amadores. Los ejemplos suelen incluir una muest ra de cdigo y quizs quiera us ar las etiquetas <example> y <code> juntas:
/// <e xa mp 1e>Aqui tiene un ejemplo de un /// a este codigo: /// x code> /// ponga agu su codigo de ejemplo /// ^ /code > /// s / example> cliente llamando

<exception>
Puede usar la etiqueta <ezception> par a document ar cualquier excepcin que pueda surgir en el cdigo del miembro. La etiqueta <exception> debe contener un atributo l lamado cref cuyo valor especifica el tipo de excepcin que se documenta. El valor del at ri but o cref debe estar entre comillas. El texto del elemento describe las condiciones en las que ap arece la excepcin:
/// <exception cref = "System.Exception" > /// Aparece si el valor introducido es menor de 0. /// < /exception>

El compi lador de C# asegura que el valor del atributo cref sea un tipo de datos v lido. Si no lo es. el compi lador genera un mensaje de aviso. A c o nt i nu a cin se indica cmo d ocumen ta r una funcin Main ( ) :
/// <exception eref=" junk ">probando</exception>

hace que el compi l ad or de C# genere un mensaje de aviso como el siguiente:


aviso CS 1574: El comentario en XML 'Main ( ) ' tiene un atributo cref 'junk' que no se encuentra

En este caso, el compi lador de C# todav a cscribe la etiqueta <except ion> en el archivo XM L. pero pone un signo de exclamaci n antes del atributo cref:

68

Cmember na me = " M :M y C l a s s .Main"> <exception c r e f = " !:junk">probando</exception> </membe r>

<list>
Puede usar la etiqueta <list> p ar a describir una lista de elementos en la documentacin. Puede describir una lista no numerada, una lista n umera da o una tabla. La etiqueta <list> usa un atributo llamado type par a describir el tipo de la lista. La tabla 2.2 enumera los posibles valores para el atributo type y describe su significado.
Tabla 2.2. Valores para el atributo "type" de la etiqueta <list>

V a lo r

S ig n ifica d o

b u lle t numbe r t a b le

La lista es una lista no numerada. La lista es una lista numerada. La lista es una tabla.

Los estilos bullet y number deberan tambin incluir una o ms etiquetas <item> dentro de la etiqueta <list>. Ca da etiqueta <item> se corresponde a un elemento de la lista. C ad a etiqueta <item> debera contener una etiqueta <description>. cuyo texto define el texto de la lista de elementos:
/// /// /// /// /// /// /// /// <list t y pe ="b u l l e t "> < it em> <description>ste es el elemento 1.</description> < / item> < item> <description>ste es el elemento 2. </description> < / it em> </list>

El tipo de lista table tambin debe incluir una etiqueta <listheader>. La etiqueta <listheader> contiene una o ms etiquetas <term> que descri ben los encabezami ent os de las tablas:
/// /// /// /// <list t y p e= "t a bl e"> <listheader> <term>Elemento de la tabla </term> </listheader>

/ / / <item>
/// <description> ste es el elemento 1.</description> /// </item> /// </list>

69

<param>
Use la etiqueta <param> para document ar un par met ro para una funcin La etiqueta <param> usa un atributo, ame, c u n o valor identifica al par met ro que se est documentando. El texto de la etiqueta <param> proporciona una descripcin del parmetro:
/// Aparara name-"Flag"> /// El valor debe ser 0 para desactivado /// </par aras o 1 para activado.

El compi lador de C# asegura que el v alor del atributo ame realmente es pe ci fique el nombre de un parmetro. Si no es as. el compilador emite dos avisos. Por ejemplo, un codigo fuente como el siguiente:
/// <param name="junk">Esto es j u n k .</param> void Main(string [ ] strArguments)

publ i c static

{ } p rod uc e av isos como los siguientes:


aviso CS 1572: El comentario XML en 'Main(string[] ) ' tiene una etiqueta de parametro para 'junk', pero no hay ningn parametro con ese nombre aviso CS1573: El parametro 'strArguments' no tiene una etiqueta de parametro coincidente en el comentario XML (pero otros paramet ros si)

El pri mer aviso dice que se encontr una etiqueta <param> con un atributo ame cuyo valor no concuerda con ninguno de los p ar met ros de la funcin. El segundo aviso dice que a uno de los par met ros le falta una etiqueta <param>. La etiqueta <param> se coloca en el archivo X M L de documentacin, i ncl u so si el atributo ame es incorrecto:
<member n ame="M:Classl.Main(System.String[])"> <param n a m e = "jun k">Esto es junk.</param> </membe r>

<paramref>
Puede usar la etiqueta <paramref> par a hacer referencia a un parmet ro desde una descripcin. La etiqueta puede no tener ningn texto; sin embargo, lleva un at ri but o llamado ame. El valor del atributo ame debe indicar el nombre del p ar m et ro al que se hace referencia:
/// /// La matriz <paramref n ame="Arguments" /> contiene los parmetros especificados es la linea de comandos.

70

<permission>
Use la etiqueta <permission> p a r a d ocument ar los permisos disponibles en una funcin o variable dadas. El acceso al cdigo y los datos de una clase puede significar el ac ces o a todo el cdigo o puede ser restringido a cierto subconjunto de cdigo. Puede u s ar la etiqueta <permission> p a r a d oc um en t ar la disponibilidad del cdigo y sus datos. La etiqueta <permission> hace uso de un atributo, cref. El valor del elemento cref debe designar la funcin o la variable cuyos permisos se estn documentando:
/// <permission name= " M a m ( ) "> /// Todo el mundo puede acceder /// < /permission> a M a i n ().

<remarks>
Use la etiqueta <remarks> p ara aadir informacin. El elemento <remarks> es estupendo p ar a mo st rar una vista general de un mtodo o una variable y su uso. La etiqueta <remarks> no tiene atributos y su texto contiene las observaciones:
/// /// /// /// /// <remarks> La funcin M a i n ( ) es el punto de entrada a la aplicacin. El CLR llamar a M a i n ( ) para iniciar la aplicacin una vez que sta se haya abierto. </remarks>

<returns>
Use la etiqueta <returns> p ar a describir un valor devuelto por una f un cin. La etiqueta <returns> no tiene atributos y su texto contiene la i nforma cin del valor devuelto:
/// /// /// /// /// <returns> La funcin M a i n ( ) devolver 0 si la aplicacin proces los datos correctamente y devolver 1 en caso contrario. < / returns>

<see>
Use la etiqueta <see> par a aadir una referencia a una funcin o variable que se encuentre en ot ra parte del archivo. El elemento <see> usa un atributo l lama do cref cuyo valor especifica el nombre del mtodo o variable al que se hace referencia. La etiqueta <see> no debe contener texto:
/// <see cref="C 1 a s s 1.M a i n " />

El compi lador de C # a segura que el valor del at ri but o cref realmente e speci fique el nombre de un mtodo o variable. Si no es as. el c ompi lador emite un aviso. Por tanto, un cdigo fuente como el siguiente:

71

/// <see cre="]unk" /> public static void Main(string [ ] strArguments)

{ } produce un aviso como el siguiente:


aviso CS1574: El comentario XML en 'Classl .Main (string [ ) ' tiene un atributo cref 'junk' que no se encuentra

La etiqueta < s e e > est situada en el archivo X M L de documentacin, i nclu so si el atributo cref es incorrecto:
^member name= "M :Cassi.Main(System. String [ ] ) "> <se e cref = " ! :jun k "/> </me mb e r >

<seealso>
C o m o <see>. puede us ar la etiqueta <seealso> par a aadir una referencia a una funcin o variable que este' en otra parte del archivo. Puede que necesite g enerar d ocument aci n que cont enga una seccin de referencias <see> ademas de una seccin de referencias See Also y el compi lador de C# le permite hacer esa distincin al admi tir las etiquetas <see> y <seealso>. La etiqueta <seeaiso> usa un atributo llamado cref c u n o valor especifica el nombre del mtodo o variable al que se hace referencia. La etiqueta <seealso> no debe contener texto:
/// '.see al.so c r ef = "Cas s 1 .Main" />

El compi lador de C# as egura que el valor del atributo cref realmente es pe ci fique el nombre de un mtodo o variable Si no es as. el compi lador emite un av iso. Por tanto, un cdigo fuente como el siguiente:
/// <seealso cref="junk" /> public static void Main(string [ ] strArguments)

( ) produce un aviso como el siguiente:


aviso CS1574: El comentario XML en 'Classl.Main(string [] ) ' tiene un atributo cref 'junk' que no se encuentra

La etiqueta <seealso> est situada en el archivo X M L de documentacin, incluso si el atributo cref es incorrecto:
'membe r ame = "M: Classl.Main (System.St ring [ ] ) "> 'seealso c r e f = " ! :j un k " / > < /membe r >

72

<summary>
Use la etiqueta < s u m m a r y > p ar a pr opor ci onar una descripcin resumida de un fragment o de cdigo. Esta etiqueta no admite ningn atributo. Su texto debe describir la informacin resumida:
/// <summary> /// La funcin M a i n ( ) es el punto de entrada de /// esta aplicacin. /// </summaiy>

La etiqueta <summary> es como la etiqueta <remarks>. Generalmente, debe u sar la etiqueta <summary> p a r a pr opo rci onar informacin sobre un m todo o variable y la etiqueta < remarks> p a r a propor ci onar i nformacin sobre el tipo del elemento.

<value>
Use la etiqueta <value> p ar a describir una propiedad de la clase. La etique ta <value> no tiene atributos. Su texto debe d ocument ar la propiedad:
/// /// /// /// <value> La propiedad MyValue devuelve leidos de la base de datos. </value> int MyValue aqui . . . el nmero de registros

public

{
// . . . el cdigo de propiedad viene

Resumen
Este captulo mu es t ra cmo crear aplicaciones C# con un simple editor de texto, como el Bloc de notas. Tambi n examina varias alternativas a Visual Studio p a r a escribir cdigo. Ha construido su pri mera aplicacin de CU. Las aplicaciones CU. indepen dientemente de su t amao, deben contener una clase con un a funcin l lamada Main ( ) . La funcin Main ( ) es el punto de par ti da de su aplicacin de CU. Tamb in aprendi a aadir comentarios al cdigo fuente en CU. Puede aadir comentarios al cdigo p ar a ay ud a r a otros pro gr amado re s a comprender cmo est es tructur ado el cdigo fuente. Tambi n puede dar formato a las comentarios de tal modo que el comp il ado r pu ed a convertir los coment ari os en un document o XM L; y aadiendo pal ab ras clave especiales, puede hacer el document o X M L muy rico e informativo.

73

el Trabajar con variables

El cdigo de C# suele t rabaj ar con valores que no se conocen cuando se escribe el cdigo. Puede que necesite t r a b aj a r con un valor ledo de una base de datos en tiempo de ejecucin o quizs necesite al macenar el resultado de un clculo. C u a n do necesite al ma c en ar un valor en el tiempo de ejecucin, use una variable. Las variables son los sustitutos de los valores con los que t rabaj a en su cdigo.

Cmo dar nombre a sus variables


Cada variable que use en su cdigo C# debe tener un nombre. El compilador de C# interpreta los nombres de las variables como identificadores y. por tanto, deben seguir las convenciones de designacin de los identificadores: El primer ca rcter de un identificador debe empezar con una letra m a y s cula o mi nscul a o con un carcter subrayado. Los caracteres que siguen al primero pueden ser cualquiera de los siguientes: Una letra m ay s cul a o mi nscula Un nmero Un s ubravado

75

NOTA: C# admite cdigo fuente escrito con caracteres Unicode. Si est escribiendo su cdigo fuente usando un conjunto de caracteres Unicode, puede usar cualquier carcter de entre las clases de caracteres Unicode Lu, LI, Lt, Lm, Lo, Ni, Mn, Me, Nd, Pc y Cf en su identificados Consulte la seccin 4.5 de las especificaciones de Unicode si desea obtener ms infor macin sobre las clases de caracteres Unicode.
Tamb in puede usar una pal ab ra clave de C# como nombre de variable, pero slo si va precedida del caracter a . No obstante, no se trata de una prctica recomendable, ya que puede hacer que su cdigo resulte difcil de leer, pero es factible y el compi lador de CU lo permite.

Asignacin de un tipo a una variable


A las v ariables de C# se les asigna un tipo, que es una descripcin del tipo de datos que va a contener la variable. Quizs quiera t rabaj ar con nmeros enteros, nmeros de coma flotante, caracteres, cadenas o incluso un tipo que puede definir en su codigo. C uand o define una v ariable en su cdigo CU. debe a si gnar un tipo a la v ariable. La tabla 3.1 describe algunos de los tipos bsicos de variables de CU.
Tabla 3.1. Tipos de datos com unes de C#

D e sc r ip c i n
sbyte

Las variables con tipo sbyte pueden contener nmeros enteros de 8 bits con signo. La s de sbyte significa con signo, lo que quiere decir que el valor de la variable puede ser positivo o negativo. El menor valor posible para una variable sbyte es -128 y el mayor es 127. Las variables con tipo byte pueden contener nmeros enteros de 8 bits sin signo. A diferencia de las variables sbyte, las variables by te no tienen signo y slo pue den contener nmeros positivos. El valor ms pequeo posible para una variable by te es 0; el valor ms alto es 255. Las variables con tipo short puede contener nmeros enteros de 16 bits con signo. El menor valor posible para una variable sh o r t es -32.768; el valor ms alto es 32.767. Las variables con tipo usho rt pueden contener nme ros enteros de 16 bits sin signo. La u de u short signifi-

byte

short

us hort

76

T ip o

D e sc r ip c i n

ca sin signo. El menor valor posible para una variable u s ho r t es 0; el valor ms alto es 65.535.
int

Las variables con tipo int pueden contener nmeros en teros de 32 bits con signo. El menor valor posible para una variable int es -2.147.483.648; el valor ms alto es 2.147.483.647. Las variables con tipo uint pueden contener nmeros enteros de 32 bits sin signo. La u en uint significa sin signo. El menor valor posible para una variable uint variable es 0; el valor ms alto posible es 4.294.967.295. Las variables con tipo long pueden contener nmeros enteros de 64 bits con signo. El menor valor posible para una variable long es 9.223.372.036.854.775.808; el va lor ms alto es 9.223.372.036.854.775.807. Las variables con tipo u l ong pueden contener nmeros enteros de 64 bits sin signo. La u en u l on g significa sin signo. El menor valor posible para una variable ulong es 0; el valor ms alto es 18.446.744.073.709.551.615. Las variables con tipo char pueden contener caracteres Unicode de 16 bits. El menor valor posible para una va riable char es el carcter Unicode cuyo valor es 0; el valor ms alto posible es el carcter Unicode cuyo valor es 65.535. Las variables con tipo float pueden contener un valor de coma flotante de 32 bits con signo. El menor valor posible para una variable float es aproximadamente 1,5 por 10 elevado a 45; el valor ms alto es aproxima damente 3,4 por 10 elevado a 38. Las variables con tipo d ou b l e pueden contener un valor de coma flotante de 64 bits con signo. El menor valor posible para una variable d ou b l e es aproximadamente 5 por 10 elevado a 324; el valor ms alto es aproximada mente 1,7 por 10 elevado a 308. Las variables con tipo d e ci ma l pueden contener un va lor de coma flotante de 128 bits con signo. Las variables de tipo d ec i m a l son buenas para clculos financieros. El menor valor posible para una variable decimal es aproximadamente 1 por 10 elevado a 28; el valor ms alto es aproximadamente 7,9 por 10 elevado a 28. Las variables con tipo bool pueden tener uno de los dos posibles valores: true o false. El uso del tipo bool es

uint

long

ul ong

char

float

doub1 e

de c i m al

bool

77

T ip o

D e sc r ip c i n

una de las partes en las que C# se aparta de su legado C y C++. En ellos, el valor entero 0 era sinnimo de false y cualquier valor que no fuese cero era sinnimo de t ru. Sin embargo, en C# los tipos no son sinnimos. No pue de convertir una variable entera en su valor equivalente bool. Si quiere trabajar con una variable que necesita tener una condicin verdadera o falsa, use una variable bool y no una variable Int.

Cmo aplicar tamao a sus variables


Se estar preguntando por qu C# admite todos estos tipos de variables diferentes. Los valores ms pequeos pueden colocarse en variables de mayores tipos; por lo tanto por qu usar los tipos ms pequeos? Si una variable s h o r t puede contener valores desde -32.768 hasta 32.767, y una grande puede contener valores desde -9.223.372.036.854.775.808 hasta 9.223.372.036.854.775.807, entonces es evidente que todos los posibles valores s h o r t pueden ser almacenados en una variable lo n g . Entonces, para qu sirven los tipos s h o r t ? Por qu no usar un variable lo n g para todo? Una respuesta es el consumo de memoria. Una variable lo n g puede conte ner valores ms grandes, pero tambin necesita ms memoria. Una variable s h o r t usa 16 bits (dos bytes), mientras que una grande usa 32 bits (cuatro bytes de memoria). Si va a trabajar con valores que no van ms all del lmite de una variable s h o r t , use la variable s h o r t . Es una buena cos tumbre usar toda la memoria que necesite, pero no usar ms de la necesaria.

Cmo declarar sus variables


Antes de poder usar su v ariable, debe declararla en su cdigo. Al declarar una variable informa al compi lador de C# del tipo y nombre de su variable. Una variable se declara escribiendo su tipo, seguido de algn espacio en blanco v. a continuacin, del nombre de la v ariable. Termine la declaracin con un punto v coma. Al gunos ejemplos de declaracin de variables son:

byte MyByteVarable ; in t V a 1 u e 12 3 ;
ulong

AVeryLa rg eN um be r;

78

NOTA: Los espacios en blanco se definen como cualquier nmero de espacios necesario para mejorar la legibilidad del cdigo.
Debe declarar sus variables dentro de un a clase o de una funcin. El siguiente cdigo es vlido:
class MyClass MylntegerVariable ;

{
int

static void M a i n ( )

{
float AnotherVariable;

System.Co ns ol e . W r i t e L i n e ( " H e l l o ! ");

} }

NOTA: Puede declarar una variable donde desee, pero tenga en cuenta que si la declara en una funcin, como se muestra en la variable AnotherVariable del ejemplo anterior, slo el cdigo incluido en esa funcin podr trabajar con la variable. Si la declara dentro de la clase, como en la variable Mylnt egerVariable (tambin en el ejemplo ante rior), todo el cdigo de esa clase podr trabajar con esa variable. Si toma el cdigo del ejemplo y le aade otra funcin a la clase, el cdigo de esa nueva funcin podr trabajar con la variable MylntegerVariable pero no podr trabajar con la variable AnotherVariable. Si esta nueva fun cin intenta acceder a la variable AnotherVariable declarada en la funcin Main ( ) , obtendr el siguiente mensaje de error del Compilador de C#:
error CS0103: El nombre 'AnotherVariable' o espacio de nombre 'MyClass' no existe en la clase

Uso de valores por defecto en las variables


En otros lenguajes de programaci n, es posible t raba jar con una variable sin antes asignarle un valor. Este vaco es una fuente de errores, como demuest ra el siguiente cdigo: class MyClass {
static void M a i n ( )

79

{
int MyVariable; es el valor de "MyVariable" aqui?

// Cual

} } Cul es el valor de MyVariable cuando se ejecuta Main ( ) ? Su valor es desconocido porque el cdigo no asi gna ningn valor a la variable. Los p rogr amadore s de C# eran conscientes de los errores que podian aparecer como resultado de usar variables a las que no se las ha asignado explcitamente un valor. El c ompi lador de C# bu sca condiciones como sta y genera un mensaje de error. Si la funcin Main ( ) del cdigo anterior hace referencia a la variable MyVariable sin que se le hay a asignado un valor, el compi lador de C# muest ra el siguiente mensaje de error:
error CS0165: Uso de la variable local no asignada 'MyVariable'

C# distingue entre variables asigna da s y no asignadas. Las variables as i gn a das han recibido un valor en algn punt o del cdigo y las variables no asi gnadas no han recibido ningn valor en el cdigo. En C# no se permite t ra ba j ar con variables no asi gnadas porque sus valores son desconocidos y empl ear estas v a riables puede generar errores en su cdigo. En al gunos casos. C # otorga valores por defecto a variables. Uno de estos casos es una variable declarada en el nivel de clase. Las variables de clase reciben valores por defecto si no se les asi gna un val or en el cdigo. Modifique el cdigo anterior ca mbi ando la variable MyVariable de una variable declarada en el nivel de funcin a una variable d ec la rada en el nivel de clase:
class MyClass

{
static static int MyVariable; void Main()

{
// MyVariable recibe un valor por // defecto y puede ser usada agu

} } Esta accin mueve la declaracin de la variable dentro de la variable de clase y la variable ahor a es accesible p ar a todo el cdigo incluido en la clase, no slo en la funcin Main (). CU asigna valores por defecto a variables de nivel de clase y el compi lador de CU le permite t r ab a ja r con la variable MyVariable sin as i g narle un valor inicial. La tabla 3.2. enumera los valores que se asignan por defecto a las variables de clase.

80

Tabla 3.2. Valores por defecto de las variables

T ip o d e v a r ia b le

V a lo r p o r d e fe c to

sbyt e b y te s h o rt u s h o rt in t u in t lo n g u lo n g ch a r flo a t doub 1 e de cim a 1 bool

0 0 0 0 0 0 0 0 carcter Unicode con valor 0 0.0 0.0 0.0 false

Asignacin de valores a variables


En algn punto de su cdigo, quer r darle a sus variables un valor. Asi gnar un valor a una variable es sencillo: se escribe el nombre de la variable, el smbolo i g u a l el valor y se termina la instruccin con un punt o y coma:
MyVariable = 123;

Puede asi gnar un valor a la variable cuando declara la variable:


int MyVariable = 123;

Apre nder otros medios de as ignar valores a las variables en las secciones posteriores.

Uso de matrices de variables


Las matrices simplemente son bytes de memori a contiguos que al macenan datos a los que se accede us ando un ndice que est en la matriz. En esta seccin se analizan las matrices unidimensionales, mul tidimensionales y escalonadas.

81

Declaracin de matrices unidimensionales


Sup on ga que est escribiendo una aplicacin de C# par a que los profesores introduzcan las calificaciones de los exmenes p a r a cada uno de los estudiantes de su clase y quiere declarar variables que almacenen la punt uaci n del examen de cada alumno. Como la calificacin del examen esta entre 0 y 100 puede u sar tipos byte. Si su p rog rama admite 25 estudiantes en una clase, su primer pensamiento puede ser declarar 25 variables por separado:
Byte
Byte

T estScoreForStudentl;
TestScoreForStudent2;

Byte TestScoreForStudentB; / / ... ma s ...


b yt e T e s t S c o re Fo rS t .u d e n 1 2 5 ;

Esto requerir mucho tiempo y su cdigo sera difcil de leer y mant ener con todas esas variables. Lo que necesita es un modo de decir. "Quiero tener una coleccin de 25 variables". Es decir, lo que queremos es una matriz. Una matriz es una coleccion de variables, cada una de las cuales tiene el mismo tipo de variable. Las matrices tienen un tamao, que especifica cuantos elementos pueden contener. La declaracin de una matriz es algo asi:
byte [] TestScoresForStudents;

La declaracin byte especifica que todos los elementos de la matriz son valores de tipo byte. Mediante los corchetes se indica al compi lador de C U que quiere c rear una variable de matriz, en vez de una sola variable, y el identificador TestScoresForStudents es el nombre de la matriz. El elemento que falta en esta declaracin es el t amao de la matriz. Cuant os elementos puede contener esta m a t r i z > El t amao de la matriz se especifica m e diante el oper ador de CU new. Este operador indica al compilador de CU que quiere reservar suficiente memoria par a una nueva variable; en este caso, una matriz de 25 variables byte:
byte [ ] TestScoresForStudents;
= new byte[25];

TestScoresForStudents

La pal abra clave byte indica al compi lador que quiere crear una nueva m a triz de variables byte. y [25] indica que quiere reservar suficiente espacio para 25 variables byte. Cad a variable de la matriz se denomina elem ento de la matriz, y la matriz que ac a ba de crear contiene 25 elementos. Debe acordar se de especificar el tipo de matriz cuando use la pal abr a clave new. aunque ya haya especificado el tipo de la matriz cuando la declar. Si olv ida hacerlo, obt endr un mensaje de error del compilador. El cdigo:

82

byte [ ] TestScoresForStudents ; TestScoresForStudents = new [25];

hace que el compi lador de C# emita el error:


error CS1031: Se esperaba un tipo

Este error aparece porque el cdigo no tiene un tipo de variable entre la nueva pal abr a clave y el t amao de la matriz. Tambi n debe recordar u s ar el mismo tipo que us cuando declar la matriz. Si usa un tipo diferente, obtendr otro mensaje de error, como demuest ra el si guiente cdigo:
byte [ ] TestScoresForStudents; = new long[25];

TestScoresForStudents

Este cdigo hace que el compi lador de C# emita el error:


error CS0029: No se puede 'l o n g [ ] ' a 'byte[ ]' convertir implcitamente el tipo

El error se produce porque el tipo de la instruccin (byte) no concuerda con el tipo usado en la nueva instruccin (long). Las matrices como sta se llaman matrices u n id im e n sio n a le s . Las matrices unidimensionales tienen un factor que determina su tamao. En este caso, el nico factor que determina el t amao de la matriz es el numero de estudiantes de la clase. El valor inicial de los elementos de la matriz queda det erminado por los v a l o res por defecto del tipo de matriz. C ad a elemento de la matriz se imcializa con un valor por defecto de acuerdo con la t abla 3.2. C omo esta matriz contiene elemen tos de tipo byte. ca da elemento de la matriz tiene un valor por defecto de 0.

Cmo trabajar con los valores de las matrices unidimensionales


A cab a de crear una matriz con 25 elementos de tipo byte. C ad a elemento de la matriz tiene un nmero. El primer elemento de la matriz ocu pa el ndice cero, y el ltimo elemento de la mat ri z es uno menos que el nmero de elementos de la matriz (en este caso, el ltimo elemento es el elemento 24). Las matrices de C# se llaman matrices de hase cero porque los nmeros de sus elementos empiezan en el cero. T r a b aj a r con un elemento individual de la matriz es sencillo. Para obtener un valor de la matriz, acceda a l con el nombre de la variable y el numero de la v ariable entre corchetes, como se mues tra en el siguiente cdigo.
byte FirstTestScore ; = TestScoresForStudents [0] ;

FirstTestScore

83

E s t e e o d i g o a c c e d e al p r i m e r e l e m e n t o de la m a t r i z T e s t s c o res ForStudents y asigna su valor a la primera variable FirstTestScore var i a b l e . Para poner un valor en la matriz, simplemente acceda al elemento usando la misma sintaxis, pero coloque el nombre de la matriz y el nmero del elemento a la izquierda del signo igual:
TestScoresForStudents [5 j = 100;

Este codigo al mac en a el valor 1 0 0 en el de'cimo elemento de la mat ri z

TestScoresForStudents. C'# no permite acceder a un elemento que no se


encuentre en la matriz. Como la matriz que ha definido contiene 25 elementos, los nmeros de los elementos posibles van de 0 a 24. inclusive. Si usa un numero de elemento inferior a 0 o mayor que 24. obt endr un mensaje de tiempo de ej ecu cin. como se mues tra en el siguiente cdigo:
TestScoresForStudents [1000] 12 3;

Este cdigo se compila sin errores, pero al ejecutar la aplicacin se produce un error porque no hay un elemento 1000 en su matriz de 25 elementos. Cua nd o se llega a esta instruccin, el Entorno de ejecucin comn (C'LR) detiene el p r o g r a ma e inicia un mensaje de excepcin:
Exoeption occur re d: System.IndexOutOfRangeException : An except ion of type S y s t e m .IndexOutOfRangeException was thrown.

IndezOutOf B.angeEzception indica que la aplicacin intent acceder a un elemento con un numero de elemento que no tiene sentido para la matriz.

Inicializacin de valores de elementos de matriz


S u pon gamo s que quiere crear una matriz de cinco nmeros enteros v que el valor de cada elemento sea distinto del que nos ofrecen por defecto. Puede escribir instrucciones individuales para inicializar los valores de la matriz:
mt f] MyAr r a y ; [5] ;

MyArray - new m t M y A r r a y [0] ^ Q; M y A r r a y [1] - 1 ; M y A r r a y [2] = 2; M y A r r a y [ 3] ^ 3; M y A r r a y [4] - 4;

Si al escribir el codigo ya conoce los valores con los que quiere inicializar la matriz, puede especificar los valores en una lista sep arad a por comas y encerrada entre llaves. La lista se coloca en la mi sma lnea que la declaracin de matriz. Puede poner todo el codigo anterior en una sola lnea escribiendo lo siguiente:
mt [ M yA r r a y = ( 0 , 1 , 2 , 3, 4} ;

84

Usando esta sintaxis, no especifica el nuevo operador o el t amao de la matriz. El compilador de C# examina su lista de valores y calcula el tamao de la matriz.

Declaracin de matrices multidimensionales


Puede pensar en una matriz unidimensional como en una lnea. Se extiende en una direccin. Puede i maginarse una mat ri z multidimensional con dos di mens io nes como un trozo de papel de grfica. Sus dimensiones no slo se extienden hacia fuera, sino tambin hacia abajo. Esta seccin estudia los tipos ms comunes de matriz.

Uso de matrices rectangulares


Co nt in ua mo s con el ejemplo de las calificaciones de los exmenes. La matriz unidimensional definida en la seccin previa contena un conjunto de cali ficaci o nes de 25 estudiantes. Ca da estudiante dispone de un elemento en la matriz para al macenar una calificacin. Pero, que ocurre si quiere al macenar varias califica ciones p ar a varios estudiantes? Ahora tiene una matriz con dos factores que a f ec tan a su tamao: el nmero de estudiantes y el nmero de exmenes. S uponga que sus 25 estudiantes harn 10 exmenes a lo largo del curso. Eso significa que el profesor tiene que corregir 250 exmenes por curso. Puede declarar una matriz unidimensional p ar a que contenga las 250 calificaciones:
byte [ ] TestScores ForStudents ; = new b y t e [250];

TestScoresForStudents

Pero esto podra resultar confuso. Cmo se usa esta m at r i z ,} Aparecen pri mero las puntuaciones de un solo estudiante o colocamos en pri mer lugar las calificaciones del primer es tud iant e9 Un modo mejor de declarar una matriz consiste en especificar cada dimensin por separado. Decl arar una matriz multidimensional es tan sencillo como colocar c omas entre los corchetes. Coloque una coma menos que el nmero de d imen si o nes necesarias par a su matriz multidimensional, como en la siguiente declaracin:
byte [,] TestScoresForStudents;

Esta declaracin define una matriz multidimensional de dos dimensiones. Usando el o per ado r new p ar a crear una nueva matriz de este tipo es tan senci llo como especificar las dimensiones individualmente, sep arad as por comas, en los corchetes, como se m ues tra en el siguiente cdigo:
byte [,] TestScoresForStudents; = new byte [10, 25];

TestScoresForStudents

Este cdigo indica al compi lador de C# que quiere crear una matriz con una dimensin de 10 y otra dimensin de 25. Puede i maginar una matriz de dos di

85

mensiones como una hoja de calculo de Microsoft Excel con 10 filas v 25 c ol u m nas. La tabla 3.3 recoge el aspecto que podria tener esta matriz si sus datos estuvieran en una tabla.
Tabla 3.3. Representacin en una tabla de una matriz de dos dimensiones

E xam en

E stu d ia n te 1

E stu d ia n te 2

E s t u d ia n t e 3 ...

E stu d ia n te 25

Examen 1 Examen 2

90 95

80 85

85 90

75 80

Examen 10

100

100

100

100

Para acceder a los elementos de una matriz de dos dimensiones, use las mismas reglas par a n umera r elementos que en las matrices unidimensionales. (Los n m e ros de elemento van de 0 a uno menos que la dimensin de la matriz.) Tambi n se usa la mi sma sintaxis de coma que uso con el oper ador new. Escribir cdigo para al ma c en ar una calificacin de 75 par a el primer examen del alumno 25 seria algo asi:
Test Scor es Fo r Stud e n t s |0, 24] - 75 ;

Leer la calificacin del quinto examen del alumno 16 sera algo as:
byt.e Fit thScoreForStudent 1 ;

Fi f thScoreForStudenti

Tes tScoresFo rS t u d e n t s [4,

15];

En otras palabras, cuando trabaje con una matriz de dos dimensiones v c ons i dere la matriz como una tabla, considere la primera dimension como el numero de fila de la tabla y el segundo numero como el numero de columna. Puede micializar los elementos de una matriz multidimensional cuando declare la variable de matriz. Para ello, coloque cada conjunto de v alores para una sola dimension en una lista delimitada por comas rodeada por llaves:
mt [, ] MyAr r ay - { {0 , 1, 2 } , {3 , 4 , 5 } } ;

Esta instruccin declara una matriz de dos dimensiones con dos filas v tres columnas. Los valores enteros 0. 1 y 2 estn en la primera fila, v los valores 3. 4 y 5 estn en la segunda fila. Las matrices de dos dimensiones con esta es tructur a se llaman matrices r ec tangulares. Estas matrices tienen la forma de una tabla: cada fila de la tabla tiene el mismo numero de columnas. C# permite definir matrices con mas de dos dimensiones. Para ello basta con utilizar mas comas en la declaracin de la matriz.

86

Puede definir un a matriz de cuatr o dimensiones con tipo l o n g . por ejemplo, con la siguiente definicin:
long [,,,] ArrayWithFourDimensions;

Asegrese de definir todas las dimensiones cuando use el o pe r ad or new:


ArrayWithFourDimensions = new long [5, 10, 15, 2 0];

E1 acceso a los elementos de la mat ri z se realiza de la mi sma manera. No olvide especi fi car todos los elementos de la matriz:
A r r a y Wi th Fo ur Di me ns io ns [0, 0, 0, 0] = 32768436;

Definicin de matrices escalonadas


C # permite definir matrices escalonadas, en las que ca da fila puede tener un nmero diferente de columnas. Vol vamos al ejemplo de las calificaciones de los estudiantes par a explicarlo. S upo ng a tambin que el nmero mx imo de e x m e nes es 10. pero al gunos estudiantes no tienen que hacer los ltimos examenes si obtuvieron buena nota en los anteriores. Puede c rear una matriz rectangular para lo que necesita al macenar, pero puede a c a b a r con elementos que no se utilizan en su matriz rectangular. Si algunos estudiantes no hacen todos los exmenes, tendr elementos en su mat ri z rect angul ar que no se usan. Estos elementos des a pr ov e chados equivalen a memori a desperdiciada, lo que pretendemos evitar. Una estrategia mejor consiste en definir una matriz en la que cada elemento de la matriz sea. en s mismo, una matriz. La figura 3.1 ejemplifica este concepto. Mues tra al estudiante 1 con espacio p ar a tres calificaciones, al estudiante 2 con espacio p ar a cinco calificaciones, al estudiante 3 con espacio p ar a dos califica ciones y al estudiante 25 con espacio p ar a las diez calificaciones (los otros es tu diantes no aparecen en la figura).

C a lific a c i n 1 C a lific a c i n 1 C a lific a c i n 1

C a lific a c i n 2 C a lific a c i n 2 C a lific a c i n 2

C a lific a c i n 3 C a lific a c i n 3 C a lific a c i n 4 C a lific a c i n 5

E s t u d ia n t e 25

C a lific a c i n 1

C a lific a c i n 2

C a lific a c i n 3

C a lific a c i n 4

C a lific a c i n 5

C a lific a c i n 6

C a lific a c i n 7

C a lific a c i n 8

C a lific a c i n 9

C a lific a c i n 10

Figura 3.1. Las matrices escalonadas permiten definir una matriz que contiene otras matrices, cada una con un nmero diferente de elementos.

Estas matrices escal onadas tienen dos dimensiones, como las matrices rec tangulares, pero cada fila puede tener un nmero de elementos diferente (lo que da a las matrices su aspecto escalonado).

87

Las matrices escal onadas se definen utilizando dos grupos de corchetes i nme diatamente despus del nombre del tipo de matriz. C uan do hace una llamada a new. se especifica un t amao para la pri mera dimensin (la matriz student en nuestro ejemplo), pero no la segunda. Tras definir la pri mera matriz, haga una nueva llamada a new par a definir las otras matrices (las matrices score en nuestro ejemplo):
byte [ ][ ] ArraysOfTestScores ;

ArraysOfTestScores = new byte [25][]; ArraysOfTestScores [0 ] = new b y t e [3]; Ar ra y s O f T e s t S c o r e s [1] = new b y t e [5]; ArraysOfTestScores [2] = new byte [2]; Ar ra y s O f T e s t S c o r e s [24] = new b y t e [10];

Una vez que ha construido la matriz escalonada, puede acceder a sus el emen tos de la mi sma forma que en una matriz rectangular.

Tipos de valor y de referencia


Recuerde que debe usar la p al abr a clave new par a crear la matriz. Este requi sito es distinto de los tipos que hemos visto hast a ahora. Cu an do t rabaje con codigo que use variables int o long. por ejemplo, puede usar la variable sin usar new:
int IntegerVariab1e ; = 12345;

IntegerVariable

Por qu son tan diferentes las m a t ri c e s9 Por qu se necesita utilizar new al crear una m a t r i z 9 La respuesta est en la diferencia entre tipos de valor y tipos de referencia. Con un tipo de valor, la v ariable retiene el valor de la variable. Con un tipo de referencia, la v ariable retiene una referencia al valor al macenado en algn otro sitio de la memoria. Puede imaginar una referencia como una v ariable que apunt a hacia otra parte de memoria. La figura 3.2 muest ra la diferencia.
int IntegerVariable

123
long LongVariable

456
double [] ArrayOfDoubles 0.0 0.0 0.0 0.0 0.0

Figura 3.2. Los tipos de valor contienen datos. Los tipos de referencia contienen referencias a datos situados en algn otro lugar de la memoria.

88

Ca d a uno de los tipos comentados has ta este punto es un tipo de valor. Las variables p ropor ci onan suficiente capaci dad de a lmacenami ent o p a ra los valores que pueden contener y no necesita new para crear un espacio par a sus var ia bles. Las matrices son tipos de valor y los objetos son tipos de referencia. Sus valores estn en algn otro lugar de la memori a y no necesita usar la pal abr a clave new par a crear suficiente espacio par a sus datos. Aunque necesita us ar la pal ab ra clave new p ar a crear espacio de memoria p a r a un tipo de referencia, no necesita escribir ningn cdigo que borre la m em o ria cuando haya ac ab ad o de usar la variable. El C L R contiene un mecanismo l lamado recolector de elem entos no utilizados que realiza la tarea de liberar la memori a que no se usa. El C L R ejecuta el recolector de elementos no utilizados mientras se ejecuta su aplicacin de C#. El recolector de elementos no utilizados registra su p rog ram a buscando memori a no us ada por ni nguna de sus variables. Li berar la memori a que ya no se usa es tarea del recolector de elementos no utilizados.

Cmo convertir tipos de variable


Puede t opar con una situacin en la que tenga una variable de un tipo, pero necesite t raba jar con un fragmento de cdigo que necesite otro tipo. Si. por ej em plo. est t rabaj ando con una variable de tipo int y necesita p as ar el valor a una funcin que requiere el uso de una variable de tipo long. entonces necesita realizar una conversin de la variable int en variable long. C# admite dos tipos de conversiones: conversiones implcitas y conversiones explcitas. Las siguientes secciones describen cada uno de estos tipos de co nv er siones.

Conversiones implcitas
El compi lador de C# realiza a ut omt icame nte las conversiones implcitas. Exami ne el siguiente cdigo:
int In te g e r V a r i a b l e ; long LongVariable; IntegerVariable = 123; LongVariable = I n t e g e r V a n a b l e ;

En este cdigo, a una variable de tipo entero se le asigna el valor 123 y a una variable long se le asi gna el valor de la variable de tipo entero. C uando se ejecute este cdigo, el val or de LongVariable es 123. El compi lador de CU convierte el valor de la v ariable de tipo entero a un v alor long porque la conversin de un valor int a un valor long es una de las conversiones implcitas permitidas por C#. La tabl a 3.4 recoge las conversiones

89

implcitas permitidas por C#. La pri mera col umna enumera el tipo original de la variable y la fila superior enumer a los tipos de datos a los que puede convertirlo. Una X en la celdilla significa que puede convertir implcitamente el tipo de la izquierda al tipo en la parte superior.
Tabla 3.4. C onversiones implcitas de tipo de valor

s byte
X
-

byte s h o rt u sh o rt in t
-

u in t
-

long
X X X X X X X X
-

c h a r flo a t ulo ng
-

decim al dou ble


X X X X X X X X
X
-

X x X
-

X X X X X

X X X X X X X X X X

X
-

X x
-

X
-

X X
-

X X X X X X X X

X
-

1
!

X
-

X
-

X
-

x -

X
-

X X

NOTA: No puede convertir ningn tipo a un tipo char (excepto mediante la variable char, lo que en realidad no es una conversin). Adems, no puede hacer conversiones entre los tipos f loating-point y los tipos decimales.

Conversiones explcitas
Si escribe cdigo que intente conv ertir un valor que use tipos no admitidos por una conversin implcita, el compi lador de C# genera un error, como mues tra el siguiente cdigo:
char CharacterVariable; mt IntegerVanable; IntegerVariable = 5; CharacterVariable = IntegerVariable;

El compi lador de CU produce el siguiente error:


error CS0029: No se puede 'in t ' a 'char' convertir implcitamente el tipo

90

Este error se produce porque ni nguna conversin implcita admite la conve r sin de una variable i n t a una variable c h a r variable. Si realmente necesita hacer esta conversin, tiene que realizar una conversin explcita. Las conversiones explcitas se escriben en su cdigo fuente y le dicen al compi lador "haz que se p ro d uz c a esta conversin, aunque no puede ser realizada implcitamente". Escribir una conversin explcita en el codigo CU requiere colo car el tipo al que est convirtiendo entre parntesis. Los parntesis se colocan j u st o antes de la variable que est usando c omo fuente de la conversin. A conti nuacin se incluye el cdigo anterior pero usando una conv ersin explcita:
char int CharacterVanable; IntegerVariable;

IntegerVariable = 9; CharacterVariable = (char)IntegerVariable;

Esta tcnica es conocida como conversin de la variable de tipo entero a una variable de tipo carcter. Algunos tipos no pueden ser convertidos, ni siquiera mediante una operacin de conversin explcita. La tabla 3.5 enumera las conver siones explcitas que admite CU. La p ri mera col umna e numer a el tipo original de la variable y la fila superior enumera los tipos de datos a los que puede convert ir lo. Una X en la celdilla significa que puede convertir explcitamente el tipo de la i zquierda al tipo de la parte superior usando la operacin de conversin explcita.
Tabla 3.5. Conversio nes explcitas de tipo de valor

s b y te
X

b y te s h o rt u s h o r t i n t u in t lo n g
X X X X X X X X X X X X
-

c h a r f l o a t u lo n g d e c im a l d o u b le
X X X X X X X X X X X X
-

X X X X X X
-

X X X X
-

X X
-

X X
-

t .

X X X X

X X X X X X X X X X

X X X X
-

X X X X X

: : i ' :

X X X X X

X X X X

X X X X

X X X X

X X X

X X X X

X X X

X X

I I..

X , ! X

T amb in puede realizar conversiones explcitas sobre tipos de valor conv ir tiendo explcitamente el valor al tipo apropiado, como se mu es tra en el siguiente

91

ejemplo. C# permite u sar un oper ador de conversin explcita incluso con co n versiones implcitas, si lo desea:
int integerVariable; long o n g V a r i a b l e ; IntegerVariable - 12 3; L o n g V a n a b l e = (long) IntegerVariable;

Esta sintaxis no es necesaria, porque C# permite conversiones implcitas de variables i n t a variables l o n g . pero puede escribirlo si quiere.

Cmo trabajar con cadenas


C# admite un tipo de referencia llamado s t r i n g . El tipo de dato s t r i n g representa una cadena de caracteres Unicode.

N O T A : Unicode es un estndar mundial de codificacin de caracteres. Los caracteres Unicode tienen 16 bits, con lo que admiten 65.536 caracteres posibles. Los caracteres ANSII tienen 8 bits, y aceptan hasta 256 caracte res posibles.

Use el siguiente cdigo para cr ear e inicializar una cadena en C#:


string MyStnng; = "Helio f rom C# !" ;

MyStrmg

Al igual que con el resto de las variables, puede inicializar una cadena en la mi sma linea que su declaracin:
string MyString = "Helio from C#!";

Uso de caracteres especiales en cadenas


C# permite usar una sintaxis especial para insertar caracteres especiales en su cadena. Estos caracteres especiales aparecen en la tabla 3.6.
Tabla 3.6. C a r a c t e r e s e s p e c i a l e s d e C #

C a ra cteres

F u n c i n

\t

Los caracteres especiales \t incrustan una tabulacin en la cadena. Una cadena definida como h e i i o \ t t h e r e

92

C a ra cteres

F u n c i n

se almacena en memoria con un carcter de tabulacin entre las palabras helio y there.
\r

Los caracteres especiales \r incrustan un retorno de carro en la cadena. Una cadena definida como hello\ rthere se almacena en memoria con un retorno de carro entre las palabras helio y there. El carcter retorno de carro devuel ve el cursor al principio de la lnea, pero no mueve el cursor una lnea por debajo. Los caracteres especiales \v insertan una tabulacin ver tical en la cadena. Una cadena definida como helio\ v t h e r e se almacena en memoria con un carcter de tabulacin vertical entre las palabras helio y there. Los caracteres especiales \ f insertan un carcter de im presin de pgina en la cadena. Una cadena definida como h e i i o \ f t h e r e se almacena en memoria con un carcter de impresin de pgina entre las palabras helio y there. Las impresoras suelen interpretar un carcter de impresin de pgina como una seal para pasar a una nueva pgina. Los caracteres especiales \n insertan una nueva lnea en la cadena. Una cadena definida como h e l l o \ n t h e r e se almacena en memoria con un carcter de nueva lnea entre las palabras h e lio y th e re . La comunidad de desabolladores de software ha debatido durante mucho tiempo la interpretacin del carcter de nueva lnea. Siem pre ha significado, "mueve la posicin de la siguiente sali da una lnea ms abajo". La duda est en si la operacin tambin incluye mover la siguiente posicin al primer ca rcter de la lnea anterior. .NET Framework interpreta el carcter de nueva lnea como bajarlo una lnea y devolver la posicin del siguiente carcter al principio de la siguiente lnea. Si no est seguro, siempre puede escribir los carac teres especiales \n y \ r juntos. Los caracteres especiales \x permiten especificar un ca rcter ASCII usando dos dgitos hexadecimales. Los dos dgitos hexadecimales deben seguir inmediatamente a los caracteres \x y deben corresponder con el valor hexadecimal del carcter ASCII que quiere producir. Por ejemplo, el carcter espacio en ASCII tiene el cdigo de decimal 32 . El valor decimal 32 es equivalente al valor hexadecimal 20. Por tanto, una cadena definida como h e l l o \ x 2 0 there se almacena en memoria con un ca rcter de espacio entre las palabras helio y there.

\v

\f

\n

93

C a ra cteres

F u n c i n

\u

Los caracteres especiales \u permiten especificar un ca rcter Unicode usando exactamente cuatro dgitos hexadecimales. Los cuatro dgitos hexadecimales deben colocarse inmediatamente despus de los caracteres \u y deben corresponder al valor hexadecimal del carcter Unicode que quiere producir. Por ejemplo, el carcter espacio en Unicode tiene un cdigo de decimal 32. El valor decimal 32 es equivalente al valor hexadecimal 20. Portanto, una cadena definida c o m o h e l l o \ u 0 o 2 0 there se alma cena en memoria con un carcter de espacio entre las pa labras helio y there. Asegrese de usar exactamente cuatro dgitos despus de los caracteres \u. Si el valor es menor de cuatro dgitos, use ceros para rellenar su valor hasta que llegue a los cuatro dgitos. Los caracteres especiales \\ permiten especificar un ca rcter de barra invertida en la posicin actual. Una cade na definida como h e l l o W t h e r e se almacena en memoria con un carcter barra invertida entre las palabras helio y there. La razn por la que debe haber dos barras invertidas es simple: el uso de una sola barra invertida podra hacer que el compilador de C# la confundiera con el principio de otro carcter especial. Por ejemplo, suponga que olvida la segunda barra invertida y escribe h e i i o \ t h e r e en su cdigo. El compilador de C# ver la barra invertida y la t en la palabra there y los confundir con un carcter de tabulacin. Esta cadena se almacenara en memoria con un carcter de tabulacin entre las palabras helio y there. (Recuerde que la T en there se interpretara como un ca rcter de tabulacin y no sera parte de la palabra real.)

\\

Desactivacin de los caracteres especiales en cadenas


Puede o rdenar al compi lador de C# que ignore los caracteres especiales en una cadena ant eponi endo el signo @a la cadena:
string MyString = @ "he 11 o\there " ;

Este cdigo asigna a la variable MyString el valor del texto hello\there. Como la cadena tiene delante el signo se desactiva el modo habitual de inter pretar los caracteres \t como m ar cad or de tabulacin. Esta sintaxis tambin permite escribir nombres de directorio en cadenas de nombre de archivo de C# sin

94

u sar la doble b ar ra invertida. Por defecto, siempre necesitar usar las dobles bar ras invertidas:
string MyFilename = "C :W F o l d e r 1 W F o l d e r 2 W F o l d e r 3\\f i le .txt " ;

Sin embargo, con el prefijo @ , puede conseguirlo con una sola ba r ra invertida.
string MyFilename = 0"C :\Folder1\Folder2 \Folder3\ f i le .tx t ";

Cmo acceder a caracteres individuales en la cadena


Puede acceder a caracteres en la cadena como si la cadena fuese una matriz. Concept ualment e, puede imaginarse una cadena como una matriz de caracteres. Puede us ar la sintaxis de elemento de matriz entre corchetes p ar a acceder a c ua l quier carcter de la cadena:
char MyCharacter; string MyString = "Helio MyCharacter from C#!";

= MyString[9];

Este cdigo coloca el valor ' m ' en la variable MyCharacter. El carcter m ' est en el elemento 9 de la cadena, si imagina la cadena como una matriz de caracteres. Adems, t enga en cuenta que esta matriz de caracteres es de base cero. El primer ca rc te r de la cadena se encuent ra en realidad en el elemento 0. El dcimo carcter de esta cadena, como ha aprendido, est localizado en el elemen to 9.

Declaracin de enumeraciones
A diferencia de las variables trat adas hast a el momento, una enumeracin no es un tipo en s misma, sino una for ma especial de tipo de valor. Una enumeracin se deriva de S y s t e m .Enum y proporci ona nombres par a valores. El tipo s u b y a cente que representa una enumeraci n debe ser byte. short. int o long. C ad a campo de u na enumeracin es esttico y representa una constante. Para declarar una enumeracin, debe usar la pal abr a clave enum seguida del nombre de la enumeracin. A continuacin debe escribir una llave de ape rt ura seguida por una lista de las cadenas de la enumeracin y finalizar con una llave de cierre, como se m ues t ra en el siguiente ejemplo:
public enum Pizza

{
Supreme, MeatLovers, CheeseLovers,

95

Vegetable,

} Este cdigo crea una enumeracin llamada Pizza. La enumeraci n pizza contiene cuatro pares diferentes nombre/ valor que describen diferentes tipos de pizza, pero no se definen valores. C uand o declara una enumeracin, el primer nombre que declara t oma el valor 1 y as sucesivamente. Puede invalidar esta funcionalidad asi gnando un valor a cada nombre, como se muest ra a c ont i nua cin:
public enum Pizza

{
S up r eme = 2,
MeatLovers3,

CheeseLovers = 4 , Vegetable - 5,

) El valor de cada campo de enumeracin ha sido i ncrementado en 1. Aunque no todo este codigo es necesario. As ignando a Supreme un valor de 2. los si guien tes ca mpos siguen la secuencia. Por tanto, puede eliminar las asignaciones a MeatLovers. CheeseLovers. y Vegetable. Se puede hacer referencia a los enumeradores de una de estas dos formas. Puede p ro g ra ma r sobre sus nombres de campo o puede p ro g ra ma r sobre sus v alores. Por ejemplo, puede asi gnar el nombre de ca mp o a una v ariable de c ade na con el siguiente cdigo:
string MyString - Pizza. Supreme;

Quizas quiera hacer referencia al valor de un campo. Puede conseguirlo m e diante la conversin de tipos. Por ejemplo, puede recuper ar el valor del campo Supreme con el siguiente cdigo:
Int. Mylnteger = (int )Pi z z a .Supreme ;

Resumen
Este capitulo examina las v ariables y sus tipos. Hay muchas clases de tipos de valor y cada uno tiene sus propias caractersticas y requisitos de memoria. Al g u nos tipos pueden ser convertidos implcitamente a otros tipos, pero otros deben ser convertidos explcitamente usando la sintaxis apropiada. Las matrices contienen colecciones de variables del mismo tipo. Son tiles cuando se necesita mant ener un conjunto de variables del mismo tipo. C# admite matrices unidimensionales y multidimensionalcs. Las matrices de C# son de base cero: es decir, el nmero del primer elemento de una matriz es el 0. Las cadenas le ayudan a t rabaj ar con partes de texto en su cdigo. Son conjuntos de caracteres

96

Unicode. C# permite i ncrust ar caracteres especiales en sus cadenas, pero p r o porciona el prefijo @ p a r a especificar los casos en los que no necesite que se procesen los caracteres especiales. Se puede acceder a los caracteres de una cadena como si fueran matrices de caracteres.

97

Expresiones

Las expresiones son el elemento bs ico y fundament al de cualqui er lenguaje de p rogr amaci n. Medi ant e el uso de operadores, las expresiones permiten que una operacin realice compar aci one s simples, asignaciones e incluso op er a ci o nes muy complejas que necesitaran millones de aos p a r a completarse. Este captulo t rata del uso de los operadores p ar a realizar funciones m a t e m ticas. asi gnar valores a variables y realizar comparaciones. Una vez que h a y a mos comprendi do estos elementos bsicos, est udi aremos al gunas expresiones a va nzad as que usan operadores muy especficos del lenguaje C # y que le brindan u na ventaja sobre la mayo r a de los dems lenguajes de programaci n. Para ce rrar este captulo, revisaremos las expresiones que usan operadores p ar a m an i p ul ar la parte ms pequeas de un byte. el bit.

Cmo usar los operadores


Las expr es iones puede n escri bir se u s a n do variabl es: val ores codificados especficamente, llamados valores literales (explicados en la seccin "Cmo usar literales", posteriormente en este mi smo captulo): y smbolos llamados opera d o res. C# admite varios operadores, cada uno de los cuales realiza una accin diferente. Las variables o los valores literales que aparecen en una expresin se

99

llaman opremelos. Los operadores se aplican a los operandos y el resultado de la operacin es otro valor. C# consta tres tipos de operadores: O p erad o res unarios. trabajan con un solo operando. Una expresin con un oper ando y un oper ador produce un solo valor. O perad ores binarios, t rabaj an con dos operandos. Una expresin con dos operandos y un o per ador produce un solo valor. O p erad o res ternarios, trabajan con tres operandos. C # admite slo un o per ando ternario.

Uso de expresiones primarias


Las expresiones pri mari as son la base del cdigo C#. C# define varios tipos diferentes de expresiones primarias: Literales Identificadores Expresiones con parntesis Acceso a mi embros Expresiones de invocacin Acceso a elementos La pal abr a clave this Acceso a bases Op erado re s de incremento y decremento postfijo El oper ador new El operador typeof Los operadores checked y unchecked

Las expresiones pri mari as permiten definir el orden de las operaciones dentro de una expresin, definir nuevos literales (por ejemplo, valores codificados especficamente) y declarar nuevas variables p ar a la aplicacin. En las siguientes secciones se e xa mi na rn estas expresiones y cmo usarlas.

Cmo usar los literales


Los literales son valores codificados es pecficamente que se pueden escribir di rectamente en el cdigo fuente C#. Ha y muchos tipos de literales diferentes.

100

Para mos trar lo que es un literal, examine la siguiente lnea de cdigo en C# que us a el valor literal Brian.
if (FirstName == "Brian")

Aqu se ha codificado el valor de Brian p ar a usarlo en una comparacin. En lugar de un valor definido por el usuario, es preferible al mac enar las cadenas en variables de modo que. si hiciera falta ca mbi ar los valores, slo habra que c a m biarlos en un sitio sin necesidad de bu s ca r cada una de sus ocurrencias en todas las lneas de cdigo. El siguiente cdigo mues tr a el mejor mtodo p a r a al mac enar y u s a r una c ad e na con vistas a compararla:
string MyFirstName = "Brian; if (FirstName == MyFirstName)

Como puede ver, ste es un enfoque mucho ms claro p a r a u sar un valor literal.

Literales booleanos
C# define dos valores literales booleanos, las pal ab ras clave True y False:
bool MyTrueVariable = true; bool MyFalseVariable = false;

Ambos valores tienen un tipo de valor bool. La pal abra clave True es el equivalente entero de uno negativo (-1). mientras que el equivalente de False es el cero.

Cmo usar los literales enteros en notaciones decimales y hexadecimales


Se pueden escribir literales enteros us ando una notacin decimal o una n o t a cin hexadecimal. De for ma par eci da a los literales vistos anteriormente, estos literales permiten ordenar el cdigo. Los valores literales pueden ser colocados en la parte superior del listado del cdigo. Si result ara necesario modificar estos en al guna ocasin, resultara muy sencillo c a mb i ar la ocurrencia del valor. Los literales decimales integrales se escriben como series de uno o ms n m e ros usando los caracteres 0, 1. 2. 3. 4. 5, 6. 7, 8 y 9:
int MyVariable = 125;

Los literales decimales tambin pueden contener un sufijo de un ca rc te r que especifique el tipo del literal. Si el literal tiene como sufijo una U may s cul a o minscula, el literal decimal se considera de tipo sin signo:
uint MyVariable = 125U;

101

El t ermi no sin signo significa que no se especifica si el nmero es positivo o negativo. Por tanto, si convierte un valor de 100 negativo (-100) a un valor sin signo, su resultado sera simplemente cien (100). Si el valor es lo suficientemente pequeo como p a r a poder ser almac en ado en un tipo uint. el compi lador de C# consi derar el literal como de tipo uint. Si el valor del literal integral es demasiado grande p ar a un tipo uint, el compi lador de C # consi der ar el literal como de tipo ulong. Los diferentes tipos representan el t am a o de la informacin que est al macenando. El tipo uint puede contener un nmero comprendido entre 0 y 4 . 294 .9 67. 29 5; mientras que el valor ulong puede contener un valor entre 0 y 8. 446 .74 4. 073 .70 9. 55 1.615. Si el literal tiene como sufijo una L m ay s cul a o minscula, el literal decimal se consi dera de tipo long:
long MyVariable = 125L;

Si el valor est dentro del rango de tipo long. el compi lador de C# con si der a r el literal como de tipo long. Si el valor no est dentro del rango de tipo long. el c ompi lador de C # cons ider ar el literal como de tipo ulong.

JNOTAf

el compilador de C# acepta tanto la 1 minscula como la

L mayscula como sufijos, probablemente preera usar la L mayscula. La 1 minscula se parece demasiado al nmero 1 y si otros programadores leen el cdigo, podran confundir la 1 con el 1.
Si el literal tiene como sufijos L y U. el literal decimal se considera de tipo

long sin signo:


ulong MyVariable = 125LU;

El compi lador de C# acept a tanto un sufijo en el que la L aparece delante de la U como un sufijo en el que la U aparece delante de la L. Adems, el compi lador de C# acepta la combinacin de letras en mayscul as y en minsculas. Los sufijos LU. Lu. 1U. lu, UL. Ul. uL y ul denominan al sufijo ulong. Escribir literales integrales en formato hexadecimal permite escribir un literal usando las letras de la A a la F junto a los nmeros del 0 al 9 . Los literales h exadeci mal es deben tener el prefijo 0X o Ox:
int MyVariable = 0x7D; // 7D hex = 125 decimal

Se pueden us ar letras mays cul as y minsculas par a la notacin hexadecimal. Tambi n se pueden us ar como sufijos los mismos caracteres que est aban di sponi bles p ar a los literales decimales:
long MyVariable = 0x7DL;

La decisin de u sar un valor hexadecimal queda compl et ament e a discrecin del p rogr amador. Usar hexadecimales en lugar de otro tipo de literales no supone

102

ni nguna diferencia respecto a u s ar cualquier otro tipo de nmero. No obstante, es aconsejable u s ar valores hexadeci mal es cuando se est const ruyendo una a p l i ca cin que utilice especificaciones en formato hexadecimal. Por ejemplo, una interfaz p ar a el m dem de su ordenador. La referencia del p r o g r a ma do r p a r a su mdem podra especificar los valores de algunas operaciones en formato hexadecimal. En lugar de leer toda la referencia del p r o g r a ma do r y convertir todos los nmeros al s i s t e m a d e c i m a l , n o r m a l m e n t e s lo t e n d r a qu e c o d i f i c a r e s t o s n m e r o s hexadecimales directamente en la aplicacin, evitando as cualqui er error de c on versin.

Cmo usar los literales reales para valores de coma flotante


Los literales reales permiten escribir valores de coma flotante en el cdigo C#. Los literales reales pueden incluir tanto una coma decimal como un exponente. Las comas decimales pueden apa r ec e r en literales reales y los nmeros p u e den ap ar ec er antes y despus de la co ma decimal. Tamb in es posible que un literal real empiece con una coma decimal, lo que es til cua ndo se quiere crear un valor m ayo r de cero, pero menor de uno. Los valores como 2,5 y ,75 son ejemplos de literales reales. C# no impone ningn lmite al nmero de cifras que pueden apa rec er antes o despus de la coma decimal, mientras el valor del literal quede dentro del rango del tipo deseado. T am bi n puede especi fi car un e xp on e n te en sus literales reales. Los exponentes se escriben con una E m ay s cul a o mi nu scu la i nmediatamente despus de la porcin decimal del nmero. Tr as la E se incluye uno o ms nmeros decimales p a r a indicar el valor del exponente. Esto quiere decir que se puede escribir el valor 750 como un literal real de 7 .5e2. Tambi n puede apa r ec e r un signo ms o un signo menos entre la E y el valor del exponente. Un signo ms significa un exponente con valor positivo: un signo menos significa un exponente con valor negativo. El literal real 7 .5e + 2 define un valor de 750 v el literal real 7 .5e-2 define un valor de .075. Si no se usa ninguno de los dos signos, el compi lador de C# consi dera que el valor del e x p o nente es positivo. Al igual que los literales decimales, los literales reales tambin pueden llevar detrs un sufijo p ar a especificar el tipo del literal. Si no se usa un sufijo en el literal real, el compi lador de C# considera que el literal es de tipo double. Si el literal real tiene como sufijo una F may scu la o minscula, se considera que el literal decimal es del tipo f loat:
float MyVariable = 7.5F;

Si el literal real tiene como sufijo una D m ay sc ul a o minscula, se considera que el literal decimal es de tipo double:
double MyVariable = 7.5D;

Si el literal real tiene c omo sufijo una M m ay sc ul a o minscula, se considera que el literal decimal es de tipo decimal:
decimal MyVariable = 7 .5M;

103

Cmo usar los literales de carcter para asignar valores de carcter


Los literales de carcter permiten escribir valores de carcter en el cdigo C#. Normalmente, los literales de ca rcter ap arecen entre comillas simples:
char MyVariable = 'a' ;

T ambi n se pueden usar las secuencias de escape vistas en un captulo a nt e rior par a escribir literales de carcter en cdigo C#. Estos literales de carcter deben encerrarse entre comillas simples:
char MyVariable = '\t'; // caracter tabulador

NOTA: Si quiere utilizar una comilla simple como literal de carcter, de ber anteponerle una barra invertida. Escribir confunde al compilador de C#. Escriba en su lugar *V\
Puede definir valores hexadccimales como literales de carcter us an do la se cuencia de escape \x seguida de uno. dos o tres caracteres hexadccimales:
char MyVariable = '\x5C';

Cmo usar los literales de cadena para incrustar cadenas


Los literales de cadena permiten incrustar cadenas en el cdigo CU. Los litera les de cadena se escriben como se indica en un captulo anterior, poniendo la cadena entre dobles comillas:
stnng MyVariable = "Helio from C#!";

El compi lador de C# reutiliza muchos literales de cadena con los mismos c o n tenidos. con lo que conserva espacio en el ejecutable final, como mu es tra el si guiente cdigo:
stnng stnng Stringl = "Helio" ; S t r in g 2 = "Helio";

C ua nd o se compila este cdigo, el ejecutable contiene u na copia del literal de la cadena Helio. Las dos variables de cadena leen el valor de la nica copia al mac enada en el ejecutable. Esta optimizacin permite al compi lador de C# c on servar el uso de memori a del cdigo, ya que a lmac en ar slo una copia del literal requiere menos memori a que al ma c en ar dos copias del mismo literal.

Cmo usar los literales nuil


El literal nuil es una p al abr a clave de C # que permite poner un objeto en un estado nulo o sin uso:
object MyOb]ect = nuil;

104

Uso de identificadores
Los identificadores C# son ejemplos de expresiones simples. Los identificadores tienen un tipo y el tipo se especifica c uando se declara el identificador:
int MyVariable = 123;

El identificador MyVariable se considera una expresin y tiene un tipo int. Los identificadores pueden ser definidos en c ualqui er bloque de cdigo que se encuentre entre llaves, pero su tipo no puede cambiar:
public static void M a i n ( ) = 123; // "MyVariable" // "MyVariable" todava es un todava es un "int "int"

{
int MyVariable MyVariable MyVariable = 1; = 2;

} Si intenta redefinir el tipo de un identificador dentro del mi smo bloque de cdigo, el c ompi lador de C# gene rar un mensaje de error.
public static void M a m ( )

{
int MyVariable = 123; float MyVariable = 1.25;

} El compilador de C# genera un mensaje de error en la linea que intenta redefinir

MyVariable como un val or float'.


error CS0128: Ya se ha definido una variable 'MyVariable' en este mbito local denominada

Sin embargo, se puede reutilizar el identificador si aparece en un bloque de cdigo separado:


public static void M a i n ( ) = 12 3;

{
int MyVariable

}
public void A n o t h e r F u n c t i o n ( ) = 1.25;

{
float MyVariable

Expresiones entre parntesis


Como su nombre indica, las expresiones entre parntesis son expresiones e n cerradas entre parntesis. El compilador de C# evala la expresin incluida en los

105

parntesis y el valor de la expresin entre parntesis es el resultado de la e v a l ua cin. Por ejemplo, el valor de la expresin entre parntesis (3+2) es 5.

Cmo llamar a mtodos con expresiones de acceso a miembros


Cu an do se necesita l lamar a un mtodo de un objeto, se escribe el nombre del objeto seguido por un punto y p or el nombre del mtodo. C uando el C L R llama al m t o do Ma i n ( ) p ar a empezar a ejecutar la aplicacin, crea un objeto a partir de su clase y llama a la funcin M a i n ( ) de ese objeto. Si se escribiese este cdigo en C# sera algo parecido a lo siguiente:
MyClass MyObject;

MyObject = new MyClass ( ); MyObj e c t .M a i n ( );

Los objetos se estudian con ms detalle en captulos posteriores. Lo ms i m portante a ho ra es darse cuenta de que la instruccin que llama a M a i n ( ) cont ie ne una expresin de acceso a miembros, que contiene un objeto, un punt o y una l lamada de funcin. En captulos posteriores, ver qu objetos pueden tener datos adems de codigo. Puede acceder a los datos usando la mi sma sintaxis de expresin de acceso a miembro.

Cmo llamar a mtodos con expresiones de invocacin


Las expresiones de invocacin se usan par a hacer una llamada a un mtodo en un objeto. El cdigo us ado en el caso del acceso a mi embro tambin mues tra una expresin de invocacin. El cdigo llama a un mtodo (en este caso M a i n ( ) ). que hace que el codigo invoque al mtodo M a i n ( ) del objeto. Si se llama a un mtodo desde otro mtodo en el mi smo objeto, puede us ar el nombre del mtodo en la llamada. No necesita es pecificar un objeto o un nombre de clase v no es necesaria la sintaxis de acceso a miembro, como muest ra el listado 4.1.
Listado 4.1. Expresin de invocacin class MyClass static void M a i n ( )

{
public

{
MyClass myclass = new M y C l a s s ();

106

myc l a s s .D o W o r k ();

}
void DoWork( ) aqui su trabajo

{
// haga

} } En este ejemplo, el mtodo Main () llama a un mtodo DoWork (). Sin embargo, antes hace falta crear una referencia a myClass y luego invocar al m t o do DoWork (). El tipo de u na expresin de invocacin es el tipo que devuelve la funcin a la que se llama. Si, por ejemplo, el cdigo C# llama a u na funcin que devuelve un tipo int. la expresin de invocacin que llama a ese mtodo tiene un tipo int.

Cmo especificar elementos de matriz con expresiones de acceso a elementos


Las expresiones de acceso a elementos permiten es pecificar elementos de m a triz. El nmero del elemento de mat ri z se escribe dentro de corchetes.
int [ ] MyArray; [5];

MyArray = new int M y A r r a y [0] = 12 3;

En este ejemplo, al elemento cero de la mat ri z l lamada MyArray se le asigna el valor de 123. C# permite que cualqui er expresin que p ro du z ca un resultado de tipo int, uint, long o ulong se utilice como expresin de elemento. C# tambi n p er mi te el uso de cualquier expresin cuyo resultado sea de un tipo que pueda ser convertido implcitamente en tipo int. uint. long o ulong. En el cdigo anterior, se us a un literal entero como expresin de elemento. Podra igualmente escribir un tipo de expresin diferente p ar a especificar el elemento, como muest ra el listado 4.2.
Listado 4.2. Acceso a elementos class MyClass static void M a i n ( )

{
public

{
int [ ] MyArray; MyClass myclass = new MyClass ( ); MyArray = new int [5]; MyArray[ m y c l a s s .G e t A r r a y l n d e x ()] =

123;

107

int

GetArraylndex O return ;

{ } } Este eodigo funciona porque el mtodo G e t A r r a y l n d e x ( ) devuelve un i n t y el resultado de la expresin de invocacin es un i n t . Como cualquier expresin cuyo valor sea i n t puede ser usada como expresin de elemento de una matriz. C# permite que este cdigo se ejecute. El resultado de la expresin de acceso al elemento es el tipo del elemento al que se accede, como se muest ra en el siguiente cdigo:
int [ ] MyArray; [5];

MyArray = new int MyArray[] = 12 3;

La expresin de acceso al elemento M y A r r a y [ 0 ] es de tipo i n t porque el elemento al que se accede en la expresin es de tipo i n t .

Cmo acceder a objetos con la palabra clave this


C# define una pal abra clave t h i s que puede usarse par a especificar un objeto p ar a un fragment o de cdigo que necesite acceder a esc objeto. La pal ab ra clave t h i s se estudia con mas detalle en la seccin que trata de las clases. El listado 4.3 usa la palabra clave t h i s .
Listado 4.3. A cceso mediante palabra clave class MyCiass static voicl Main ( )

{
public

{
// llame D o W o r k ( ) en este objeto MyCiass myclass = new M y C i a s s (); myclass .DoWork. (! ;

}
void DoWo r k ( )

{
MyCiass myclass = new M y C i a s s (); t h i s .DoWo r k 2 ( ); // haga aqu su trabajo

108

void

DoWork2( )

{ } } En este ejemplo, la e xpresi n de acceso this tiene el tipo MyClass porque la clase MyClass contiene el cdigo que incluye la expresi n de acceso ths.

Cmo acceder a objetos con la palabra clave base


C # tambin define la pal abr a clave base par a su uso con objetos. En un captulo posterior apr ender que puede usar clases como punto de partida par a const rui r nuevas clases. Las clases originales reciben el nombre de clases base y las clases construidas a partir de ellas se llaman clases derivadas. Para ordenar al cdigo C# de la clase derivada que acceda a los datos de la clase base, se usa la pal abr a clave base. El tipo par a las expresiones que usan base es la clase base de la clase que contiene la p al ab r a clave base.

Cmo usar los operadores postfijo de incremento y de decremento


C# permite incrementar o reducir valores numricos usando smbolos es pe ci a les. El operador ++ incrementa el valor y el operador reduce el valor. Se pueden apl icar estos operadores a expresiones de tipo sbyte. byte. short. ushort. int. uint. long y ulong. El listado 4.4 mues tra los operadores de incremen to y decrement o en accin.
Listado 4.4. O peradores de incremento y de decrem ento class MyClass static void M a i n ( )

{
public

{
int Mylnteger;
Mylnteger = 125; Mylnteger++; // el valor Mylnteger--; // el valor

ahora es 126 ahora vuelve a ser

125

El tipo de u na expresin que u s a oper adores postfijos de incremento y de decrcmento concuerda con el tipo cuyo valor se est i ncrementando o reduciendo. En el listado 4.4. los oper adores de incremento y de decremento tienen tipo int.

109

Creacin de nuevos tipos de referencia con el operador new


El operador new se usa par a crear nuevas instancias de tipos de referencia. Hast a ahora, el operador new ha sido usado p ar a crear nuevas matrices y cuando estudie los objetos, aprender a usar el o per ador new par a crear nuevos objetos. El operador new es considerado una expresin y el tipo de la expresin c on cuerda con el tipo de la variable cr eada con la p al ab ra clave new.

Cmo devolver informacin sobre el tipo con el operador typeof


El op er ado r typeof es una p al abr a clave C# que devuelve informacin sobre el tipo de una variable. Se usa como si fuera una funcin, empleando la p al abr a clave typeof seguida de una expresin:
class MyClass static void M a i n ( )

{
public

{
System.Consol.WriteLine (typeof (i n t ) ) ;

} } La p al ab ra clave typeof devuelve un objeto llamado System. Type que describe el tipo de la variable. El tipo de la expresin typeof es la clase

S y s t e m .Type.

Cmo usar operadores checked y unchecked


Los operadores checked y unchecked permiten activar o desactivar la verifica cin en tiempo de ejecucin de las operaciones matemt icas. Si se incluye una operacin mat emt ica en un oper ado r checked. se i nformar de un error si la operacin no tiene sentido. Si se incluye una operacin mat emt i ca en un o p e r a dor unchecked. se informar de un error incluso si la operaci n no tiene sentido El listado 4 5 muest ra un probl ema de desbor damient o matemtico. Se de c la ran dos variables enteras. Intl y Int2 y una tercera. IntlPlusInt2. c u y o valor a lmacena la suma de las otras dos. Los dos enteros se suman y el resultado se al macena en la tercera variable entera. Entonces el valor de la tercera variable se escribe en la consola.
Listado 4.5. Desborde en operaciones matemticas class Listing4_5

110

publc static void M a m ( )

{
int int int Intl; Int 2; IntiPlusInt2;

Intl = 2000000000; Int2 = 2000000000; IntlPlusInt2 - Intl + Int2; System.Cons ole.WriteLine(IntlPlusInt2) ;

} } A cada variable entera Intl y Int2 se le asi gna el valor de dos mil millones. Esta operacin no supone ningn pro bl ema porque las variables enteras pueden al macenar valores por encima de dos mil cien millones. Sin embargo, s umar estos dos integrales y al macenar el resultado en otro integral va a s uponer un problema. La s uma sera cuatro mil millones, lo que s upera el valor lmite de un entero, poco ms de dos mil cien millones. Compile el cdigo anterior con la lnea de coman do habitual.
ese Listing4-l.cs

Cua nd o ejecute el archivo Listing4-1 exe. obt endr un gran nmero negativo, como se ve en la figura 4.1.
c \ C:\WINDOWS\System32\cmd.exe C : \ > L i s t. in y 4 - . e x e -2 9 4 9 6 7 2 9 6 C :\> ^ S J 2L

Figura 4.1. Los d e sbordam ientos producen resultados impredecibles.

Se obtiene un result ado negativo debido al modo que tiene C# de pr oc e sa r los valores demasiado grandes p ar a encajar en las variables destinadas a ellos. C# no puedo representar todo el valor de un entero, as que toma el valor propuesto, c u a t r o mil m i l l o n e s y le r e s t a el v a l o r m x i m o de un v a l o r de 32 bi ts (4.294.967. 296). extrayendo el resultado a la consola.

111

Obviamente, el cdigo ha generado un resultado distinto del que queramos. Si no se da cuenta de este tipo de errores matemticos, su cdigo puede c omport arse de for ma impredecible. Para insertar una medida de seguridad en cdigos como ste, puede usar el operador checked, como aparece en el listado 4.6.
Listado 4.6. Verificacin de los desbordam ientos de las operaciones matemticas class Listing4_6

{
public static void M a i n ( )

{
int Intl; in t In 1 2 ; m t IntlPlusInt2; Intl = 2000000000;

I n t 2 - 2000000000;
IntlPlusInt2 = checked(Intl + Int2 ); System. Consol. W r i t e L m e (IntlPlusInt2) ;

} } Si compila y ejecuta el listado 4.6 se escribir un resultado diferente en la consola:


Excepcin no controlada: S ys t e m .OverflowException : La aritmtica ha provocado un desbordamiento, at L is t i n g 4 _ l . M a i n ( ) operacion

En lugar de escribir un valor mat emt ico sin sentido en la consola, un mensaje de desbor damient o permite saber que se intent c om pr ob a r la validez del valor de la suma y que la p rue ba no fue superada. Se i nforma de una excepcin y la aplicacin concluye. La expresi n unchecked ( ) es la que se u sa por defecto. En las expresiones que tienen unchecked ( ) no se comp ru e ba la validez de los valores y la ap li ca cin sigue ej ecutndose us ando los valores no verificados, aunque no tengan s en tido. El c omport ami ent o por defecto es el de no verificar las operaciones. Sin e m bargo. si quiere que se c omprue be si todos los valores de sus operaciones son vlidos sin us ar el oper ador checked ( ) en el cdigo, puede u s ar la opcin / checkedi del compilador. Compil e el listado 4.1 con la siguiente lnea de c o mando:
ese /checked+ L i s t m g 4 - 1 .es

C u an do se ejecuta el ejecutable de listing 4-1, se obtiene el mi smo mensaje de excepcin que se obt uvo con listing 4-2, porque la opcin /checked+ obliga a c om p ro ba r la validez de los valores de todas las operaciones matemticas.

112

Las expresiones uaras


Las expresiones unarias funcionan sobre un solo operando. C # admite las siguientes expresiones unarias: Unario ms o per ador Unario menos oper ador O p e r ad o r de negacin lgica Op e ra do r de compl ement o bit a bit O p e r ad o r de direcci onami ent o indirecto O p e r ad o r de di recci onami ent o O p e r ad o r de incremento y decrcment o prefijado Expresiones de conversin La siguientes secciones t ratan estas expresiones unarias con detalle.

Cmo devolver valores de operando con el operador unario ms


El operador unario ms (+) devuelve el v al or del operando. Puede pensar en l como el o pe r ad or m atem tico positivo. C# define el operador unario ms para los oper andos de tipo int. uint, long. ulong. f loat. double y decimal.

Cmo devolver valores de operando con el operador unario menos


El operador unario menos ( - ) devuelve el valor del operando. Puede pensar en l como el o pe r ad or m atem tico negativo. El valor de un oper ando con un oper a dor unitario menos es el equivalente negativo del operando. C # define el operador unario menos p ar a los operandos de tipo int, long, f loat. double y de

cimal.

Expresiones negativas booleanas con el operador de negacin lgica


El op er ad or de negacin lgica niega el valor de una expresin booleana. El operador ca mbi a el valor True a False y el valor False a True. Se usa el signo de exclamaci n p a r a escribir un oper ad or de negacin lgica en el cdigo

113

C#. El oper ador se coloca antes de la expresin bool eana que quiera negar, como se ilustra en el listado 4.7.
Listado 4.7. Operador de negacin lgica class MyClass

1
public static void Main ()

{
bool MyBoolean; = true; = IMyBoolean;

MyBoolean MyBoolean

//

"MyBoolean"

ahora

es

false

} )

El operador de complemento bit a bit


C# permite aplicar una operacin de complemento bit a bit a expresiones int. uint. long y ulong. Las operaciones de complemento bit a bit consideran al valor como si fueran un binario y dan la vuelta a todos los bits. Los bits que tenan un valor 1 se v u c h n 0 y los bits que tenan un valor 0 se vuelven 1. Los operadores de compl ement o bit a bit se especifican colocando el ca rcter virgulilla ( - ) antes de la expresin que debera ser compl ement ada bit a bit. como se ve en el listado 4.8.
Listado 4.8. Operador de complem ento bit a bit class MyClass

{
p u b 1 ic s tat ic v o i e l Ma in ()

{
in t In t 1; Int 1 = 123; Int l - -Int 1 ;

} }

Cmo prefijar operadores de incremento y decremento


Los operadores postfijos ++ y pueden ser usados en uno de los dos modos. Ya ha visto las versiones postfijas de los operadores, que aparece despus de la expresin. Las versiones prefijas aparecen antes de la expresin, como se ve en el listado 4.9.

114

Listad o 4.9. Operadores de incremento y decrem ento prefijados

class MyClass

{
public static void M a i n ( )

{
int Mylnteger; Mylnteger = 125; ++Mylnteger; // el valor ahora es 126 --Mylnteger; // el valor ahora vuelve a ser

125

} } El tipo de un a expresin que us a los oper adores postfijos de incremento y decrement o c onc uer da con el tipo cuyo valor se increment a o reduce. T eng a en cuenta la sutil diferencia entre estos operadores prefijos y los operadores postfijos que se vieron con anterioridad: con los operadores prefijos, el valor se cambi a despus de que se evale la expresin. El listado 4.10 ilustra esta diferencia.
Listado 4.10. Diferencias entre operadores postfijos y prefijos class Listing4_10 static void M a i n ( )

{
public

{ int

In 1 1;

I n t 1 = 12 3;
S y s t e m . C o n s o l . W r i t e L i n e (I n t 1 + + );

System.Consol.WriteLine(++Int 1 );

} } Compile y ejecute el listado 4.3. El resultado de esta aplicacin aparece en la figura 4.2. La pri mera instruccin del listado 4.10 usa el oper ador postfijo de incremento, lo que significa que el val or se increment a despus de que se ejecute la instruccin. La aplicacin escribe el valor actual. 123. en la consola y luego incrementa el valor a 124. La segunda instruccin usa el oper ad or de incremento postfijo, lo que significa que el val or se incrementa antes de que se ejecute la instruccin. La aplicacin primero incrementa el valor actual a 125 y luego escri be el valor actual en la consola.

Los operadores aritmticos


Los operadores aritmticos permiten realizar clculos en el cdigo CU. Las expresiones que us an operadores aritmticos son expresiones binarias porque se necesitan dos operandos p ar a realizar una operacin matemtica.

115

HBAVJi IJ l.MUUiffl m *i'lW ff!BW


C :\>L ist ing4-10.exe 123 125

Id
Figura 4.2. Uso de operadores prefijos y postfijos

Cmo asignar nuevos valores con el operador de asignacin


El oper ador de asignacin asigna un nuevo v alor a una variable. El signo igual se usa como operador de asignacin:
Mylnteger - 3;

Se establece el valor de Mylnteger en 3 y se pierde el valor anterior de

MyVariable.
Los operadores de asignacin compuest a permiten usar el operador de a s i g n a cin mas de una vez en una instruccin:
Mylnteger = MyOtherInteger = 3;

El valor de la expresin a la derecha se usa como el nuevo valor par a las variables. En este ejemplo, se asigna 3 a Mylnteger y a MyOther Integer.

Uso del operador multiplicacin


El v alor de una expresin que usa el oper ador de multiplicacin es el producto de los valores de los dos operadores. El carcter asterisco se usa como operador de multiplicacin, como se v e en el listado 4.11.
Listado 4.11. Operador multiplicacin class MyClass static void M a i n ( )

{
public

116

{
int M y l n t e g e r ; Mylnteger = 3 * c; // Mylnteger sera 18

} } Si se est mul tiplicando un valor por una v ariable v colocando el resultado en la misma variable, se puede escribir una instruccin abreviada par a realizar la multiplicacin. Al introducir un asterisco seguido por un signo igual se multiplica un v alor por una variable y se actualiza el v alor de la variable con el resultado:
MyIntege r *= 3 ;

Esta instruccin es la abrev iatura de la siguiente:


Mylnteger = Mylnteger * 3;

Uso del operador divisin


El valor de una expresin que usa el o per ador de div isin es el producto de los valores de los operadores. La bar ra inclinada es el carcter que se usa como o per ado r de divisin, como se ve en el listado 4.12.
Listado 4.12. Operador divisin (E jemplo 1) class MyClass static voicl Main ( )

(
public

{
int M y l n t e g e r ; Mylnteger = 6 / 3 ; // Mylnteger sera 2

} } Si la operacin de divisin da como resultado un resto, el resultado de la operacin ser slo el cociente (vase el listado 4.13).
Listado 4.13. Operador divisin (Ejemplo 2) class MyClass static void M a i n ( )

{
public

{
int Mylnteger; Mylnteger = 7/3;

} }

117

Cuand o se ejecuta este cdigo, la variable Mylnteger tiene un valor de 2 . porque si se divide 7 entre 3 queda un cociente de 2 y un resto de 1. Si se divide un valor entre una variable y se coloca el resultado en la mi sma variable, se puede escribir una instruccin abrevi ada p ar a realizar la divisin. Escribiendo una b ar r a inclinada seguida por un signo igual se divide un valor entre una variable y se actual iza el valor de la variable con el resultado:
Mylnteger /= 3 ;

La instruccin anterior es una abr evi at ura de la siguiente:


Mylnteger = Mylnteger / 3;

Uso del operador resto


El valor de una expresin que usa el oper ado r de resto es el resto de una operacin de divisin. El ca rc te r tanto por ciento se usa como el oper ador de divisin (vase el listado 4.14).
Listado 4.14. Operador resto class MyClass static void M a i n ( )

{
public

{
int Mylnteger; MyIntege r = 7 3;

} } Cuand o se ejecuta este cdigo, la variable Mylnteger tiene el valor de 1. porque si se divide 7 entre 3 queda un cociente de 2 y un resto de 1. Si se est calculando un resto usando una variable y se coloca el resultado en la mi sma variable, se puede escribir una instruccin abrevi ada para realizar la operacin de resto. Si se escribe un signo de t anto por ciento seguido del signo igual se calcul ar el resto de una v ariable y se actual izar el valor de la v ariable con el resultado:
Mylnteger = 3;

La instruccin anterior es la abr ev iat ura de la siguiente:


Mylnteger - Mylnteger 3;

Uso del operador suma


El valor de una expresin que usa el oper ador de suma es la s uma de los valores de los dos operadores. El carcter s uma se usa como el oper ador de multiplicacin (vase el listado 4.15).

118

Listad o 4.15. Operador suma class MyClass static void M a i n ( )

{
public

{
int Mylnteger; Mylnteger = 3 + 6 ; // Mylnteger ser 9

} } Si se est sumando un valor a una variable y se coloca el resultado en la misma variable, se puede escribir una instruccin abr evi ada que realice la suma. Al escribir un signo ms seguido de un signo igual se aade un valor a una variable y se actual iza el val or de la variable con el resultado:
Mylnteger += 3;

La instruccin anterior es la abr evi at ura de la siguiente:


Mylnteger = Mylnteger + 3;

El oper ado r de s uma tiene un significado especial cuando los dos operandos son cadenas. La s uma de dos cadenas une la pri mera cadena a la segunda:
string C o m b i n e d S t r m g = "Helio from " + "C#";

El valor de CombinedString es Hello f rom C# cuando se ejecuta este cdigo.

Uso del operador resta


El valor de una expresin que usa el oper ador de resta es la diferencia de los valores de los dos operadores. El carcter guin se usa como el oper ador de resta (vase el listado 4.16).
Listado 4.16. O perador resta class MyClass static void M a i n ( )

{
public

{
int Mylnteger; Mylnteger = 7 - 3 ; // Mylnteger ser 4

} } Si se est restando un valor a u na variable y se coloca el resultado en la misma variable, se puede escribir una instruccin abr evi ada que realice la resta. Al es-

119

cribir un signo menos seguido de un signo igual se resta un valor de una variable y se actualiza el valor de la variable con el resultado:
Mylnteger -= 3;

La instruccin anterior es la abrevi at ura de la siguiente:


Mylnteger = Mylnteger - 3;

Los operadores de desplazamiento


Los oper adores de despl azami ent o permiten mover bits de lugar en un valor de su codigo C#. Las expresiones que usan los operadores de despl azami ent o son expresiones binarias porque se necesitan dos operandos p ar a realizar una operacin de desplazamiento.

Cmo mover bits con el operador de desplazamiento a la izquierda


El valor de una expresin que usa el operador de desplazamiento a la izquierda se muev e a la izquierda la cantidad de bits especificados. Se usan dos caracteres menor que (<<r) como operadores de desplazamiento a la izquierda (vase el lista do 4.17).
Listado 4.17. Operador de desplazamiento a la izquierda class MyClass static void M a i n ( )

{
public

(
mt Mylnteger;

M y l n t e g e r = 6 << 3; ( } Cua nd o se ejecuta este cdigo, la variable Mylnteger tiene un valor de 48. porque el valor original. 6. es considerado un nmero binario con un valor binario de ()()()()() l 10. Cad a bit en el valor original se desplaza tres lugares, que es el valor que aparece despus del oper ad or de despl azami ent o a la izquierda y se colocan ceros en los bits de orden inferior. Al ca mbi ar cada bit tres lugares da como resultado un valor binario de 00 l 10000 o 48 en el sistema decimal. Se pueden aplicar desplazamientos a la izquierda a los valores de las expr esi o nes de tipo int. uint. long y ulong. Tambi n pueden desplazarse a la iz quierda otras expresiones que pueden ser convertidas a uno de estos tipos. Las

120

expresiones de tipo int y uint pueden despl azarse hast a 32 bits de una vez. Las expresiones de tipo long y ulong pueden ser despl azadas hasta 64 bits de una vez. Si se est calculando una operacin de desplazamiento a la izquierda de un valor y una variable, y se coloca el resultado en la mi sma variable, se puede escribir una instruccin abreviada que realice esta operacin. Al escribir dos signos menor que ( ) seguidos por un signo igual se calcula la operacin de desplazamiento a la izquierda y se actualiza el valor de la variable con el resultado.
Mylnteger <<= 3;

La instruccin anterior es la abr evi at ura de la siguiente:


Mylnteger = Mylnteger << 3;

Cmo mover bits con el operador de desplazamiento a la derecha


El valor de una expresin que usa el oper ado r de despl azami ent o a la derecha se mueve a la derecha la cantidad de bits especificados. Se usan dos caracteres m ayo r que ( ) como operadores de desplazamiento a la derecha (vt'ase el listado 4.18).
Listado 4.18. O p erador de desplazam iento a la derecha class MyClass static void M a i n ( )

(
public

{
int Mylnteger; Mylnteger = 48 >> 3;

} } Cuand o se ejecuta este cdigo, la variable Mylnteger tiene un valor de 6 . porque el valor original, 48. es considerado un nmero binario con un valor binario de 00110000. Cada bit en el valor original se desplaza tres lugares, que es el valor que aparece despus del oper ad or de despl azami ent o a la derecha y se colocan ceros en los bits de orden superior. El ca mbi a r cada bit tres lugares da como resultado un valor binario de 0 0 00 01 1 0 o 6 decimal. Se pueden aplicar desplazamientos a la derecha a los valores de las exp res io nes de tipo int. uint. long y ulong. Tambi n pueden despl azarse a la der e cha otras expresiones que pueden ser convertidas a uno de estos tipos. Las expresiones de tipo int y uint pueden despl azarse hast a 32 bits de una vez. Las expresiones de tipo long y ulong pueden ser despl azadas hasta 64 bits de una vez.

121

Si est calcul ando una operacin de des plazamiento a la derecha de un valor y una variable y colocando el resultado en la mi sma variable, puede escribir una instruccin abr evi ada que realice esta operacin. Escribir dos signos may or que seguidos por un signo igual calcula la operacin de desplazamiento a la derecha y actual iza el valor de la v ariable con el resultado:
Mylnteger > >3;

La instruccin anterior es la abr evi at ura de la siguiente:


Mylnteger = Mylnteger >> 3;

Cmo comparar expresiones con operadores relacinales


Los operadores relacinales permiten c o m pa r ar dos expresiones y obtener un v alor booleano que especifica la relacin entre las dos expresiones. Las exp res io nes que usan operadores relacinales son expresiones binarias porque se necesi tan dos operandos par a realizar una operacin relacional.

Cmo comprobar la igualdad con el operador de igualdad


El operador de igualdad se usa para c omp rob ar la igualdad entre los v alores de dos expresiones. Si las expresiones tienen el mismo valor, el operador de igualdad devuelve Truc. Si tienen valores diferentes, el oper ad or de igualdad devuelve F a l s e . Como operador de igualdad se usan dos signos igual:
Mylnteger -12 3;

Si el valor de la variable Mylnteger es 123. el o per ador de igualdad devuel ve True. Si tiene otro valor, el oper ad or de igualdad devuelve False. El o perador de igualdad tiene un significado especial cuando los dos operandos son cadenas. Al co mp ar a r dos cadenas se comp ar an los contenidos de las c a d e nas. Dos cadenas se consideran iguales si tienen la mi sma longitud y los mismos caracteres en cada posicin de la cadena.

Cmo comprobar la desigualdad con el operador de desigualdad


El oper ador de desigualdad se usa par a comp ro b ar la desigualdad entre los valores de dos expresiones. Si las expresiones tienen diferentes valores, el o p e r a dor de desigualdad devuelve True. Si tienen el mismo valor, el oper ad or de

122

d es igual dad devuelve False. C omo o per ad or de desigualdad se us a un signo de exclamaci n seguido por un signo igual:
Mylnteger != 123;

Si el valor de la variable Mylnteger es 123. el op er ad or de desigualdad d evu el ve False. Si tiene otro valor, el oper ado r de desigualdad devuelve Tru. El o p er a do r de desi gual da d tiene un s ignificado especial c ua nd o los dos operandos son cadenas. Al c om p a r a r dos cadenas se c om pa r an los contenidos de las cadenas. Dos cadenas se consideran desiguales si tienen diferentes longitudes o diferen tes caracteres en, al menos, una posicin de la cadena.

Cmo comprobar valores con el operador menor que


El operador menor que se usa p ar a comp ro ba r los valores de dos expresiones y ver si un valor es menor que el otro. Si la pri mera expresin tiene un valor menor que el de la s egunda expresin, el oper ad or menor que devuelve True. Si la p ri mera expresin tiene un valor m ay o r o igual que el de la s egunda expresin, el o pe r ad or menor que devuelve False. El o per ado r menor que se representa m e diante un signo menor que (<):
Mylnteger < 123;

Si el valor de la variable Mylnteger es menor de 123. el op er ad or menor que devuelve True. Si tiene un valor mayor que o igual a 123, el operador menor que devuelve False.

Cmo comprobar valores con el operador mayor que


El operador mayor que se us a p ar a comp ro ba r los valores de dos expresiones y ver si un valor es m ay or que el otro. Si la pri mera expresin tiene un valor mayor que el de la segunda expresin, el oper ado r m ayo r que devuelve True. Si la p ri mera expresin tiene un valor menor o igual que el de la s egunda expresin, el op er ad or m ay or que devuelve False. El op er ad or m ayo r que se representa m e diante un signo m ay or que (<).
Mylnteger > 123;

Si el valor de la variable Mylnteger es mayor de 123, el oper ad or mayor que devuelve True. Si tiene un valor menor que o igual a 123. el operador menor que devuelve False.

123

Cmo comprobar valores con el operador menor o igual que


El o per ador menor o igual se usa par a c ompr ob ar los valores de dos expr es io nes y ver si un valor es menor o igual que el otro. Si la pri mera expresin tiene un valor menor o igual que el de la segunda expresin, el operador menor o igual que devuelve True. Si la primera expresin tiene un valor mayor que el de la segunda expresin, el op er ad or menor o igual que dev uelve False. Como op er ad or menor o igual que se usa un signo menor que seguido de un signo igual (< = ):
Mylnteger <= 12 3;

Si el valor de la variable Mylnteger es menor o igual a 123. el operador menor o igual que devuelve True. Si tiene un valor mayor de 123. el oper ador menor o igual que devuelve False.

Cmo comprobar valores con el operador mayor o igual que


El oper ador mayor o igual que se usa par a co mp ro ba r los valores de dos expresiones y ver si un valor es m ayo r o igual que el otro. Si la primera expresin tiene un valor mayor o igual que el de la s egunda expresin, el operador mayor o igual que dev uelve True. Si la pri mera expresin tiene un valor menor que el de la segunda expresin, el op er ado r mayo r o igual que devuelve False. C omo oper ado r m ay or o igual que se usa un signo mayor que seguido de un signo igual (> = ):
Mylnteger >= 12 3;

Si el valor de la variable Mylnteger es mayor o igual a 123, el operador mayor o igual que devuelve True. Si tiene un valor menor de 123. el operador m ayo r o igual que devuelve False.

Operadores lgicos enteros


Los oper adore s lgicos enteros permiten real izar oper aci ones arit mt icas bool eanas sobre dos valores numricos. Las expresiones que usan operadores lgicos enteros son expresiones binarias porque se necesitan dos operandos par a realizar una operacin lgica.

124

Cmo calcular valores booleanos con el operador AND


El o per ador AND se usa p ar a calcular el valor AND bool eano de dos e xp res i o nes. C omo o per ado r AND se usa el smbolo de unin (&):
Mylnteger = 6 & 3;

El val or de M y l n t e g e r es 2. Recuerde que un bit en una operaci n AND es 1 slo si los dos bits operandos de la mi sma posicin son 1. El valor 6 en binario es 1 10 y el valor 3 en binario es 0 1 1 . Si se realiza un AND booleano de 1 10 y 01 1 se obtiene como resultado un valor booleano de 010 o 2 en el sistema decimal. Si se est calculando una operacin AND sobre un valor y una variable y se coloca el resultado en la mi sma variable, se puede escribir una instruccin a b r e viada que realice la operacin AND. Si se escribe un signo de unin (&) seguido de un signo igual se calcula la operacin AND sobre una variable y un valor, y se actual iza el valor de la variable con el resultado:
Mylnteger &- 3;

La instruccin anterior es la ab rev iat ura de la siguiente:


Mylnteger = Mylnteger & 3;

Cmo calcular valores booleanos con el operador exclusivo OR


El oper ado r exclusivo OR se us a p ar a calcular el valor booleano exclusivo OR de dos expresiones. C omo o per ad or OR exclusivo se usa el signo de intercalacin
( A): Mylnteger = 6 A 3;

El val or de M y l n t e g e r es 5. Recuerde que un bit en una operacin exclusiva

OR es 1 slo si uno de los dos bits operando en la mi sma posicin es 1. El valor de


6 en binario es 110 y el valor de 3 en binario es 0 1 1. Si realizamos un booleano OR exclusivo entre 110 y 011 obt enemos como resultado un valor booleano de 101 o 5 en el sistema decimal. Si se est calculando u na operacin OR exclusiva sobre un valor y una v a r ia ble y se coloca el resultado en la mi sma variable, se puede escribir una i nst ruc cin abr evi ada que realice la operacin OR exclusiva. Si se escribe un signo de intercalacin ( A) seguido de un signo igual se calcula la operacin OR exclusiva sobre una variable y un valor, y se actualiza el valor de la variable con el result a do:
Mylnteger 3;

125

La instruccin anterior es la ab revi at ura de la siguiente:


Mylnteger = Mylnteger A 3;

Cmo calcular valores booleanos con el operador OR


El oper ado r OR se usa p ar a calcular el valor booleano OR de dos expresiones. Como oper ador OR se usa el carcter barra vertical (|):
Mylnteger = 6 | 3;

El valor de Mylnteger es 7. Recuerde que un bit en una operacin OR es 1 slo si uno de los dos bits operandos de la mi sma posicin es 1. El valor 6 en binario es 110 y el valor 3 en binario es 01 1. Si se realiza un booleano OR entre 1 10 y 01 1 se obtiene como resultado un valor de 1 1 1 o 7 en decimal. Si se est calculando una operacion OR sobre un valor y una variable, y se coloca el resultado en la mi sma variable, puede escribir una instruccin a b r ev i a da que realice la operacion OR. Si se escribe una b ar ra vertical (|) seguido de un signo igual se calcula la operacin OR sobre una variable y un valor, y se a c t u a liza el valor de la variable con el resultado:
Mylnteger

|= 3 ;

La instruccin anterior es la ab revi at ura de la siguiente.


Mylnteger = Mylnteger | 3;

Operadores condicionales lgicos


Los o per adores condicionales lgicos son los equivalentes condicionales de los operadores lgicos enteros. Las expresiones que usan los operadores co nd i cionales lgicos son expresiones binarias porque se necesitan dos operandos para realizar una operacin condicional lgica.

Comparacin de valores booleanos con el operador AND condicional


El operador AND condicional se usa para compar ar dos expresiones booleanas. El resultado de la operacin es True si ambos operandos devuelven True y False si uno de los dos operandos devuelve False. C omo o per ador AND c o n dicional se usan dos smbolos de unin:
MyBoolean = true & & false;

126

El valor de MyBoolean es False porque uno de los dos oper andos devuel ve False.

Comparacin de valores booleanos con el operador OR condicional


El oper ador OR condicional se usa p ar a c om pa r ar dos expresiones booleanas. El resultado de la operacin es True si uno de los dos oper andos devuelve True y False si los dos operandos devuelven False. C omo o per ador OR condicional se usan dos bar ras verticales:
MyBoolean = true | | false;

El valor de MyBoolean es True porque uno de los dos oper andos devuelve

True.

Comparacin de valores booleanos con el operador lgico condicional


El operador lgico condicional evala una expresin booleana. El resultado de la expresin tiene un valor si la expresin de ent rada devuelve True y otro si la expresin de ent rada devuelve False. Las expresiones que usan operadores con dicionales son expresiones ternarias porque se necesitan tres operandos p ar a rea lizar una operacin lgica condicional. El operador condicional es la nica expresin ternaria admitida por el lenguaje C#. Escribir un oper ador condicional implica escribir la expresin de entrada se gu id a por un signo de interrogacin. El valor True aparece despus, seguido de dos puntos y a continuacin seguido por el valor False:
Mylnteger = (MyVanable == 123) ? 3: 5;

Puede interpretar esta instruccin como " Co mp ar a el valor de MyVariable con 123. Si esa expresin devuelve True. haz que el valor de Mylnteger sea 3. Si esa expresin devuelve False, haz que el valor de Mylnteger sea 5".

El orden de las operaciones


C# permite colocar varios operadores en un a sola instruccin:
MyVariable = 3 * 2 + 1 ;

Cual es el valor de MyVariable a q u ) Si C# aplica la multiplicacin en pri mer lugar, leer la instruccin como "multiplica 3 por dos y luego aade 1".

127

que da como resultado un valor de 7. Si C# aplica la s uma en primer lugar, leer la instruccin como "suma 2 y 1 y luego multiplcalo por 3". que da como r es ult a do un valor de 9. C# combi na los operadores en grupos y aplica un orden de prioridad a cada grupo Este orden de prioridad especifica qu operadores se evalan antes que otros. La lista con el orden de prioridad de C# es la siguiente, ordenados de mayor prioridad a menor: Expresiones primarias Operadores n a n o s + - ! - + + Op eradores multiplicativos * / % Op eradores aditivos + Op eradores de despl azami ent o << >> Operadores relacinales < > < = > = Operadores de igualdad == != A N D logico O R lgico exclusivo OR lgico A ND condicional OR condicional T er nari o condicional Op eradores de asignacin

Repase la siguiente instruccin:


MyVariable = 3 * 2 + 1

C# da a MyVariable un valor de 7 porque la prioridad del oper ador de multiplicacin es superior a la del oper ador de suma. Esto significa que el o p e r a dor de multiplicacin se evala primero y en segundo lugar el oper ador suma. Se puede invalidar el orden de prioridad con parntesis. Las expresiones entre parntesis se evalan antes de que se apliquen las reglas de prioridad de o p er a d o res:
MyVariable - 3 * (2+1)

En este caso. C# da a MyVariable un valor de 9. porque la expresin de suma est entre parntesis, obligando a que se evale antes que la operacin de multiplicacin.

128

Resumen
C # define muchos operadores p a r a ayudarle a evaluar expresiones y a calcular nuevos valores a partir de esas operaciones. Este lenguaje permite escribir e xp re siones que realizan funciones mat emt icas y booleanas. y com pa r a dos e xp res i o nes y obtiene un resultado booleano de esa comparacin. En este capitulo, se presentan los operadores de C# y se aprende a us ar estos operadores en expresiones con literales y variables. Tambi n se han revisado las expresiones de oper ador y la prioridad al usar estos operadores en expresiones. Cuando examinemos las clases en un captulo posterior, descubri r que sus clases pueden redefinir algunos de estos operadores. A esto se le llama s obr ecar ga de operadores y le permite redefinir la for ma en que los operadores calculan los resultados.

129

Q Cmo controlar el flujo del cdigo

El co mp or ta mi en to del cdigo C# a menudo depende de las condiciones que se determinan en tiempo de ejecucin. Qui zs quiera escribir una aplicacin que salude a sus usuarios con un mensaje de "Buenos das" si la hora en ese momento es inferior a las 12:00 P.M.. por ejemplo; o "Buenas tardes" si la hora en ese momento est entre las 12:00 P.M. v las 6:00 P.M. C ompo rt ami ent os como ste necesitan que el cdigo C# exami ne valores en tiempo de ejecucin y realice una accin b as ad a en dichos valores. C# admite varias construcciones de cdigo que le permiten ex ami nar variables y realizar una o varias acciones b as ad as en dichas variables. En este captulo se examinan las instrucciones de flujo de control de C# que ac tua rn como el cerebro de las aplicaciones que escriba.

Instrucciones de C#
Una instruccin es una expresin vlida de C# que define una accin real iza da por el cdigo. Las instrucciones pueden exa mi na r valores de variables, a si g nar nuevos valores a una variable, llamar a mtodos, realizar una operacin, crear objetos o realizar al guna otra accin.

131

La instruccin ms corta posible en C# es la instruccin vaca. sta consiste en slo el punt o y coma:

Se puede us ar la instruccin vaca par a decir. "No hagas nada aqu". Esto podra no par ecer muy til, pero tiene su funcin.

NOTA: Todas las instrucciones de C# terminan en un punto y coma.


Las instrucciones se agr upan en listas de instrucciones que se componen de una o ms instrucciones escritas en secuencia:
int MyVariable; - 123; += 2 3 4 ;

MyVariable MyVariable

Por lo general, las instrucciones se escriben en su propia lnea. Sin embargo. C# no exige esta disposicin. C# ignora cualquier espacio en blanco entre instruc ciones y acept a cualquier disposicin siempre que cada instruccin este s eparada por un punto y coma:
int MyVariable; = 123; MyVariable += 234 ;

MyVariable

Las listas de instrucciones se encierran entre llaves. Una lista de instrucciones entre llaves recibe el nombre de bloque de in s tru c cio n es. Casi siempre usar bloques de instrucciones par a escribir el cdigo de la funcin. To da la lista de instrucciones de la funcin se coloca en un bloque de instrucciones. Es per f ec ta mente posible us ar slo una instruccin en un bloque de instrucciones:
public static void M a i n ( )

{
System.Consol.WriteLine ("Helio! ") ;

} C# no impone ningn lmite al nmero de instrucciones que se pueden colocar en un bloque de instrucciones.

Instrucciones para declarar variables locales


Las instrucciones de declaracin declaran variables locales en el cdigo. Ya hemos visto varios ejemplos de este tipo de instrucciones. Las instrucciones de declaracin especifican un tipo y un nombre par a un variable local:
int MyVariable;

132

T am bi n se puede inicializar la variable cuando se declara us ando un signo igual y a si gnando un valor a la variable:
int MyVariable = 123;

C# permite enumer ar varias variables en la misma instruccin. Para separar los nombres de las variables se usan comas.
int MyFirstVariable , MySecondVariable ;

C ad a variable de la instruccin tiene el tipo especificado. En el ejemplo a n te rior, MyFirstVariable y MySecondVar iable son de tipo int. Las declaraciones de constantes definen una variable cuyo valor no puede ca mbi a r durante la ejecucin del cdigo. Las declaraciones de constantes usan la pal abra clave de C# const y deben asi gnar un valor a la variable cuando se declara dicha variable:
const int MyVariable = 123;

Las declaraciones de constantes permiten una mejor legibilidad y ad mi n is tr a cin del cdigo. Se pueden tener valores constantes en el cdigo y al asignarles nombres se consigue que el cdigo resulte ms legible que si u sar a su valor. Adems, si se usan valores por todo el cdigo y luego se necesita cambiarlos, esta ser una tarea muy pesada. Si se usa una constante, slo har falta cambi ar una lnea de cdigo. Por ejemplo, suponga que est escribiendo un cdigo par a una aplicacin que realiza medidas geomtricas. Uno de los valores con los que querr t rab aj ar es pi. la relacin entre la circunferencia de un crculo y su dimetro. Sin una dec la ra cin de constante, tendra que escribir un cdigo de la siguiente forma:
Area = 3.14159 * Radius * Radius;

Al us ar una constante se logra que el cdigo sea un poco ms sencillo de entender:


const double Pi = 3.14159; * Radius;

Area = Pi * Radius

Esto es especialmente til si us a m uchas veces en el cdigo el valor de pi.

Cmo usar instrucciones de seleccin para seleccionar la ruta del cdigo


Las instrucciones de seleccin seleccionan una de las muchas rutas posibles p a r a que se ejecute el cdigo. La ruta de cdigo seleccionado se b a sa en el valor de u na expresin.

133

La instruccin if
La instruccin i f t raba ja con una expresin que devuelve un valor booleano. Si la expresin booleana resulta ser true. la instruccin incrustada en la i nst ruc cin if se ejecuta. Si la expresin booleana resulta ser false. la instruccin i ncrustada en la instruccin i f no se ejecuta:
if(MyVariable =- 123) S y s t e m . C o n s o l . W r i t e L m e ("MyVariable's valu is 123.");

La instruccin booleana se escribe entre parntesis. La instruccin incrustada sigue a los parntesis. Se usa un punto y coma par a cerrar la instruccin i ncrus tada. pero no la expresin booleana.

NOTA: Cuando se usa la instruccin i f para comprobar una igualdad, siempre se deben usar dos signos igual. Dos signos igual hacen una com probacin de igualdad, mientras que un signo igual realiza una asignacin. Si se usa accidentalmente un signo igual dentro de una instruccin i f , sta siempre devolver un valor t r u e .

En el anterior ejemplo, el valor de M y V a r i a b l e se compar a con el valor literal 123. Si el \ a l o r es igual a 123. la expresin devuelve t r u e v se escribe el mensaje M y V a r i a b : e ' s v a l e i s 12 3 . en la consola. Si el \ a l o r no es igual a 123. la expresin devuelve f a l s e y no se escribe nada. La instruccin 1 f puede ir seguida de una clausula e l s e . La palabra clave e l s e va seguida de una instruccin incrustada que se ejecuta si la expresin booleana usada en la clusula i f devuelve f a l s e :
if(MyVariable == 123) System.Console.WriteLine("MyVariable's else Sys te m. Co ns ol e.Writ eL in e("MyVariable's value value is is 123."); not 123.");

En el anterior ejemplo, el valor de M y V a r i a b l e se c ompar a con el valor literal 123. Si el valor es igual a 123. la expresin devuelve t r u e y se escribe el mensaje M y V a r i a b l e ' s v a l u e i s 1 2 3 . en la consola. Si el valor no es i g u a l a 123. la e x p r e s i n d e v u e l v e f a l s e y se e s c r i b e el m e n s a j e M y V a r i a b l e ' s v a l u e i s n o t 1 2 3 . en la consola. La clusula e l s e puede ir seguida por su propia clusula i f :
if(MyVariable == 123) System.Console.WriteLine ("MyVa riable's value else if ( M yV ariable == 124) System.Console.W r i t e L i n e ("MyVariable's value else System.Console.WriteLine("MyVariable's value is is is 12 3."); 12 4."); not 123.");

134

Las clusulas if y else permiten asociar una instruccin a la clusula. Por lo general. C# permite asociar slo una instruccin a la clusula, como se ve en el siguiente cdigo:
i f (MyVariable == 123) System.C o n s o l e .W r i t e L i n e ("MyVariable's value is System. Console . W r i t e L m e ("This always prints."); 123.");

La instruccin que escribe This always prints, en la consola siempre se ejecuta. No pertenece a la clusula if y se ejecuta i ndependientemente de si el valor de MyVariable es 123. La nica instruccin que depende de la c o m p a r a cin de MyVariable con 123 es la instruccin que escribe MyVariable' s value is 12 3 . en la consola. Si se quiere asociar varias instrucciones con una clusula if. se debe usar un bloque de instrucciones:
if (MyVariable == 123)

{
S ys t e m .Cons ol e . W r i t e L m e ("MyVar able's value is 12 3."); System.C o n s o l e .W r i t e L i n e ("This prints if MyVariable == 123 .") ;

} Tambi n se pueden usar bloques de instrucciones en las cl usul as else:


if (MyVariable == 123)

{
System.Cons o l e .W r i t eLine ("MyVariable' s value is 123."); System.C o n s o l e . W r i t e L m e ("This prints if MyVariable == 12 3.") ;

}
else

{
System. Console. W r i t e L m e ("MyVar i able's value is not System.C o n s o l e . W ri te Li ne ("This prints if MyVariable 123 .") ; 123."); !=

} C omo los bloques de instrucciones pueden contener una sola instruccin, el siguiente cdigo tambin es valido:
i f (MyVariable = = 123) is 123.");

(
System. Console . W r i t e L m e ("MyVar iable ' s value

La instruccin switch
La instruccin switch evala una expresin y c omp ar a el valor de esa e x presin con varios casos. Ca da caso se asocia con una lista de instrucciones, que recibe el n omb re de seccin de switch. C# ejecuta la lista de instruccin a sociada con la seccin de sw itch que concuerde con el val or de la expresin.

135

La expresin usada como controlador de la instruccin switch se encierra entre los parntesis que siguen a la pal abra clave switch. La expresin va seguida por llaves y las secciones de sw itch estn entre las llaves.
switch MyVariable)

{
// aqu se colocan las secciones de switch

) La expresin usada en la instruccin switch debe evaluar uno de los siguien tes tipos:

sb y t e b y te sh o rt ushort int

uint long

ulong ch a r s t r in g

Tambi n se puede usar una expresin cuyo valor pueda ser convertido implci tamente a uno de los tipos de la lista anterior. Las secciones de sw itch empiezan con la pal abr a clave de C# case, seguida de una expresin constante. A esa expresin constante le siguen dos puntos y a continuacin escribimos la lista de instrucciones:
switch ( M yV a ri a b 1e )

{
case 123: System.Console.WriteLine("MyVariable break; == 123");

) C# evala la expresin en la instruccin switch y luego bu sca un bloque switch cuya expresin constante concuerde con el valor de la expresin. Si C# puede encontr ar un valor similar en una de las secciones de switch. la lista de instrucciones de la seccin c sw itch se ejecuta. Una instruccin switch puede incluir muchas secciones de switch. cada una con un caso diferente:
switch MyVariable)

136

case 12 3: System.Cons ol . Wr it eL n e("MyVariable break; case 12 4: Sy st em .C on sol.WriteLne("MyVariable break; case 12 5: Sy st em .C on sol.WriteLne("MyVariable break;

==

123");

==

124");

==

125");

} C# permite ag r up ar varias etiquetas de caso juntas. Si se tiene ms de un caso que necesite ejecutar la mi sma lista de instrucciones, se pueden combi nar las etiquetas de caso.
switch(MyVariable)

{
case 123: case 12 4: System.Con so l .W ri te L ne ("MyVariable break; case 12 5: S ys tem .C on sol.WriteLne("MyVariable

==

123

or

124");

==

125");

break; } Una de las etiquetas de caso puede ser la p al abr a clave de C# d e f a u l t . La etiqueta d e f a u l t puede incluir su p ropi a lista de instrucciones:
s wi t c h ( M y V a r i a b l e )

{ case 123:
== 123"); S ys tem .C on sol.WriteLine("MyVariable

break;
de f a u l t : S ys te m.C on sol.WriteLne("MyVariable != 123");

break; } La lista de instrucciones d e f a u l t se ejecuta cuando ninguna de las otras sec ciones de switch define alguna constante que concuerde con la expresin s w i t c h . La lista de instrucciones d e f a u l t es la parte que dice "Si no puedes encontrar algn bloque switch que concuerde, ejecuta este cdigo por defecto". El uso de la palabra clave d e f a u l t es opcional en sus instrucciones de s w i t c h .

Cmo usar instrucciones de iteracin para ejecutar instrucciones incrustadas


Las instrucciones de iteracin ejecutan instrucciones incrustadas varias ve ces. La expresin as oc ia da con la instruccin de iteracin controla el nmero de veces que se ejecuta una instruccin incrustada.

137

La instruccin while
La instruccin while ejecuta una lista de instrucciones incrustada siempre que la expresin while resulte ser true. La expresin booleana que controla la i nstruccin while se encierra entre los parntesis que siguen a la pal abr a clave while. T ra s los parntesis situamos las instrucciones que se ejecutarn si la expresin bool eana es true:
int MyVariable = 0; < 10)

while ( M y V a n a b l e

{
Syste m. Console . W r i t e L m e (My Va r i abl e ) ; M y Va riable + +;

} El cdigo escribe en la consola: 0 1

4 5

6
7
8

El cdigo incrustado en la instruccin whi le cont ina ejecutndose siempre que el valor de MyVariable sea menor que 10. Las instrucciones incrustadas escriben el valor de MyVariable en la consola y luego incrementan su valor. Cuando el valor de MyVariable alcanza 10, la expresin booleana MyVariable < 10 devuelve false y la lista de instrucciones i ncrust ada en la instruccin whi le deja de ejecutarse. La instruccin que sigue a la instruccin whi le se ejecuta en cuanto la e xpr e sin bool eana de la instruccin while devuelve false.

La instruccin do
La instruccin whi le ejecuta sus instrucciones incrustadas cero o ms veces. Si la expresin booleana u sad a en la expresin while devuelve false. ninguna de las instrucciones i ncrustadas se ejecuta:
int MyVariable = 100; < 10)

while(MyVariable

{
System.Consol . W n t e L m e (MyV a r i abl e ) ; MyVa ri a b 1e + + ;

138

Este cdigo no escribe n ad a en la consola porque la expresin bool eana us ada en la instruccin while, M y V a r i a b l e < 1 0. devuelve f a l s e la pri mera vez que se ejecuta. Como la expresin bool eana devuelve f a l s e inmediatamente, las instrucciones i ncrust adas n un ca se ejecutan. Si quiere as egurars e de que las ins trucciones i ncrust adas se ejecuten al menos una vez. puede us ar la instruccin d o . La instruccin d o va seguida de instrucciones incrustadas, que a su vez van seguidas de la p al ab ra clave w h i l e . Tr as ella va la expresin bool eana que cont rol a el nmero de veces que se ejecuta el bucle.
int MyVariable = 0; do

{
S ys te m. Co ns ol . Wr i t e L i n e ( M y V a r i a b l e ) ; MyVariable++;

}
while(MyVariable < 10);

Este cdigo escribe lo siguiente en la consola: 0 1


2

4
5

6
8

7 9

Las sentencias incrust adas siempre se ejecutan al menos una vez debido a que la expresin b ool eana se evala despus de que se ejecuten las instrucciones in cr us tadas , como se puede ver en el siguiente cdigo:
int MyVariable do = 100;

{
System.Consol.WriteLine (MyVariable) ; MyVariable++;

}
while(MyVariable < 10);

Este cdigo escribe lo siguiente en la consola:


100

La instruccin for
La instruccin f o r es la instruccin de iteracin ms potente. El cdigo de control de una instruccin f o r se divide en tres partes.

139

Un in icia d o r . que fija las condiciones iniciales de la instruccin de bucle

fo r .
Una condicin, que especifica la expresin bool eana que mantiene ej ecu t ndose la instruccin for. Un iterador, que especifica las instrucciones que se ejecutan al final de cada paso por las instrucciones incrustadas. La instruccin for empieza con la palabra clave for. seguida por parntesis, que contienen las instrucciones iniciadora, de condicin y de iteracin, todas sepa radas por puntos y coma. Las instrucciones incrustadas siguen a los parntesis. Obser ve el siguiente bucle simple for:
int MyVar ia bl e; or(MyVariable = 0; MyVariable < 10; M yV ar i a b 1e++)

{
System. Consol . W n t e L m e (MyVar iable ) ;

} El iniciador en este bucle for es la instruccin MyVariable = 0 . El iniciador slo se ejecuta una vez en un bucle for y se ejecuta antes de que las instrucciones i ncrustadas se ejecuten por primera vez. La condicion de este bucle for es la instruccin MyVariable < 10. La condicin en un bucle for debe ser una expresin booleana. Las instrucciones incrustadas de un bucle for se ejecutan mientras esta expresin booleana devuel ve true. Cuand o la expresin devuelve false. las instrucciones incrustadas dejan de ejecutarse. El iterador de este bucle for es la instruccin MyVariable++. El iterador se ejecuta despus de cada paso por las instrucciones incrustadas del bucle for. Si se pone toda esta informacin junta, se podr interpretar la instruccin como: "Fija el valor de M y V a r i a b l e igual a cero. Mi ent ras el val or de MyVar iabl e sea menor de 10. escribe el valor en la consola y luego a ument a el valor de MyVar iable". Estas instrucciones escriben lo siguiente en la consola: 0 1 }
4

El iniciador, la condicion y el iterador de un bucle for son opcionales. Si prefiere no usar alguna de estas partes, simplemente escriba un punto y coma sin

140

especificar la instruccin. El siguiente cdigo es. en buena lgica, equivalente al cdigo anterior:
int M y V a r i a b l e = 0; f o r (/ M y V a r i a b l e < 10; MyVariable++)

{
S y s t e m . C o n s o l . W r i t e L i n e ( M y V a r i a b l e );

} Este cdigo t ambi n es equivalente al cdigo original:


int MyVariable; = 0; MyVariable < 10; )

for (MyVariable

{
S y s t e m . C o n s o l . W r i t e L i n e ( M y V a r i a b l e ); M y V a ri able + + ;

} Hay que tener cui dado cuando se omita la parte de la condicin en un bucle

for. El siguiente cdigo es un ejemplo de los probl emas que pueden surgir si no
se incluy en condiciones:
int MyVariable; = 0; ; MyVariable++)

for(MyVariable

{
System.C o n s o l . W r i t e L i n e (MyVaria b l e ) ;

} Este cdigo se ejecuta hasta que MyVariable finalmente provoc a un error porque contiene un nmero demasi ado largo par a ser almacenado. Esto ocurre porque ninguna condicin del bucle for llega a devolver false. lo que permite a la v ariable au men ta r hasta super ar su lmite. Las condiciones que faltan devuel ven true en un bucle for. C om o la condicin en el cdigo ant er ior de ejemplo siempre es true. nunca devuelve false y la instruccin for nunca deja de ejecutar su instruccin incrustada. Las expresiones iniciadoras, de condicin y de iteracin pueden contener v a rias instrucciones, s eparadas por comas. El siguiente cdigo es vlido:
int int MyFirstVarable ; MySecondVariable; = 0;

f o r ( M y F i r s t V a r i a b l e = 0, M y S e c o n d V a r i a b l e M y F i r s t V a r a b l e < 10; M y F i r s t V a r i a b l e + + , M y S e c o n d V a r i a b l e + +)

{
System.Consol.WriteLine(MyFirstVariable);
S y s t e m .C o n s o l e .W r i t e L i n e ( M y S e c o n d V a r i a b l e ) ;

141

La instruccin foreach
Se puede us ar la instruccin foreach par a repetir varias veces los elemen tos de una coleccin. Las matrices de C # admiten la instruccin foreach v pueden usarse par a t rab aj ar fcilmente con cada elemento de la matriz. La instruccin foreach se usa escribiendo la pal abr a clave foreach se guida de parntesis. Estos parntesis deben contener la siguiente informacin: El tipo del elemento de la coleccin. Un nombre identificador p ar a un elemento de la coleccin. La pal abr a clave in. El identificador de la coleccin.

Tras los parntesis se colocan las instrucciones incrustadas. El listado 5.1 muestra la instruccin foreach en accin. Crea una matriz entera de cinco elementos y luego usa la instruccin foreach para acudir a cada elemento de la matriz y escribir su valor en la consola.
Listado 5.1. Usando la instruccin f o r e a c h c la s s L is tm g 5 ^ 1 s ta tic [] v o id M a i n ()

{
p u b lic

{
in t M yA rra y; [5] ; M y A r r a y = new i n t M y A r r a y [0 ] = 0; M y A r r a y [ 1 ] = 1; M y A r r a y [ 2 ] = 2; M y A r r a y [ 3 ] = 3; M y A r r a y [ 4 ] = 4;

f o r e a c h ( i n t A rra y E le m e n t m M yA rray) S y s te m . C o n s o l . W r i t e L m e ( A r r a y E l e m e n t ) ;

} } El i dent ifi cador A r r a y E l e m e n t es una v ar ia b le defini da en el bucle foreach. Contiene el valor de un elemento de la matriz. El bucle foreach recorre cada elemento de la matriz, lo que es muy til cuando se necesita t rab aj ar con cada elemento de una matriz sin tener que conocer el t amao de la misma.

Instrucciones de salto para moverse por el cdigo


Las instrucciones de salto saltan hacia una parte especfica del cdigo. S ie m pre se ejecutan y no estn controladas por ninguna expresin booleana.

142

La instruccin break
Ya vio la i n s t r uc ci n break en la seccin dedicada a las instrucciones switch. C# tambin permite u s ar la instruccin break para salir del bloque de i ns trucciones en el que se encuentre. Normalmente, la instruccin break se usa p ar a salir de un bloque de instrucciones iterativas:
int M y V a n a b l e = 0; while(MyVariable < 10)

{
System.Consol.WriteLine(MyVar i a b l e ) ; if(MyVariable == 5)

break;
MyVariable++;

}
System.Con so l .W ri te Li ne ("Out of the loop.");

El cdigo anterior escribe lo siguiente en la consola: 0 1


2

3 4 Out of the

loop.

El cdigo se interpreta: "Si el valor de MyVariable es 5. sal del bucle while". Cuand o se ejecuta la instruccin break. C# transfiere el control a la instruccin que sigue a las instrucciones incrustadas de la instruccin de itera cin. La instruccin break suele us ar se con bloques de instrucciones switch. while. do, for y foreach.

La instruccin continu
La instruccin continu devuelve el control a la expresin bool eana que controla un a instruccin de iteracin, como se puede ver en el siguiente cdigo:
int MyVariable; for (MyVariable = 0; MyVariable < 10; MyVariable + + )

{
if (MyVariable == 5) continu; System. C on sol.WriteLine(MyVariable ) ;

} El cdigo anterior escribe lo siguiente en la consola: 0 1

143

3 4 6 7
8

5 Este cdigo interpreta: "Si el valor de MyVariable es 5. contina hasta la siguiente iteracin del bucle for sin ejecutar ninguna otra instruccin i ncr us t a da". Por eso no aparece el 5 en pantalla. Cuand o el valor de MyVariable es 5. el control regresa a la parte superior del bucle for y la l lamada a WriteLine () nunca se produce en esa iteracin del bucle for. Al igual que la instruccin break. la instruccin continu suele usarse en los bloques de instrucciones switch. while, do. for y foreach.

La instruccin goto
La instruccin goto t ransfiere sin condiciones el control a una instruccin etiquetada. Puede etiquetarse cualquier instruccin de C#. Las etiquetas de ins trucciones son identificadores que preceden a una instruccin. Despus de una etiqueta de instruccin se colocan dos puntos. Un identifcador de etiqueta sigue a la p al abr a clave goto y la instruccin goto transfiere el control a la instruccin desi gnada por el identifcador de etiqueta, como mues tra el siguiente cdigo:
int MyVariable = 0; < 10)

w h 1 1e (MyVariable

f
System.Consol . W r i t e L m e (MyVa r i ab 1 e ) ; i f( MyVariab1e == 5) goto Done; MyVa riable + +;

}
Done: System.Consol.WriteLine ("Out of the loop".);

El cdigo anterior escribe lo siguiente en la consola: 0 1 2


4 Out of the loop.

Cuando el valor de MyVariable es 5. la instruccin goto se ejecuta v transfiere el control a la instruccin con la etiqueta Done. La instruccin goto siempre se ejecuta, independientemente de la instruccin de iteracin que pueda estar ejecutndose. Tambi n se puede u sar la p al ab ra clave goto en conjuncin con las etiquetas de caso en un a instruccin switch. en lugar de una instruccin break:

144

switch(MyVariable)

{
case 12 3 : System.Cons ol e. Wr it eL in e("MyVariable goto case 12 4; case 12 4 : System.Cons ol e. Wr it eL in e("MyVariable == 123");

==

124");

break; }

NOTA: Usar la instruccin g o to en muchos sitios puede hacer el cdigo confuso @ilegible. Lo mejor es evitar usar una instruccin g o to siempre que sea posible. Intente reestructurar el cdigo para no tener que recurrir al uso de una instncci g o to .

Cmo usar instrucciones para realizar clculos matemticos con seguridad


Y a ha visto cmo las pal abr as clave checked y unchecked permiten c on t rol ar el compo rt ami ent o de las condiciones de error en sus expresiones m a t e m ticas. Tambi n se pueden us ar estas pa la br a s clave como instrucciones par a controlar la seguridad de sus operaciones matemticas. Use las pal abr as clave antes de un bloque de instrucciones al que afecte la p a l ab r a reservada checked o unchecked. como en el siguiente cdigo:
checked

{
Intl = 2000000000; Int2 = 2000000000; IntlPlusInt2 = Intl + In 12; S y s t e m . C o n s o l . W ri te Li ne (I nt lP lu s In t2 );

Resumen
C# dispone de varios medios de cont rol ar la ejecucin del cdigo, dndole opciones p ar a ejecutar un bloque de cdigo ms de una vez o. a veces, ninguna vez. b as ndos e en el resultado de una expresin booleana. La instruccin i f ejecuta el cdigo una vez. pero slo si la expresin booleana que la a c o mp a a devuelve true. La instruccin if puede incluir una clusula else. que ejecuta un bloque de cdigo si la expresin booleana devuelve false. La instruccin switch ejecuta uno de los muchos bloques de cdigo pos i bles. C ad a bloque de cdigo viene precedido de una lista de instrucciones de caso.

145

C# evala la expresin de la instruccin switch y a continuacin busca una lista de instrucciones de caso cuyo valor coincida con la expresin e valuada en la instruccin switch. Las instrucciones while. do y for continan ejecutando el cdigo mientras la expresin booleana indicada sea t rue . C uan do la expresin booleana d evuel ve false. las instrucciones incrustadas dejan de ejecutarse. Las instrucciones while y for se pueden definir p ar a que sus expresiones booleanas devuelvan i nmediatamente false. lo que quiere decir que sus instrucciones incrustadas nunca llegan a ejecutarse realmente. La instruccin do, sin embargo, siempre ejecuta sus instrucciones incrustadas al menos una vez. La instruccin foreach pr opor ci ona un buen modo de recorrer repetida y rpidamente los elementos de una matriz. Puede ordenar a un bucle foreach que recorra repetidamente los elementos de una mat ri z sin conocer el t amao de la matriz o los elementos que la forman. La instruccin foreach prepara un i dentificador especial formado por el valor del elemento de una matriz durante cada iteracin del bucle foreach. Las instrucciones break. continu y goto afectan al flujo normal de una instruccin de iteracin, como while o foreach. La instruccin break sale del bucle iterativo, incluso si la expresin bool eana que controla la ejecucin del bucle sigue devolviendo true. La instruccin continu devuelve el control a la parte superior del bucle iterativo sin ejecutar ni nguna de las instrucciones incrustadas que la siguen. La instruccin goto siempre transfiere el control a la instruccin etiquetada. Puede a c o m pa ar sus operaciones mat emt icas con instrucciones checked o unchecked para especificar cmo quiere trat ar los errores mat emt icos del cdigo C#.

146

Cmo trabajar con mtodos


151

Los mtodos son bloques de instrucciones que devuelven algn tipo de valor cuando se ejecutan. Pueden ser llamados mediante el nombre y llamar a un m to do hace que las instrucciones del mtodo se ejecuten. Ya hemos visto un mtodo: el mtodo Main ( ) . Aunque C# permite poner todo el cdigo en el mtodo Main ( ) . probablemente quiera disear sus clases p ar a definir ms de un mtodo. El uso de mtodos mantiene el cdigo legible porque las instrucciones se colocan en bloques ms pequeos, en lugar de en un gran bloque de cdigo. Los mtodos tambin permiten t omar instrucciones que pueden ser ejecutadas varias veces y colocarlas en un bloque de cdigo que puede ser llamado todas las veces que haga falta. En este captulo, apr ender a crear funciones que devuelven datos y que no los devuelven. Aprender a p as ar par met ro s a los mtodos y la mejor maner a de es truc tur ar un mtodo par a hacer sus aplicaciones modulares.

La estructura de un mtodo
Como mnimo, un mtodo est compues to de las siguientes partes: Ti po dev uelto Nom br e del mtodo

149

Lista de parmetros C u er po del mtodo

NOTA: Todos los mtodos se encierran en na clase. Un mtodo no pue de existir fuei# una clase.
Los mtodos tienen otras partes opcionales, como las listas de atributos v los modificadores de mbito. Las siguientes secciones analizan los fundament os de un mtodo.

Tipo devuelto
Un mtodo comi enz a definiendo el tipo de datos que devolver cu an do se le llame. Por ejemplo, s uponga que quiere escribir un mtodo que s uma dos nmeros enteros y devuelve el resultado. En esc caso, escribir el tipo devuelto como int. C# permite escribir un mtodo que no devuelve nada. Por ejemplo, puede e s cribir un mtodo que simplemente escri ba algn texto en la consola, pero que no calcule ningn dato que deba devolver al cdigo que llam al mtodo. En ese caso, se puede usar la p al abr a clave void p ar a indicar al compilador de C# que el mtodo no devuelve ningn dato. Si se quiere devolver un valor de un mtodo se us a la p al ab r a clave return p a r a especificar el valor que debe devolverse. La p a l ab r a clave va seguida de una expresin que evala el tipo de valor que debe devolverse. Esta e xpresin puede ser un valor literal, una variable o una expresin ms compleja.

Nombre del mtodo


Todos los mtodos deben tener un nombre. Un n ombre de mtodo es un i dentificador y los nombres de mtodo deben seguir las reglas de nomencl atur a de cualquier identificador. Recuerde que los identificadores deben e mpez ar con una letra may scu la o minscul a o con un carcter subrayado. Los caracteres que siguen al primer carcter pueden ser una letra m ays cul a o minscula, un nmero o un subrayado.

Lista de parmetros
Se puede llamar a mtodos con los parmetros que se usan par a pas ar los datos al mtodo. En el ejemplo anterior, en el que un mtodo s uma dos nmeros enteros, se necesitara enviar al mtodo los valores de los dos nmeros enteros que se van a sumar. La lista de variables recibe el nombre de lista de parm etro s del mtodo. La lista de par met ros del mtodo a parece entre parntesis y sigue al nombre del

150

mtodo. Cad a par met ro de la lista de par met ros est separado por u na coma e incluye el tipo del p a r me tr o seguido p or su nombre. Tambi n se puede prefijar los p ar met ro s de la lista de p ar met ros con modi ficadores que especifican cmo se usan sus valores dentro del mtodo. Veremos estos modificadores ms adelante en este mi smo captulo. Se pueden definir mtodos que no reciben ningn parmetro. Si se quiere utili zar uno de estos mtodos, ba st a con dejar vacos los parntesis. Y a hemos visto esto en los mt odos M a i n ( ) escritos. Tambi n se puede colocar la p al abr a clave v o i d entre los parntesis p a r a especificar que el mtodo no acept a parmetros.

Cuerpo del mtodo


El cuerpo del mt odo es el bl oque de i nstrucciones que compone el cdigo del mtodo. El cuerpo del mtodo est entre llaves. La llave de a pe r tu ra se incluye tras la lista de par met ros del mtodo y la llave de cierre se coloca detrs de la ltima instruccin del cuerpo del mtodo.

Cmo llamar a un mtodo


P a ra llamar a un mtodo, se escribe su nombre en el lugar donde debera ej ecut arse el cdigo de ese mtodo. Despus del n ombre del mtodo se escriben dos parntesis, como se muest ra en el listado 6.1. Como en todas las instrucciones de C#, la instruccin de l lamada al mtodo debe t ermi nar con un punt o y coma.
Listad o 6.1. Llamar a un mtodo simple class Listing6_l

{
public static void Main()

{
Listing6 1 MyObject;

MyObject = new L i s t i n g 6 _ l ( ); M y O b j e c t .CallMethod ( );

}
void CallMethod( ) f rom CallMethod( ) !" ) ;

{
System.Consol.WriteLine("Helio

} }

NOTA: Necesita las instrucciones de Main () que crean u nuevo objeto L i s t i h g 6 _ l antes de poder llamar a ios mtodos del objeto.

151

Si el mtodo se define con una lista de par met ros, sus valores deben ser especificados en el momento de llamar al mtodo. Debe especificar los parmetros en el mi smo orden en que son especificados en la lista de p ar met ro s del mtodo, como m ues tra el listado 6.2.
Listado 6.2. L l a m a d a a un m t o d o c o n un p a r m e t r o class Listng6 2 static void M a i n ( )

I
public

{
int Mylnteger; Listingt 2 MyObject; MyOb^ect = new L i s t m g c 2 ( ); M y O b j e c t .C a l l M e t h o d (2); Mylnteger = 3 ; MyOb ject.CallMethod(Mylnteger) ;

}
void C a l l M e t h o d (int Integer)

{
System.Consol.WriteLine (Integer) ;

} } C ua nd o compile y ejecute el listado 6.2 obtendr un resultado igual al de la figura 6.1.


c a C:\W irH D O W S\System 32\cmd!eHe~^^^^^
C : \ > L j ; ; t iriyf) 2.exe

3
C:\>

Figura 6.1. U n a s i m p l e l l a m a d a a un m t o d o d e v u e l v e e s t e r e s u l t a d o .

Esto es debido a que el mtodo Main ( ) llama a CallMethod ( ) dos veces: una con el valor 2 y otra con el valor 3. El cuerpo del mtodo CallMethod () escribe el valor sumi nist rado en la consola.

152

Cuand o sumi nist ramos un valor par a el par met ro de un mtodo, podemos usar un valor literal, como el 2 del listado 6.2 o suministrar una variable y usar su valor, como en la variable Mylnteger del listado 6.2. Cuand o se llama a un mtodo. C# toma el valor especificado y asigna esos v alores a los par met ros que se usan en el mtodo. Durante la pri mera llamada a CallMethod ( ) en el listado 6.2. el literal 2 se usa como el par met ro del mt odo y el p ar me tr o Integer del mtodo recibe el valor 2. Durant e la s eg un da llamada a CallMethod ( ) en el listado 6.2. la variable Mylnteger se usa como el par met ro del mtodo y el par met ro Integer del mtodo recibe el valor de la variable Mylnteger: 3. Los parmet ros que se especifican cuando se llama a un mtodo deben c on cor dar con los tipos especificados en la lista de parmetros. Si un par met ro de la lista de parmetros del mtodo especifica un tipo int. por ejemplo, los parmetros que le pase debern ser de tipo int o de un tipo que pueda ser convertido a int. Cual qui er otro tipo produce un error al compi lar el cdigo. C# es un lenguaje de tipo seguro, lo que significa que se c om p ru e ba la legali dad de los tipos de variables al compilar el cdigo C#. Por lo que respecta a los mtodos, esto significa que deben especificarse los tipos correctos cuando se especifican parmetros. El listado 6.3 muestra los tipos correctos durante la especificacin de parmetros:
L istado 6.3. S eguridad de tipos en listas de parmetros de mtodo class Listing6 3

{
public static void Main()

{
Listmgc 3 MyObject;

MyObject = new L i s t m g 6 _ 3 () ; MyObject.CallMethod("a s tr in g" );

}
void C a l l M e t h o d (int Integer)

{
S y s t e m . C o n s o l .W ri te Li ne (I nt eg er );

} } Este cdigo no se compila, como puede verse en la figura 6.2. El compi lador de C# emite estos errores porque el mtodo CallMethod ( ) se es t e j e c u t a n d o con un p a r m e t r o de c a d e n a y la lista de p a r m e t r o s CallMethod ( ) especifica que se debe us ar un nmero entero como parmetro. Las cadenas no son nmeros enteros ni pueden ser conv ertidas a nmeros enteros y esta discordancia hace que el compi lador de C# genere errores. Si el mtodo devuelve un valor, debe declararse una variable que contenga el valor devuelto. La variable u sada par a esta operacin se coloca antes del nombre

153

del mtodo y un signo igual s epa ra el identifieador de la variable y el nombre del mtodo, como se ve en el listado 6.4.
C:\WINDOWS\System32\cmd.exe

HY,

.=JnjxJ

C : \ k s c Ciassl.cs Compilador de Microsoft <K> Uisual GB -NET versin V.00.9466 para Microsoft <R) .NET Framework uersin 1.0.3705 CC> Microsoft Microsoft Corporation 2001. Reservados todos los derechos. C l a s s i .o s <8,3>: error CS1502: La mejor coincidencia de mtodo sobrecargado para 'Listing6__3 .CallMetliodCintV tiene algunos argumentos no vlidos Classi -e s <823>: error CS1503: Argumento '1': no se puede convertir de string' a ' int '

Figura 6.2. La llamada a un mtodo con un tipo de datos no vlido produce errores de compilacin.

Listado 6.4. Devolucin de un valor de un mtodo c 1 ass Listingt 4 f public static void Main ()

(
L i s t m g t 4 MyOb^ect; int ReturnValue; MyObject = new L i s t m g c _ 4 ( ); ReturnValue = My Ob ] e c t . A d d l n t e g e r s (3, 5); System. Con sol. W r i t e L m e (Re t ur nVa le ) ;

)
int Addlntegers(int Integerl, int Integer2)

{
int Sum; + Integer2;

Sum = Integerl return Sum;

} } En este cdigo suceden varias cosas: Se declara un mtodo llamado Addlntegers ( ) . El mtodo tiene dos parmetros en su lista de parmetros: un numero entero llamado Integerl y otro numero entero llamado Integer2.

154

El cuerpo del mtodo Addlntegers () su ma los valores de los dos parmet ros y asigna el resultado a una variable local llamada Sum. Se devuelve el val or de Sum. El mt odo Main ( ) llama al mtodo AddIntegers ( ) con los valores 3 y 5. El valor devuelto del mtodo Addlntegers () se coloca en una variable local llamada ReturnValue.

El valor de ReturnValue se escribe en la consola.

La figura 6.3 contiene los resultados del progr ama que aparece en el listado 6.4.
ca

C:\WINDOWS\System32\cmd.exe

L zJ
Figura 6.3. Los datos se devuelven de un mtodo y se muestran en la ventana de la consola

Tipos de parmetros
C# permite cuatro tipos de par met ros en una lista de parmetros: Parmet ros de entrada Parmetros de salida Parmet ros de referencia Matrices de parmet ros

Parmetros de entrada
Los p a r m etro s de entrada son par met ros cuyo valor es enviado al mtodo. Todos los par met ros que se han usado hasta ahor a han sido par met ros de entra-

155

da. Los valores de estos par met ros de entrada se envan a la funcin, pero el cuerpo del mtodo no puede c a mb i ar per manent ement e sus valores. El listado 6.4 del anterior ejemplo define un mtodo con dos p ar met ro s de entrada: Integerl y Integer2. Los valores de estos par met ros se i nt rodu cen en el mtodo, que lee sus valores y hace su trabajo. Los parmetros de entrada se pasan a los mtodos por valor. Bsicamente, el mtodo ve una copia del valor del parmetro, pero no se le permite ca mb ia r el valor propor ci onado por la parte que realiza la llamada. En el listado 6.5 se puede ver un ejemplo.
Listad o 6.5. Cmo modificar copias de parmetros de entrada c 1a s s Listing 5

{
public static void M a i n ( )

{
int Mylnteger; L i s t m g c 5 MyObject; MyOb j ect = new L i s t m g o 5 () ; Mylnteger = 3 ; MyObject.CallMethod(Mylnteger); Sy st em .C on so l . W r i t e L i n e ( M y l n t e g e r ) ;

}
voi d C a l l M e t h o d (int Integerl)

i Integerl = 6;
System.Consol.WriteLine (Integerl) ;

En el listado 6.5. el mtodo Main ( ) establece una variable entera llamada Mylnteger y le asigna el valor de 3. A continuacin llama a MyMethod () con Mylnteger como parmet ro. El mtodo CallMethod ( ) establece el v a lor del par met ro en 6 y luego escribe el v alor en la consola. Cuand o el mtodo Ca 1 1Method () se devuelve, el mtodo Main () continua y escribe el valor de Mylnteger. Si ejecuta este cdigo, el resultado debera parecerse al de la fi gu ra 6.4. Este resultado se produce porque el mtodo CallMethod ( ) modifica su copia del par met ro de entrada, pero esa modificacin no afecta al valor del mtodo original propor ci onado por Main ( ) . El valor de Mylnteger sigue siendo 3 despus de que regrese el mtodo CallMethod () . debido a que CallMethod ( ) no puede ca mb ia r el valor del p ar met ro de entrada del ele mento que hace la llamada. Slo puede ca mbi ar el valor de su copia del valor.

Parmetros de salida
Los parm etros de sa/ida son parmetros cuyos v alores no se establecen cuando se llama al mtodo. En su lugar, el mtodo establece los v alores y los devuelv e al

156

elemento que hace la l lamada mediante el p ar me tr o de salida. Suponga, por ejemplo, que quiere escribir un mtodo que cuente el nmero de registros de una t abl a de una base de datos. S uponga que tambin quiere especificar si la o p er a cin se realiz satisfactoriamente. (La operacin puede no realizarse si, por ejem plo, la t abl a de bases de datos no est disponible.) Por tanto, queremos que el mtodo devuelva dos instancias de informacin: Un cont ador de registros. Un indicador de xito de operacin.
X

Figura 6.4. Demostracin de parmetros de entrada con la funcin C a l l M e t h o d ().

C# slo permite a los mtodos devolver un valor. ,Qu hacer si queremos que devuelva dos instancias de i n f or ma c i n9 La respuest a est en el concepto de p ar met ro de salida. Puede hacer que su mt odo devuelva el indicador de xito de la oper aci n como un valor booleano y especificar el recuento de registros como un par met ro de salida. El mtodo a l m a cena el recuento de registros en una variable de salida, cuyo valor es recogido por el elemento que hizo la llamada. Los par met ros de salida se especifican en listas de par met ros con la p al abr a clave o u t . La p al ab ra clave o u t debe preceder al tipo de par met ro en la lista de parmetros. C uand o se llama a un mtodo con un p ar m et ro de salida, se debe dec la rar una variable que contenga ese valor, como se ve en el listado 6.6.
Listad o 6.6. Cmo trabajar con parmetros de salida c la s s L is tin g 6 ^ 6 s ta tic v o id M a i n ()

{
p u b lic

{
in t M y ln te g e r;

157

Listmg6

6 MyObject;

MyObject - new L i s t i n g 6 _ 6 (); MyOb j ect.CallMethod (out Mylnteger) ; Sy s t e m . C o n s o l e .WriteLine (Mylnteger);

}
voici CallMethod (out int Integerl)

(
Integerl = 7;

} ) El listado 6.6 define un mtodo llamado CallMethod () . que define un p ar m et r o de salida entero llamado Integerl. El cuerpo de! mtodo establece el valor del parmet ro de salida en 7. El mtodo Main ( ) declara un entero llamado M y l n t e g e r y lo us a como p a r m e t r o de sal ida p a r a el mt odo C a l l M e t h o d ( ) . C u a n d o C a l l M e t h o d ( ) se d e v u e l v e , el v a l o r de Mylnteger se escribe en la consola. La figura 6.5 contiene el resultado de estas aplicaciones de prue ba de parmetros.
C:\WINDOWS\System32\cmdexe
C :\>List ing6 _ 6 .exe 7 C:\>_
X

y.
Figura 6.5. Un parmetro de salida devuelve el valor apropiado.

Debe usarse la palabra clave out dos veces por cada parmetro: una vez cuando se declara el par met ro y otra vez cuando se especifica el p ar met ro de salida al llamar al mtodo. Si se olvida la pal abra clave out al llamar a un mtodo con un parmetro de salida, se obtienen los siguientes errores del compilador:
Listing6-6.cs (9, 6): error CS 1502: La me j o r coincidencia de mtodo sobrecargado para 'Li st i n g 6 _ 6 .C a l l M e t h o d (out int)' tiene algunos argumentos no validos Listing6-6.cs (9,2 6) : error CS1503: Argumento '1' : no se puede convertir de 'int' a 'out int'

158

Cualquier valor a signado a variables usadas como par met ros de salida antes de que se llame al mtodo se pierde. Los valores originales se sobrescriben con los valores que les asign el mtodo.

Parmetros de referencia
Los p a r m etro s de referencia proporcionan valores por referencia. En otras pal abras, el mtodo recibe una referencia a la variable especificada cuando se l lama al mtodo. Piense en un p ar me tr o de referencia como en una variable de entrada y de salida: El mtodo puede leer el valor original de la variable y tambin modificar el valor original como si fuera un p ar met ro de salida. Los par met ros de referencia se especifican en listas de par met ros con la p al abr a clave ref . La p al abr a clave ref debe preceder al tipo del par met ro en la lista de parmetros. C uando se llama a un mtodo con un par met ro de referen cia. se debe declarar una variable p ar a que contenga el valor del p ar met ro de referencia, como se ve en el listado 6.7.
Listado 6.7. Cmo trabajar con parmetros de referencia class Listmgc_7 static void Main()

{
public

{
int Mylnteger; Listing6_7 MyObject; MyObject = new Listing6_7 () ; Mylnteger = 3; S y s t e m . C o n s o l e . Wr it eL in e( My ln te g er ); M y O b j e c t .CallMethod (ref Mylnteger) ; S y s t e m . C o n sol . Wr it eL in e( My ln te g er );

}
void C a l l M e t h o d (ref = 4; int Integerl)

{
Integerl

} } El mtodo CallMethod ( ) del listado 6.7 us a un p ar met ro de referencia llamado Integerl. El cuerpo del mtodo establece el valor del p ar met ro de re fer enci a en 4. El mt od o M a i n ( ) d e c l a r a una v ar ia b le en te r a l lamad a Mylnteger y le asigna un valor de 3. Escribe el valor de Mylnteger en la consol a y luego lo us a como el p a r me tr o del mtodo CallMethod (). Cuando CallMethod ( ) se devuelve, el val or de Mylnteger se escribe en la consola una segunda vez. Si ejecuta el cdigo del listado 6.7 debera obtener los valores que aparecen en la figura 6.6.

159

0A C:\WINDOWS\System32\cmd.exe

w eM iu.m L iflfea /-.

JO ]

C : \ > L i a t inc/6 7 . ex e O 4 C:\>_

Figura 6.6. Un parmetro de referencia cambia su variable directamente.

La segunda lnea lee 4 porque la sintaxis del p ar met ro de referencia permite al mtodo c ambi ar el valor de la variable original. Este es un cambio respecto al ejemplo de p ar met ro de ent rada del listado 6.5. Debe usarse la palabra clave r e f dos veces par a cada parmetro: una vez cuando se declara el par amet ro en la lista de par met ros y otra vez cuando se especifica el p ar met ro de referencia al llamar al mtodo.

Matrices de parmetros
Los mtodos suelen escribirse para recibir un nmero especifico de parmetros. Un mtodo con una lista de tres par met ros siempre espera ser llamada con tres par met ros, ni ms. ni menos. Sin embargo, a veces puede ocurrir que un mtodo no conozca cuntos par met ros debe acept ar al ser diseado. Puede escribir un mtodo que acepte una lista de cadenas que especifiquen los nombres de los regis tros que debern borr ars e del disco. .Cuntas cadenas debe permitir el mtodo . Para ser flexible, el mtodo debe disearse de man er a que el i nvocador pueda especificar las cadenas que necesita. Esto hace que llamar al mtodo sea un poco ms flexible porque el elemento que realiza la llamada ah or a puede decidir c u a n tas cadenas deben p as ar se al mtodo. Sin embar go cmo escribiremos la lista de par met ros de la lista cuando el mtodo no conoce cuntos p ar met ro s le sern pasados. Las matrices de parmet ros resuelven este problema de diseo ya que permiten especificar que el mtodo acepte un nmero variable de argumentos. La matriz de par met ros de la lista de par met ros se especifica usando la p al abr a clave de C# p a r a m s . seguida del tipo de variable que deber p ropor ci onar el llamador La especificacin de tipos va seguida de corchetes, que a su vez van seguidos del identificador de la matriz de parmetros, como se ve en el listado 6.8.

160

Listad o 6.8. C mo trabajar con matrices de parmetros class Listing6_8

{
public static void M a i n ( ) MyObject;

{
Listing6_8

MyObject = new L i s t i n g 6 _ 8 (); M y O b j e c t .C a l IMethod (1) ; M y O b j e c t .C a l l M e t h o d (1, 2) ; M y O b j e c t .C a l I M e t h o d (1, 2, 3) ;

void

CallMethod(params

int [] ParamArray)

{
System. Consol . W n t e L m e ("------ " ) ; System.Consol.WriteLine ("CallMethod () ") ; S y s t e m . C o n s o l . W r i t e L i n e ("------ "); foreach(int ParamArrayElement in ParamArray) S y s t e m . C o n s o l . W r i t e L i n e (Pa r a m A r r a y E l e m e n t );

} } En el listado 6.8. el mtodo CallMethod ( ) est escrito p ar a acept ar un nmero variable de enteros. El mtodo recibe los p ar met ro s en for ma de matriz de nmeros enteros. El cuerpo del mtodo usa la instruccin foreach para iterar la matriz de par met ros y escribe cada elemento en la consola. El mtodo Main ( ) llama al mtodo CallMethod ( ) tres veces, cada vez c o n un n u m e r o de a r g u m e n t o s d i f e r e n t e . E s t o es p o s i b l e s l o p o r q u e CallMethod ( ) se declara con una matriz de parmetros. La figura 6.7 indica que todos los par met ros fueron pas ados intactos al mtodo.
c -A C:\WINDOWS\System32\cmd.exe
C :\ > 1 ,is t ing6 0 .e xe C a l IMethodO

CdllMethodC

Id

Figura 6.7. La palabra clave params permite cualquier nmero de parmetros.

161

Puede usar una matriz de par met ros en su lista de par met ros de mtodo. Puede c ombi nar una matriz de par met ros con otros par met ros en la lista de par met ros de mtodo. Sin embargo, si usa una matriz de p ar met ros en una lista de par met ros de mtodo, debe especificarla como el ltimo par met ro de la lista. No se puede usar las pal abr as clave o u t o r e f en una matriz de parmetros.

Sobrecarga de mtodos
C# permite definir varios mtodos con el mi smo nombre en la mi sma clase, siempre que esos mtodos tengan listas de par met ros diferentes. Esta operacin se conoce como so brec a rg a r el nombre del mtodo. Obser ve el ejemplo en el listado 6.9.
Listado 6.9. Cmo trabajar con mtodos sobrecargados class Listing6_9 static void M a i n () 9 MyObject;

{
public

{
Listmgc

MyObject = new L i s t i n g 6 _ 9 (); M y O b ] e c t . A d d (3 , 4) ; M y O b j e c t . A d d (3.5, 4.75);

}
void Add ( m t Integerl, int Integer2)

{
in t S u m ; S ys te m. Co ns ole.WriteLine("adding Sum = Integerl + Integer2; S y s t e m . C o n s o l e . W r i t e L i n e (Sum) ; two i nt egers");

}
void Add(double Doublel, double Double2)

(
double Sum; two doubl es ") ;

Sy st em .C on sole.WriteLine("adding Sum = Doublel + Double2; S y s t e m . C o n s o l e . W r i t e L i n e (Sum) ;

El listado 6.9 i mplementa dos mtodos A d d ( ) . Uno de ellos t oma dos n m e ros enteros como par met ros de entrada y el otro toma dos dobles. Como las dos implementaciones tienen diferentes listas de par met ros . C# permite que los dos

162

mt odos Add () coexistan en la mi sma clase. El mtodo Main ( ) llama al m t o do Add ( ) dos veces: u na vez con dos par met ros integrales v otra con dos v al o res de punto flotante. Como puede ver en la figura 6.8, los dos mtodos se ejecutan satisfactoriamente, proc es ando los datos correctos.
c< v C:\WINOOWS\System32\cmd.exe
C : \ >I> i s t :i n a d d i r x f t;w o (> 9 . e x e inteqer'

'

?
addinq l;no

8,25
C:\>

doubles

y.
Figura 6.8. El mtodo sobrecargado suma nmeros enteros y dobles.

Cuand o el compi lador de C# encuent ra una llamada a un mtodo que tiene ms de una implementacin, ex ami na los par met ros usados en la l lamada y lla ma al mtodo con la lista de p ar met ro s que mejor concuerde con los par met ros usados en la llamada. En la primera llamada a Add ( ) se usan dos nmeros e n t e r o s . E n t o n c e s , el c o m p i l a d o r de C # e m p a r e j a e s t a l l a m a d a con la i mplement aci n de Add ( ) que toma los dos p ar met ros de ent rada enteros p o r que los par met ros de la l lamada c oncuerdan con la lista de par met ros que tiene los nmeros enteros. En la segunda llamada a Add ( ) se usan dos dobles. El compi lador de C# entonces empar ej a esta l lamada con la i mplementacin de Add ( ) que toma los dos par met ros de ent rada dobles porque los par met ros de la l lamada concuerdan con la lista de p ar met ro s que tiene los dobles. No todos los mtodos sobre carg ado s necesitan u sar el mismo nmero de pa r m et ros en su lista de parmetros, ni todos los p ar met ro s de la lista de p ar met ros tienen que ser del mismo tipo. El nico requisito que C# exige es que las funciones tengan diferentes listas de parmet ros. Una versin de una funcin so bre carg ada puede tener un entero en su lista de par met ro s y la otra versin puede tener tipos de datos como string, long y character en su lista de parmetros.

Mtodos virtuales
P ar a proseguir con el t ema de los mtodos virtuales, hay que co mprender el concepto de herencia. La herencia b a s a una clase en otra ya existente, aadiendo

163

o quitando f uncionalidad segn se necesite. En las siguientes secciones e x a m i n a remos cmo se crean y se usan los mtodos virtuales.

Mtodos sobrecargados
Para e mpez ar esta seccin, const rui r un ejemplo de clase llamado Books. Esta clase contiene dos mtodos llamados Title y Rating. El mt odo Tit le devuelve el nombre de un libro y el mt odo Rating devuelve un a cadena indi cando el n m er o de estrellas con que ha sido calificado el libro en cuestin. En el listado 6.10 se recoge el cdigo completo de su aplicacin. Escrbalo en su editor de texto preferido y complelo como hizo antes.
Listad o 6.10. Cmo mostrar la inform acin del ttulo y la puntuacin de un libro con las siguie ntes clases using System; namespace BookOverride Book stnng Title () Book";

{
class

{
public

{
return "Programming Rating()

}
public stnng

{
return "5 Stars";

} }
class Classl void M a i n (s t r i n g [ ] args)

{
static

{
Book be = new Book ( ); C o n s o l . W n t e L m e (be.Title ( ) ); C o n s o l . W r i t e L i n e ( b e . R a t i n g ());

Antes de ejecutar este prog rama, repselo rpidamente. C omo puede o b s e r var. un a clase contiene el mtodo Main ( ) . Este mtodo es donde se inicializa una instancia de la clase BookOverride. que contiene los mtodos Title y

Rating.
Despus de inicializar una instancia, se llama a los mtodos Title y Rating y se escribe la salida en la consola. El resultado puede verse en la figura 6.9.

164

Figura 6.9. El ttulo y la puntuacin de su libro aparecen como se esperaba.

A continuacin, s obre cargue el mtodo Title creando una clase ba sa d a en la clase Book. Para crear una clase ba sa d a en otra clase (y que por t anto p er mi te s ob re car ga r mtodos), simplemente declare una clase de la for ma habitual y p on ga a continuacin del nombre de la clase dos puntos y el no mbre de la clase en la que quiere que se base. A a da el cdigo del listado 6.11 a la aplicacin.
L istad o 6.11. Cmo s o b recargar m todos derivando la clase Book class Wiley : Book

{
new public string Title ( ) "C# Bible";

{
return

} } Este cdigo crea una clase Wiley que hereda la clase Book. Ahor a puede p a r a cr ear un nuevo mtodo pblico llamado Title. Como ya se ha asignado a este mt odo el mi smo n ombre que al definido en la clase Book, se s obrecarga el m t o d o Title aunque sigue di sponiendo de acceso a los otros mi embros dentro de la clase Book.

Ahor a que ha s o b re c ar ga d o el mt odo Title, debe c a m b i a r el mtodo Main ( ) p ar a us ar su nueva clase. Cambi e su mtodo Main ( ) como se m u e s tra en el listado 6.12.

165

Listad o 6.12. Cmo modificar el mtodo Main() para sobrecargar una clase statxc void M a i n (string [] args)

{
Wiley be = new Wiley() ; C o n s o l . W r i t e L i n e ( b c . T i t l e ()); Consol.WriteLine ( be .R at in g( ) );

} En su mtodo Main(). cambie la variable be p ar a crear la nueva clase Wi ley. Como h ab r adivinado, al llamar al mtodo Title. el titulo del libro cambi a de Programming Book a C# Bible. Fjese en que t odav a tiene acceso al mt od o Rating. que fue definido originalmente en la clase Book. La s obrecarga de mtodos dentro de una clase base es una excelente manera de ca mb ia r la funcionalidad especifica sin grandes probl emas

Resumen
C# permite escribir mtodos en sus clases de C#. Los mtodos pueden a yuda r a div idir el cdigo en partes fciles de entender y pueden brindar un lugar nico en el que al ma c ena r codigo que puede ser llamado varias veces. Las funciones pueden recibir parmetros. Los par met ros de entrada contie nen valores que han sido p as ados a los mtodos, pero sus valores no pueden cambiar. Los parmet ros de salida tienen valores que les son asignados por un mtodo y el valor asi gnado es v isible par a el elemento que hace la llamada. Los par met ros de referencia contienen v alores que pueden ser proporcionados dentro de la funcin y ademas, su valor puede ser modificado por el mtodo. Las m a t r i ces de par met ros permiten escribir mtodos que toman un nmero v ariable de argumentos. C# tambin permite s obr e ca rga r mtodos. Los mtodos s obrecargados tienen el mismo nombre pero diferentes listas de parmetros. C# usa los par met ros propor ci onados en una llamada p a ra determinar qu mtodo debe inv ocar cuando se ejecute el cdigo.

166

Agrupacin de datos usando estructuras


C# permite a g r u p a r las variables en estructuras. Al definir una estructura p a r a los datos, todo el g rup o puede ser proces ado con un solo nombre de es tru c tura, sin i mport ar el nmero de variables que contenga la estructura. El uso de un a sola es tructur a facilita la mani pul aci n de un conjunto de variables, en lugar de tener que seguir la pi st a de cada variable p or separado Una es tructur a puede contener campos, mtodos, constantes, constructores, propiedades, indizadores, operadores y otras estructuras. Las e st ructuras de C# son tipos de valor, no tipos de referencia. Esto significa que las variables de e st ruc tur a contienen directamente los valores de las e st ru ctu ras, en l ugar de mantener u na referencia a un a es tructur a que se encuent ra en otra parte de la memoria. Al gunas de las variables declaradas en el cdigo C,U pueden tener una relacin lgica con otras variables ya declaradas. Suponga, por ejemplo, que quiere escri bir un cdigo que t rabaje con un punt o de la pantalla. Puede declarar dos v ar ia bles p ar a describir el punto:
int int XC oo rdinateOfPoint; YCoordinateOfPoint;

El punt o tiene dos valores, la coor denada x y la coor denada y, que funcionan j u n ta s p ar a describir el punto.

169

Aunque puede escribir el cdigo C# de esta manera, es bast ant e pesado. Los dos valores deben poder usarse en cualqui er cdigo que quiera t ra ba j ar con el punto. Si quiere que un mtodo trabaje con el punto, tendr que p a s ar los valores uno a uno:
void Wor k W i t h P o m t ( int /.Coordnate, int '/Coordnate) ; void S e t M e w P o m t (out m t (Coordnate, out int YCoordinate) ;

La situacin resulta incluso mas complicada cuando varias variables t rabajan juntas par a describir una sola entidad. Por ejemplo, un empleado en una base de datos de recursos humanos puede tener variables que representen un nombre de pila, un apellido, una direccin, un numero de telfono y un salario actual. C ont ro lar todas estas variables por separado y asegurarse de que todas se usan como un g ru po puede volverse complicado.

Cmo declarar una estructura


Los contenidos de una estructura se declaran usando la pal abra clave struct. Para dar nombre a una est ructura use un identificador despus de la pal abr a clave struct. La lista de variables que forman la est ructura se encierra entre llaves a cont inuacin del identificador de la estructura. Las declaraciones de mi embro de la est ructura suelen llevar antepuesta la pal abr a clave public para avisar al compi lador de que sus valores deben ser pblicamente accesibles a todo el cdigo de la clase. Ca da declaracin de mi embro termina con un punto y coma. La declaracin de una e st ructur a que defina un punto puede parecerse a lo siguiente:
struct Pomt mt mt X; Y;

{
public public

} En el ejemplo anterior, los mi embros de la est ructura. X e Y. tienen el mismo tipo. Sin embargo, esto no es obligatorio. Las est ructur as tambin pueden estar formadas por variables de distintos tipos. El ejemplo anterior del empleado puede present ar este aspecto:
struct Employee s t n n g FirstName; s t n n g LastName; s t n n g Address; string City; s t n n g State; ushort ZIPCode; decimal Salary;

{
public public public public public public public

170

Como con todas las instrucciones de C#. slo puede declararse una est ructura desde el interior de un a clase.

Los valores iniciales de los mi embros de la e st ruc tur a siguen las reglas de inicializacin de valores descritas en un captulo anterior. Los valores se inicializan con alguna representacin del cero y las cadenas se vacan. C# no permite inicializar mi embros de es tru ct ur as en el moment o de declararse. Obs er ve el error en el siguiente cdigo:
struct Point

{
public int X = 100; public int Y = 200;

} Est a declaracin p roduc e estos errores del compilador:


error campo error campo CS0573: 'Point.X': no se permiten de instancia en las estructuras CS0573: 'Point.Y': no se permiten de instancia en las estructuras inicializadores inicializadores de de

Puede u s ar un mtodo especial llamado co nstru cto r p ar a inicializar miembros de e st ructur as con valores distintos de cero. M s adelante, en este mi smo c a p t u lo, se e xa mi na rn los constructores.

Cmo usar estructuras en el cdigo


Despus de habe r definido la estructura, puede u s ar su identifcador como un tipo de variable, igual que si fuera un tipo int o long. Indique el identifcador de la estructura, seguido de algn espacio en blanco y del identifcador de la variable de estructura:
Point MyPoint;

Esta declaracin declara una variable l lamada MyPoint cuyo tipo es el de la estructura Point. Se puede usar esta variable igual que cualquier otra variable, incluso dentro de e xpresiones y como p a r m et ro de un mtodo. El acceso a cada mi embro de la es tructur a resulta tan sencillo como escribir el nombre del identifcador de la variable de la estructura, un punto y a continuacin el mi embro de la estructura. El listado 7.1 mues tra cmo se puede u sar una es t ru ct ur a en el cdigo.

171

Listad o 7.1. A cce so a miembros de la estructura class Listmg7 Point int X; int Y; 1

{
struct

{
public public

}
public static void M a i n ( )

{
Point MyPoint;

M y P o m t . X = 100; MyPoint.Y = 200; S y s t e m . C o n s o l . W ri te Li ne (M yP oi nt . X) ; S y s t e m . C o n s o l . W ri te Li ne (M yP oi nt . Y) ;

} } El resultado de este ejemplo debera ser el siguiente:


100
2 0 0

Se puede asignar una variable de est ructura a otra, siempre que las estructuras sean del mismo tipo. Cuando se asigna una variable de est ructura a otra. C# asigna el valor de la variable de est ructur a que aparece antes del signo igual a los valores correspondientes de la es tructur a que aparece despus del signo igual, como se puede obs er var en el listado 7.2.
L istado 7.2. Asignacin de una variable de estructura a otra class Listing7_2 Point int X; int Y;

{
struct

{
public public

}
public static void M a i n ( ) M yF i r s t P o i n t ; MySecondPoint; 100; 100; 2 00; 200;

{
Point Point

MyFirstPoint.X = M y F i r s t P o i n t .Y = M y S e c o n d P o i n t .X = M y S e c o n d P o i n t .Y =

172

S ystem.C o n s o l e . W r i t e L in e( My Fi rs tP oi nt .X ) ; Sy st em . C o n s o l e . W r i t e L i n e ( M y F i r s t P o i n t .Y ) ; MyFirstPoint = MySecondPoint;

System.Cons ole.WriteLine(MyFirstPoint.X) ; Sy st em . C o n s o l e . W r i t e L i n e ( M y F i r s t P o i n t .Y) ;

} } El cdigo anterior asi gna el valor 100 a los mi embros de MyFirstPoint y el v a l o r de 2 00 a los m i e m b r o s de M y S e c o n d P o i n t . Los v a l o r e s de MyFirstPoint se escriben en la consola y luego los valores de la variable MyFirstPoint se copian en los valores de la variable MySecondPoint. T ra s la asignacin, los valores de MyFirstPoint se vuelven a escribir en la consola. Si compila y ejecuta este cdigo, obt endr el resultado ilustrado en la figura 7.1.
c.A C:\WINDOW5\System32\cmd.exe
C : \ > L i;', t i i K f V

.....i ny

1m

2 . * xe

?.m

2M U C: '

Figura 7.1. Asignacin de una estructura a otra

Todos los valores de una es truc tu ra se sobrescriben en una asignacin con los valores de la variable de es truc tu ra indicada despus del signo igual.

Cmo definir mtodos en estructuras


Adems de variables, en las est ructur as se pueden incluir mtodos. Si necesita escribir un cdigo que trabaje con los contenidos de u na estructura, podra consi der ar la opcin de escribir el mtodo dentro de la mi sma estructura.

173

Cmo usar mtodos constructores


Una es tructur a puede incluir un mtodo especial llamado constructor. Un mtodo co ns tructor se ejecuta cuando se ejecuta en t iempo de ejecucin una declaracin de variable que usa el tipo de la estructura. Las est ructur as pueden tener v a n o s constructores o ninguno. Las dec laraci o nes de constructores de es tructur a son muy parecidas a las declaraciones de mtodos de clase, con las siguientes excepciones: Los constructores no devuelven ningn valor. No se pueden u sar pal abr as clave de tipo de devolucin p ar a escribir un const ructor de estructura, ni siquiera void. Los identificadores de constructores tienen el mismo nombre que la es truc tura. Los constructores deben tener al menos un parmetro. C# no permite defi nir un constructor sin parmetros. C# siempre define una constructor por defecto sin par met ros por nosotros. Este es el const ructor que inicializa todos los miembros de la e st ruc tu ra a cero o su equivalente. Una es tructur a puede definir ms de un constructor, siempre que los c o n st ru c tores tengan diferentes listas de parmetros. El listado 7.3 mues tra una estructura Point con dos constructores.
Listad o 7.3. C onstructores de estructuras class Listing7_3 Point

{
struct

{
public int X; publ i c int Y ; public Point(int InitialX)

{
X = ImtialX; Y = 10 0 0;

public Point (int

ImtialX,

int

ImtialY)

{
X = ImtialX; Y = Initial Y;

public

static

void M a i n ( ) = new Point ();

{
Point M y F i r s t P o m t

174

Point M y S econdPoint = new Point (100) ; Point M y T h i r d P o m t = new Point (250, 475) System.Console .W r i t e L m e (My Fi r s t P o m t . X ) ; System.Console . W r i t e L m e (My Fi r s t P o m t . Y ) ; System.Console . W r i t e L m e ( M y S e c o n d P o m t .X) S y s t e m .Console . W r i t e L m e ( M y S e c o n d P o m t .Y ) System. Con sole . W r i t e L m e (MyThi rdPoi nt .X ) ; System.Console . W r i t e L m e (MyThi r d Po i nt .Y ) ;

La figura 7.2 ilustra el resultado de compilar y ejecutar el cdigo del listado 7.

Figura 7.2. La estructura revela los valores predefinidos.

Ten ga en cuenta los siguientes conceptos del listado 7.3: La estructura Point declara dos constructores. Uno recibe como a r g u mento un solo nmero entero y el otro recibe dos nmeros enteros. Ambos llevan ant epuest a la p al ab r a clave public por lo que su cdigo es ac ces i ble al resto del cdigo de la clase. El const ructor con un p a rm et ro entero asigna al mi embro X de la es t ruc t ura el valor del ar gument o entero y asigna al miembro Y de la est ructura el valor 1.000. El const ructor con dos par met ros enteros asigna al mi embro X de la es t ru ct ura el valor del pri mer ar gu me nt o entero y asigna al mi embro Y de la es tructur a el val or del segundo ar gume nt o entero.

175

El cdigo declara tres variables de tipo Point. C ad a una de ellas llama a uno de los constructores Point. La declaracin de MyFirstPoint llama al constructor sin argumentos. Este es el constructor por defecto que C# define par a cada estructura. La declaracin de MySecondPoint lla m a al c o n s t r u c t o r q u e t i e n e un a r g u m e n t o y la d e c l a r a c i n de MyThirdPoint llama al const ructor con dos argumentos. Preste mucha atencin a la sintaxis del listado 7.3. que invoca a un constructor de estructura. Si se quiere invocar a un const ructor en una estructura, se debe emplear la pal abr a clave new seguida del nombre de la es truc tu ra y de los par met ros del const ructor entre parntesis. El valor de esa expresin se asigna a la variable que se est declarando. Observe la siguiente declaracin:
Point MyThirdPoint = new Point (250, 475);

Esta declaracin indica: "Crea una nueva est ructur a Point usando el c on s tr uc tor que tiene dos enteros. Asigna su valor a la variable MyThirdPoint". D e b i do a las reglas de asignacin de estructuras anteriormente descritas, los miembros de la variabl e MyThirdPoint reciben los valores de los mi embros de la nueva estructura. No es necesario hacer nada ms con la nueva est ructura cr eada c u a n do se llam a new. El entorno comn de ejecucin (C L R) detecta que la e s t r u c t u ra ya no se us a y se deshace de ella mediante el meca ni smo de recoleccin de elementos no utilizados. En el listado 7.3 tambin aparece la sintaxis del const ructor sin parmetros:
Point MyFirstPoint = new P o i n t ();

Asi se indica al compi lador de C# que se quiere inicializar la es tructur a de la for ma habitual. Se deben asi gnar valores a todos los mi embros de una est ructur a antes de usarla, bien invocando su co ns tructor sin par met ros o asi gnando e xpl citamente todos los ca mpos de un valor. Observe el listado 7.4.
L istad o 7.4. Si se usa una estructura antes de inicializarla se producen errores de compilacin class Listing7_4 Point int X; int Y;

{
struct

{
public public

}
public static void M a i n ( ) MyPoint;

{
Point

S y s t e m . C o n s o l .W r i t e L i n e ( M y P o i n t .X );

176

System.Consol.WriteLine(MyPoint.Y)

El cdigo anterior es errneo y al compilarlo el c ompi lador de C# produce los siguientes mensajes de error:
error CS0170: Uso del campo 'X', posiblemente error CS0170: Uso del campo 'Y', posiblemente warning CS0649: El campo 'Listing7_4.P o i n t .X ' siempre tendr el valor predeterminado 0 warning CS0649: El campo 'Listing7_4.P o i n t .Y' siempre tendr el valor predeterminado 0 no asignado no asignado nunca se asigna nunca se asigna

y y

Los mensajes de error avisan de que las llamadas a WriteLine() usan mi embros de datos en la estructura, pero que a esos miembros de datos todava no se les ha asignado valor. La variable MyPoint no ha sido inicializada con una llamada al const ructor sin par met ros ni t amp oco se han asi gnado valores expl citamente a sus miembros. C# no invoca al cons tructor sin par met ro s a menos que se escri ba la l lamada en el cdigo. Este es otro ejemplo de cmo el compilador de C# protege el cdigo par a evitar que se comport e de forma impredecible. Tod as las variables deben inicializarse antes de ser usadas.

Cmo llamar a mtodos desde estructuras


Ta mb i n se pueden escribir mtodos en las estructuras. Estos mtodos siguen las mi smas reglas que los mtodos de clase: deben es pecificar un tipo de d evol u cin (o void) y tener un identificador y una lista de argumentos, que puede estar vaca. Para llamar a un mtodo en una est ructur a se usa la mi s ma notacin de puntos que p a r a acceder a un mtodo de clase. Observe el listado 7.5.
Listad o 7.5. Cm o llamar a mtodos de estructura class Listing7__5 Point

{
struct

{
public int X; publ ic int Y ; public Point(int InitialX, int InitialY)

{
X = InitialX; Y = InitialY;

}
public bool IsAtOrigin()

177

f ( (X == 0) && (Y = = 0) ) return true; e 1s e return false;

} (
pub 1 1 c s tatic vo ic i M a m () 2 00) ;

I
Point Point M y F i r s t P o m t = new Point (100, My.;econdPoint - nexv Point () ;

if : (MyF'i rst Poi nt . IsAtOri.gin (j -- true) System.Consol .Writ.eLine ("MyFirstPoint o n q m . " ); e 1s e : jy ste m .: o n sol. W i :it e I ,in e "M y Fi rst Poi n t o r iy in ." ; i f (MySecondPoint.IsAtOr iqin) == true) System.Conso 1e .Wr itel.ine ("MySecondPo int o r icj i .n ." ) ; e 1s e System.Conso 1e .Wr iteLine ("MySecondPoi nt c j i i g in ." ) ;

is at

the

is n o t at

th e

at

the

is not

at

the

} La estructura Poi nt del listado 7.5 declara un mtodo llamado TsAtOr iqi n . El codigo de ese mtodo c omp rue ba los valores de los mtodos de la es tructur a y devue lve true si las coordenadas del punto son (0. 0) y false en cualquier otro caso. El mtodo M ai n ( ) declara dos variables de tipo Point: a la variable M y F i r s t P o i n t se le asignan las coordenadas (100. 200) usando el constructor explcito v a la variable M y S e c o n d P o i n t se le asignan las coordenadas (0. 0) usando el cons tructor por defecto sin parmet ros. En ese momento el mtodo M ai n () llama al mtodo I sAtOr iqin con los dos puntos y escribe un mensaje bas ado en el valor devuelto por el mtodo. Si se compi la y ejecuta el cdigo del listado 7.5. se obtiene el siguiente resultado en la consola:
MyFirstPoint s not at the o n g i n . MySecondPoint s at the o n g i n .

Hay que a segurars e de prefijar los mtodos con la pal abr a clave pu bl ic si se quiere que sean accesibles por todo el resto del cdigo de la clase.

Cmo definir propiedades en estructuras


Las propiedades de una es tructur a permiten leer, escribir y calcul ar valores usando descriptores de acceso. A diferencia de los campos, las propiedades no se

178

consideran variables; p or tanto, no designan espacios de al macenamiento. Debi do a esto, no pueden ser p as adas como par met ros r e f o o u t . El listado 7.6 incluye una propi edad dentro de la est ruc tu ra Point.
Listad o 7.6. Definicin de una propiedad en el interior de una estructura class Listing7_6

{
struct Point

{
private int x; public int X

{
ge t

{
return x;

} set {
x = valu;

public

static void M a i n ( )

{
int RetValue; Point MyPoint = new P o i n t ();

MyPoint.X = 10; RetValue = MyPoint.X; Sy st em .C on so le . W r i t e L i n e ( R e t V a l u e ) ;

Este cdigo asigna un valor al mi embro X de la est ructur a Point y luego devuelve este valor a la variable RetValue. El resultado del listado 7.6 se ilustra en la figura 7.3. El uso de propiedades es u na for ma excelente de leer, escribir y c alcular datos dentro de una estructura. No hace falta incluir mtodos voluminosos p ar a que realiccn los cl cu los y se p uede definir cmo y c u n d o puede n a c t u a r los descriptores de acceso get y set.

Cmo definir indizadores en estructuras


Los indizadores son objetos que permiten indizar una est ructur a de forma muy parecida a una matriz. Con un mdizador. se pueden declarar varias estructuras al mi smo tiempo y hacer referencia a cada es tr uc tu ra usando un nmero de ndice.

179

El listado 7.7. que declara una est ructur a llamada MyStruct que contiene una cadena y un ndice, lo demuestra.

Figura 7.3. Definicin de una propiedad en el interior de una estructura

Listado 7.7. Cmo incluir un indizador en una estructura

class (

L i s t ing7 _7

s t r u c t My S tiuc t public public string string []clata ; this [int

index]

{
get

{
return d a ta [i nd ex ];

} set {
data[index] = value;

public

static void M a i n ( )

{
in t x ; MyStruct ms.data m s [0 ] = m s [1 ] = m s [2] = m s [3] = m s [4] = ms = new M y S t r u c t ( ); = new string[5]; "Brian D Patterson"; "Aimee J Patterson"; "Breanna C Mounts"; "Haileigh E Mounts"; "Brian W Patterson";

180

for (x=0;x < 5 ;x++) Sy st em .C on so l . W r i t e L i n e ( m s [ x ] );

} } C om o se puede ver. este ejemplo crea un nuevo objeto MyStruct y asigna a los mi embros data el valor 5. lo que indica que se usan cinco copias de esta estructura. Pa ra hacer referencia a cada copia de esta est ructura se usa un nmero indizador (de 0 a 5) y se al macenan los nombres dentro de la estructura. Para as egurars e de que todos lo datos per manecen intactos, se aplica un simple bucle a los posibles nmeros de ndice y se escribe el result ado en la consola. En la figura 7.4 se ilustra el resultado del listado 7.7.
C:\WINDOWS\System32\cmd.exe
C : \ > L i t i n < ( 7
B i'i< u i i

7 .o < > : D \ i I t. r - (Mi J Pat. t , m i C M ounts

U rticin n a

H a i ( t; i jh H M o t n t; R r i - u t U Ptt. t > ;r s o n

Figura 7.4. Para devolver fcilmente los datos se incluye un indizador dentro de la estructura

Un indizador en una es tructur a puede ser muy til cuando se t rabaj a con g r a n des cantidades de datos del mismo tipo. Por ejemplo, si se va a leer la i nformacin de una di reccin desde una bas e de datos, ste es un excel ent e l ugar p ar a almacenarla. Todos los ca mpos se mantienen mientras se pr opor ci ona un m e c a nismo p ar a acceder fcilmente a cada dato de los registros.

Cmo definir interfaces en estructuras


Las interfaces son un modo de as egurars e de que cualqui era que use la clase cumple con todas las reglas i mpuestas p a r a hacerlo. Estas pueden incluir la i mplement aci n de ciertos mtodos, propi edades y eventos. C u an d o se expone una interfaz, sus usuar ios deben heredarla y al hacerlo estn obligados a crear ciertos mtodos y as sucesivamente. Esto as egu ra que la clase y/o es tructur a se use de forma correcta.

181

Tambi n se puede incluir una interfaz dentro de una estructura. El listado 7.8 muest ra c mo implementar correctamente un a interfaz.
L istado 7.8. Cmo implementar una interfaz en una estructura class Listing7__8

{
interface Interface

(
void M e t h o d ( );

}
struct MyStruct : Ilnterface

{
public void M e t h o d ( ) Method") ;

{
System. Console.WriteLine ("Structure

public

static

void M a i n ( )

{
MyStruct DemoStructure = new M y S t r u c t (); D e m o S t r u c t u r e .M e t h o d ();

} } Este cdigo crea una interfaz l lamada IInterface. Esta interfaz contiene la definicin de un mt odo l lamado Method. Se crea una estructura y al final de su nombre se incluyen dos puntos seguidos del nombre de la interfaz que desea derivar. El mtodo, que simplemente escribe un a lnea de texto en la consola, se incluye en la estructura. En la figura 7.5 es ilustra el resultado del programa. Para demost rar lo i mportante que es la interfaz. si elimine las cuatro lneas que c o mpo nen el mt odo Method en la estructura MyStruct y vuelve a compi lar el prog rama, o bt endr el siguiente mensaje de error:
Classi.es (8,9): error CS0535: 'Listing7_8.MyStruct ' no implementa e 1 miembro de interfaz L isting7_8.IInterface.Method()'

El comp il ado r de C# determin que no i mplement amos todos los mtodos e s tipulados por la interfaz. Como no se implemento el mtodo correcto, el pro gr ama no se pudo compilar, indicando de esta for ma que no se cumplen todas las reglas.

Cmo usar los tipos simples de C# como estructuras


Los tipos primitivos (int. uint, long y similares) descritos en un captulo anterior en realidad se implementan como est ructur as en el C L R de NET. La

182

tabla 7.1 enumera las p al abr as clave con valor variable y los nombres de las e st ructur as N E T que actual mente los implemcntan.
C:\WINDOWS\System32\cmd.exe
C :\>Lis t ing ? - 8 .exe Structure Method
C :\>

Figura 7.5. Cmo implementar un interfaz en una estructura

Tabla 7.1. Nombres de estructura

NET para tipos de valor

Palabra clave d e C # sbyte byte short us ho rt int uint long ulong char float double bool decimal

N o m b r e d e estructura . N E T S ys t e m , .S B y t e .B y t e S ys t e m . S ys tern, .I n t i 6 Sys t e m .U i n t 16 S ys t e m . I n t 3 2 S ys t e m , .U i n t 32 .I n t 6 4 Sys t e m , ,U i n t 64 Sys t e m . S ys t e m . Char Sy st e m . ,S i n g l e .D o u b l e Sys t e m , S ys t e m . .B o o l e a n S ys te m.,D e c i m a l

Este es que ma es parte de lo que hace que el cdigo C# sea compat ibl e con otros lenguajes NET. Los valores C # se asigna a las estructuras N E T que pue-

183

de usar cualquier lenguaje NET. porque el C L R puede usar cualquier estructura N E T La asignacin de las palabras claves de C# con estructuras N E T tambin permite que las estructuras usen tcnicas como la sobrecarga de operadores para definir el comportamiento del valor cuando se usan en una expresin con un o per a dor. Se analizar la sobrecarga de operadores cuando se traten las clases C#. Si lo desea, puede usar los nombres reales de est ructur a . NET en lugar de las pal abr as clave de C#. El listado 7.9 muest ra el aspecto que tendra el listado 7.5 si se escribiera usando los nombres de est ructuras NET.
Listado 7.9. C mo usar los nombres de tipo de estructura NET class Listing7_9

{
struct Point System.Int32 System.Int32 X; Y; IntialX, System.Int32 ImtialY)

{
public public public

Point(System.Int32

{
X = IntialX; Y = In 1 1i a 1Y ;

public

System.Boolean

IsAtOrigm

{
i f ((X == 0) && (Y == 0)) return true;

else
return false;

public

static

void M a i n ( ) 200) ;

{
Point M y F i r s t P o m t = new Point (100, Point M y S e c o n d P o m t = new Point ();

if (MyFirstPoint.I s A t O r i g i n ( ) == true) System.Console.WriteLine("MyFirstPoint is at the origin."); else System.C on so le .W ri te Li ne ("MyFirstPoint is not at the

o rig in .");
if ( My Se c o n d P o m t .IsAtOrigin () == true) System. Console .WriteLine (" M y S e c o n d P o m t

is

at

the

o rig in .");
else System.C on so le .W ri te Li ne (" M y S e c o n d P o m t is not at the

origin.") ; } }

184

Resumen
Las est ructuras permiten ag r up ar un conjunto de variables con un solo n o m bre. Las variables pueden declararse usando el identificador de estructura. Las estructuras se declaran usando la pa la br a clave de C# struct. Todas las est ructur as de C# tienen un nombre y una lista de miembros de datos. C# no pone ningn lmite al nmero de miembros de datos que puede contener una estructura. Se accede a los miembros de est ructuras mediante la notacin StructName . MemberName. Los mi embros se pueden usar en cualquier parte donde est p e r mitido usar su tipo de datos, incluyendo e xpresiones y par met ros de mtodos. Las estructuras pueden i mplementar tanto mtodos como variables. Los mi em bros de est ructuras se invocan usando la notacin StructName .MethodName y se usan igual que los nombres de mtodo de clase. Las est ructur as tambin implementan mtodos especiales llamados constructores, que micializan la es t ruct ura con un estado conocido antes de u sar la estructura. Los tipos de valor de C# son asignados a est ructuras definidas por el C LR de N E T Esto es lo que permite que otros cdigos de N E T usen los datos. Todas las variables son compatibles con C L R de N E T porque las variables se definen usando est ructuras compatibles con el C LR

185

Parte II

Programacin orientada a objetos con C#

187

| Escribir cdigo orientado a objetos


Los lenguajes de p rog ra ma ci n siempre se han diseado en torno a dos c on ceptos fundamentales: los datos y el cdigo que oper a sobre los datos. Los len guajes han evolucionado a lo largo del tiempo p a r a c a mb i ar el modo en que estos dos conceptos interactan. En un principio, lenguajes como Pascal y C invitaban a los p rogr amadore s a escribir software que t ra ta ra al cdigo y a los datos como dos cosas separadas, sin ni nguna relacin. Este enfoque dio a los progr amadore s la libertad, pero tambi n la obligacin, de elegir el modo en que su cdigo gest io na los datos. Adems, este enfoque obl igaba al p ro gr a ma do r a traducir el mundo real que se quera model ar us and o soft ware a un modelo especfico p a r a ordenadores que u sar a datos y cdigo. Los lenguajes c omo Pascal y C se c onst ruyeron en torno al concepto de p r o c e dimiento. Un procedi miento es un bl oque de cdigo con nombre, exact ament e igual que los actuales mtodos de C#. El estilo de s oftware desarrol lado usando estos lenguajes se l lama p ro g r a m a c i n p r o c e d u r a l. En la prog ramaci n procedural. el p r og r am ad o r escribe uno o ms procedi mientos y t r ab a ja con un conjunto de variables independientes definidas en el programa. Todos los procedimientos pueden verse desde cualquier parte del cdi go de la aplicacin y todas las variables pueden ser mani pul ad as desde cualquier parte del cdigo.

189

En los aos 90. la programacin proccdural dio paso a lenguajes como Smalltalk y Simula, que introdujeron el concepto de objeto. Los inventores de estos l engua jes se dieron cuenta de que el ser humano no expr esa ideas en trminos de bloques de cdigo que actan sobre un grupo de variables; en su lugar, expresan ideas en trminos de objetos. Los objetos son entidades que tienen un conjunto de valores definidos (el estado del objeto) y un conjunto de operaciones que pueden ej ecut ar se sobre ese objeto (los com po rtam ien tos del objeto). Por ejemplo, imagine un cohete espacial. Un cohete espacial tiene estados, como la cantidad de combustible o el nmero de pasajeros a bordo, y comportamientos, como "despegar" y "aterrizar". Ademas, los objetos pertenecen a clases. Los objetos de la misma clase tienen el mismo estado y el mismo conjunto de comportamientos. Un objeto es un caso concreto de una clase. El cohete espacial es una clase, mientras que el cohete espacial llamado Discovery es un objeto, un caso concreto de la clase cohete espacial.

NOTA: En realidad, ni siquiera en la programacin procedural son visibles todos los procedimientos ni todas las variables. Igual que en C#, los len guajes procedurales tienen reglas de mbito que controlan la visibilidad del cdigo y de los datos. Por lo general podemos hacer visibles los proce dimientos y los datos (a los que nos referiremos en este captulo como elementos) en el procedimiento, archivo fuente, aplicacin o nivel externo. El nombre de cada mbito es autoexplicativo. Un elemento visible en el nivel de procedimiento slo es accesible dentro del procedimiento en el que se define. No todos los lenguajes permiten crear procedimientos dentro de otros procedimientos. Un elemento visible en el nivel de archivo fuente es visible dentro del archivo en el que se define el elemento. En el nivel de aplicacin, el elemento es visible desde cualquier parte de cdigo en la misma aplicacin. En el nivel externo, el elemento es visible desde cual quier parte de cdigo en cualquier aplicacin. El punto principal es que, en programacin procedural, la interaccin entre datos y cdigo est controlada por los detalles de implementacin, como el archivo fuente en el que se define una variable. Una vez que se decide hacer visible una variable fuera de sus propios procedimientos, no se obtiene ayuda para proteger el acceso a esa variable. En aplicaciones grandes con varios miles de variables, esta falta de proteccin suele acarrear fallos difciles de encontrar.
El desarrollo de software orientado a objetos tiene dos claras ventajas sobre el desarrollo de software procedural. La primera ventaja es que se puede especificar lo que debe hacer el software y cmo lo har usando un vocabulari o familiar a los usuarios sin preparacin tcnica. El software se est ructura u sando objetos. Estos objetos pertenecen a clases con las que el usuario del mundo de los negocios, al

190

que est destinado, est familiarizado. Por ejemplo, d urante el diseo de soft ware AT M. se usan clases como CuentaBancaria. Cliente. Presen tacin y similares. Esto reduce el trabaj o necesario p a ra t raduci r una situacin del mundo real al modelo de s oftware y facilita la comuni caci n con la gente ajena al software y que est i nteresada en el pro duc to final. Este modo ms sencillo de disear s oft wa re ha conducido a la apari ci n de un es tndar p ar a describir el diseo del software orientado a objetos. Este lenguaje es el Lenguaje unificado de modelado o UML. La segunda ventaja del software orientado a objetos se demu es tra durante la implementacin. El hecho de que ahor a podemos tener mbitos de nivel de clases, permite o cultar variables en las definiciones de clase. C ad a objeto t endr su p r o pio conjunto de variables y estas variables por lo general solamente sern a cces i bles mediante las operaciones definidas por la clase. Por ejemplo, las variables que contienen un estado del objeto CuentaBancaria slo sern accesibles l lamando a la operacin Retirada ( ) o Depsito ( ) asociada a ese objeto. Un objeto CuentaBancaria (o cualquier otro objeto) no tiene acceso a otro estado pri vado del objeto CuentaBancaria. como el balance. A este p ri nci pio se le llama encapsulacin. El desarrollo de software orientado a objetos se fue haciendo ms pop ul ar a medida que los pr ogr amad or es ad op t ab a n este nuevo modo de di sear software. C# es un lenguaje orientado a objetos y su diseo g ar ant iza que los prog ramad ores de C# sigan los conceptos correctos de la prog ramaci n ori ent ada a objetos.

NOTA: SmallTalk, Java y C# son lenguajes orientados a objetos puros porque no se puede escribir un programa sin usar objetos. A otros lengua jes, como C y Pascal, se les llama lenguajes procedurales o orientados a objetos porque no disponen de compatibilidad integrada que permita crear objetos. Existe un tercer tipo de lenguaje hbridos, como C++, en los que se puede elegir si usar o no objetos. Bjame Stroustrp, el ffivefttor de C++, tambin era tina versin mejorada del lenguaje de programacin C La cea* patibilidad con el cdigo C existente ayudaba a <$u$ C*H- se convirtiera en un lenguaje importante.
En este captulo se estudian los conceptos que componen un lenguaje orientado a objetos, empezando por sus componentes esenciales (las clases y objetos), hasta los trminos ms avanzados (abstraccin, tipos de datos abstractos, encapsulacin. herencia y polimorfismo). Se t rat arn los conceptos bsicos y se p r o c ur ar evitar los detalles especficos sobre cmo estn implementados estos conceptos en CU. Estos detalles especfi cos se t rat arn en captulos posteriores.

191

Clases y objetos
En primer lugar, esta seccin vuelve a tratar la diferencia entre un objeto y una clase. Este libro usa mucho estos dos trminos y es importante distinguir entre ellos. Una clase es una coleccion de cdigo y de variables. Las clases gestionan el estado, en forma de las variables que contienen, y comportamientos, en forma de los mtodos que contienen. Sin embargo, una clase slo es una plantilla. Nunca se cr ea una c las e en el cdigo. En su l ugar, se cr ean objetos. Por ejemplo. C uen taB a n c a r i a es una clase con una variable que contiene el saldo de la cuenta v los mtodos Retirada (). Depsito () y Mo str ar S a l d o (). Los objetos son casos concretos de una clase. Los objetos se construyen usando una clase como plantilla. Cuando se crea un objeto, ste gestiona su p r o pio estado. El estado de un objeto puede ser diferente del estado de otro objeto de la mi sma clase. Imagine una clase que define a una persona. Una clase persona va a tener estado (quizas, una cadena que representa el nombre propio de la persona) \ comport ami ent o, mediante mtodos como I r ATr aba jar ( ) . C o mer ) e I r A D o r m i r (). Se pueden crear dos objetos de la clase persona, cada uno con un estado diferente, como se muest ra en la figura 8.1. La figura 8.1 muest ra la clase persona y dos objetos persona: uno con el nombre propio "Alice" v otro con el nombre propio "Bob". El estado de cada objeto se al mac ena en un conjunto de variables diferentes. Vuelva a leer la frase anterior. Esta frase c on tiene un punto esencial par a co mprender el funcionamiento de la pr ogr amaci n orientada a objetos. Un lenguaje admite objetos cuando no se necesita crear un cdigo especial para disponer de un conjunto de variables cada vez que se crea un objeto diferente.

NOTA: Si un lenguaje admite la gestin automtica del estado dentro de objetos pero carece de las otras caractersticas descritas en esta seccin, suele recibir el nombre de lenguaje basado en objetos. Visual Basic 6 admi te objetos, pero no admite la herencia de implementacin; por tanto, no se le considerar como un autntico lenguaje orientado a objetos. Autnticos len guajes orientados a objetos son SmallTalk, Java y C#.

Terminologa del diseo de software orientado a objetos


Se e nc ontr ara con muchos trminos cuando lea libros sobre el desarrollo de software orientado a objetos y probablement e se encuentre con muchos de estos trminos cuando trabaje con codigo C#. Algunos de los trminos ms usados son:

192

Abst racci n Tipos de datos abstractos Encapsulacin He ren ci a Polimorfismo

Las siguientes secciones definen cada uno de estos trminos con detalle.
P erso n + F irs tN a m e : S tring + G o T o W o rk () : void + E a t() : void + G o T o S le e p () : void

P erso n 1 : P e rso n F irs tN a m e : S trin g = A lic e

P e rso n 2 : P erso n F irs tN a m e : S tring = B ob

Figura 8.1. E s t a c l a s e p e r s o n a t i en e d o s o b j e t o s p e r s o n a .

Abstraccin
Es importante darse cuenta de que el objetivo de la pro gr amaci n no es r epr o ducir t odos los aspect os posibles del mundo real de un concepto dado. Por ej em plo. cuando se p r o gr a ma una elase P e r s o n . no se intenta model ar todo lo que se conoce sobre una persona. En su lugar, se t rabaja dentro del contexto de la apl ica cin especfica. Slo se modelan los elementos que son necesarios p a r a esa a p li cacin. Algunas caracter st icas de una persona, como la nacionalidad, pueden existir en el mundo real, pero se omiten si no son necesarias p ar a la aplicacin en cuestin. Una persona en una aplicacin banc ari a est ar interesada en aspectos diferentes de los de. por ejemplo, una persona en un juego de accin. Este con cep to recibe el nombre de a b stra cci n y es una tcnica necesaria p ar a el manejo de los conceptos infinitamente complejos del mundo real. Por tanto, cua ndo se haga preguntas sobre objetos y clases, tenga siempre en cuenta que debe hacerse estas preguntas en el contexto de una aplicacin especfica.

Tipos de datos abstractos


Los tipos de datos abs tra ct os fueron el pri mer intento de det erminar el modo en que se usan los datos en programaci n. Los tipos de datos abst ract os se c r ea ron porque en el mun do real los datos no se componen de un conjunto de v a r i a

193

bles independientes. El mundo real est c ompuest o de conjuntos de datos relacio nados. El estado de una persona p ar a una aplicacin determinada puede consistir en. por ejemplo, nombre, apellidos y edad. Cu an do se quiere cr ear una persona en un progr ama, lo que se quiere crear es un conjunto de estas variables. Un tipo de datos abst ract os permite present ar tres variables (dos cadenas y un numero entero) como una unidad y t raba jar cmodamente con esta unidad par a contener el estado de una persona, como se ve en este ejemplo:
struct Person

{
pub l i c public pub l i c S tri ng FirstName; St ri n g LastName; int A g e ;

} Cuand o se asigna un tipo de datos a una variable del cdigo, se puede usar un tipo de datos prim itivo o un tipo de datos abstracto. Los tipos de datos primitivos son tipos que CU reconoce en cuanto se instala. Ti pos como int. long. char y string son tipos de datos primitivos de C#. Los tipos de datos abst ract os son tipos que C# no admite cuando se instalan Antes de poder us ar un tipo de datos abs tra ct o hay que declararlo en el cdigo Los tipos de datos abst ract os se definen en el cdigo en lugar de hacerlo en el compi lador de CU. Por ejemplo, imagine la est ructur a (o clase) Person. Si escribe cdigo CU que usa una estructura (o clase) Person sin escribir cdigo que le indique al compilador de C# a qu se parece una est ructura (o clase) Person y cmo se comport a, se obtiene un error de compilacin. Observe el siguiente cdigo:
class MyClass voicl M a i n ( ) M y Pe rso n; = "Malgoska";

{
s ta t i c

{
Pe rso n

P e r s o n .F i r s t N a m e

} } Si se compi la este cdigo el compi lador de C# genera el siguiente error.


error CS0234: El tipo 'Person' no existe en 'MyClass' (falta una o el nom b r e del e s p a c i o de n omb res la clase o el e s p a c i o de n ombres r e f e r e n c i a de ensamblado?)

El probl ema de este cdigo es que el tipo de datos Person no es un tipo de datos primitivo y no est definido por el lenguaje CU. Como no es un tipo pr imi tivo. el compi lador de CU considera que se t rata de un tipo de datos abst ract o y revisa el cdigo buscando la declaracin de un tipo de datos Person. Sin e m ba r go. como el compi lador de CU no puede en co nt rar informacin sobre el tipo de

194

datos abstracto Person genera un error. Tra s definir un tipo de datos abstracto, puede usarse en el cdigo C # exact ament e igual que si fuera un tipo de datos primitivo. Las est ructur as y las clases de C# son ejemplos de tipos de datos abstractos. Una vez que se ha definido una est ructura (o clase), se pueden u sar las v a r i a b l e s de ese t i p o d e n t r o de o t r a e s t r u c t u r a (o cl as e ). L a e s t r u c t u r a LearningUnit. por ejemplo, contiene dos variables Person:
struct LearningUnit Person Person Tutor; Student;

{
public public

Encapsulacin
Mediante la encapsulacin. los datos se ocultan, o se encapsulan. dentro de u na clase y la clase implementa un diseo que permite que otras partes del cdigo accedan a esos datos de for ma eficiente. Imagine la encapsulacin como un envol torio protector que rodea a los datos de las clases de C#. Cmo ejemplo de encapsulacin. observe la es tructur a Point con la que t rabaj en un captulo anterior.
struct Point int X; int Y;

{
public public

} Los miembros de datos de esta es tructur a son pblicos, lo que permite que cualquier parte de cdigo que acceda a la e st ru ctur a acceda tambin a los m i em bros de datos. C omo cualquier parte de cdigo puede acceder a los miembros de datos, el cdigo puede asi gnar a los valores de los miembros de datos cualquier valor que pueda representarse en un valor int. No obstante, puede surgir un p robl ema al permitir que los clientes asignen los valores de los miembros de datos directamente. Supongamos que se usa la es truc tura Point par a representar una pantalla de ordenador con una resolucin de 800 x 600. En ese caso, slo tiene sentido permitir al cdigo que asigne a X valores entre 0 y 800 y a Y valores entre 0 y 600. No obstante, con el acceso pblico a los miembros de datos, no hay nada que impida al cdigo asi gnar a X el valor 32. 000 y a Y el valor 38.000. El compi lador de C# lo permite porque esos valores son posibles en un entero. El prob lema es que no tiene sentido permitir valores tan elevados. La encapsul aci n resuelve este problema. Bsicamente, la solucin est en m ar c ar los mi embros de datos como privados, par a que el cdigo no pueda a c c e der a los miembros de datos directamente. A continuacin puede escribir mtodos en una clase de punt o como SetX () y SetY (). Los mtodos SetX () y SetY ()

195

pueden a si gnar los valores y tambin pueden contener cdigo que genere un error si se trata de llamar a SetX ( ) o a SetY ( ) con par met ros con valores demasiado grandes. La figura 8.2 muest ra el posible aspecto de una clase Point.
P oint -X : int -Y : int + S e tX () : bool + S e tY () : bool + G e tX () : int + G e tY () : int

Figura 8.2. Las variables de miembros en la clase Point estn encapsuladas

NOTA: El signo meaos delante de los miembros de datos es una notacin UML que indica que los miembros tienen una visibilidad privada. El signo ms delante tos miembros de datos es una notacin UML que indica que tos miembros tienen una visibilidad pblica.
La tcnica consistente en m ar c ar como privados los miembros de datos resuel ve el probl ema de que el cdigo establezca sus valores directamente. Si los m i em bros de datos son privados, slo la propia clase puede verlos y cualquier otro cdigo que intente acceder a los miembros de datos genera un error del compilador. En lugar de acceder directamente a los mi embros de datos, la clase declara mtodos pblicos llamados SetX ( ) y SetY ( ) . El cdigo que quiere asi gnar los valores de los puntos X e Y llama a estos mtodos pblicos. Estos mtodos p u e den ac ept ar el nuevo valor de las coordenadas y un parmet ro, pero tambin pueden c o m pr o ba r los nuevos valores p ar a as egurars e de que estn dentro de los lmites adecuados. Si el nuevo valor est fuera de los lmites, el mtodo devuelve un error. Si el nuevo valor est dentro de los lmites, el mtodo puede establecer un nuevo valor. El siguiente seudo cdigo mu est ra cmo se puede i mplement ar el m t o do SetX ():
bool SetX(int NewXValue) of range)

{
f(NewXValue s out return false; X = NewXValue; return true;

} Este cdigo ha e nc aps ul ado el mi embro de datos de la c oor denada X y p er mi te a los invocadores as ignar su valor a la vez que impide que le asignen un valor no vlido. Cmo los valores de las coor denadas X e Y en este diseo son privados, las otras partes de cdigo no pueden exa mi na r sus valores actuales. La accesibilidad

196

p ri vada en la prog ramaci n orientada a objetos evita la llamada lean el valor actual o guar den el nuevo variables privadas, se pueden implement ar mtodos que devuelven el valor actual de las coordenadas. En este diseo, la clase enc ap sul a los valores de otras partes del cdigo lean y escriban sus valores. La ot ra ventaja: el mtodo que realiza el acceso impide surdos a los mi embros de datos.

que las partes que realizan valor. Para exponer estas como GetX () y GetY () X e Y aunque permite que encapsulacin proporciona que se asignen valores a b

Herencia
Algunas clases, como la clase Point. se disean partiendo de cero. El e st a do y los co mpo rt ami ent os de la clase se definen en ella misma. Sin embargo, otras clases toman prestada su definicin de otra clase. En lugar de escribir otra clase de nuevo, se pueden t omar el estado y los comport ami ent os de otra clase y usarlos como punto de par ti da par a la nueva clase A la accin de definir una clase usando otra clase como punto de parti da se le llama herencia.

Herencia simple
S up on gamos que estamos escribiendo cdigo usando la clase Point y nos damos cuenta de que necesitamos t r aba j ar con puntos tridimensionales en el m is mo cdigo. La clase Point que ya hemos definido modela un punt o en dos dimensiones y no podemos usarlo p a r a definir un punt o tridimensional. Decidi mos que hace falta escribir un punt o tridimensional llamado Point 3D. Se puede disear la clase de una de estas dos formas: Se puede escribir la clase Point3D par ti endo de cero, definiendo m i e m bros de datos llamados X. Y y Z y escribiendo mtodos que lean y escriban los mi embros de datos. Se puede derivar de la clase Point. que ya implementa los mi embros X e Y. Heredar de la clase Point propor ci ona todo lo necesario par a trabaj ar con los mi embros X e Y. por lo que todo lo que hay que hacer en la clase Point3D es i mplementar el mi embro Z. La figura 8.3 mues tra el aspecto que podra tener la clase Point3D en UML.

NOTA: l& notacin UML que ndica que ios miembros tienen visibilidad protegida es el stnbolo de libra delate d los miembros de datos.Visibif^ad protegida sijpjiBa que la visi&ttidad es pblica para las ciases deri vadas y privadas para todas las dems clases.
La figura 8.3 refleja la herencia simple. La herencia simple permite que una clase se derive de una sola clase base. Este tipo herencia tambin es conocido

197

como derivar una clase de otra. Parte del estado y del comport ami ent o de la clase Point3D se derivan de la clase Point. En este caso, la clase u sa da como punto de par ti da recibe el nombre de clase base y la nueva clase es la clase derivada. En la figura 8.3 la clase base es Point v la clase derivada es Point3D.
Point #X : int #Y : int +SetX() +SetY() +GetX() +GetY() : bool : bool : int : int

Pont3D -Z : nt +GetZ() : nt +SetZ() : bool Figura 8.3. La clase P o m t 3 D hereda los m todos y las variables de la clase Point.

Derivar una clase de otra aut omt icame nte permite que los miembros de datos pblicos (y protegidos) y a los mtodos pblicos (y protegidos) de la clase base estn di sponibles par a la clase derivada. Como los mtodos GetX ( ) .GetY ( ) . Set X ( ) y Set Y ( ) estn ma rc a do s como pblicos en la clase base, estn aut omticamente disponibles par a las clases derivadas. Esto significa que la clase Po i nt 3 D dispone de los mtodos pblicos GetX ( ) . GetY ( ) . SetX ( ) y Set Y ( ) ya que se derivaron de la clase base Point. Una seccin de codigo puede crear un objeto de tipo Point 3D y llamar a los mtodos GetX ( ) . GetY ( ) . SetX () y SetY (). aunque los mtodos no esten implementados explcitamente en esa clase. Se derivaron de la clase base Point y pueden ser usados en la clase derivada Point3D.

Herencia mltiple
Algunos lenguajes orientados a objetos tambin permiten la herencias m lti ple. lo que permite que una clase se derive de ms de una clase base. C# solo permite herencias simples. Esta restriccin se debe a que el C L R de N E T no admite clases con varias clases base, principalmente porque otros lenguajes N ET . como Visual Basic, no admiten p or s mismos herencias mltiples. Los lenguajes que admiten herencia mltiple, como C++. tambin han ev idenciado la dificultad de us ar correctamente la herencia mltiple.

198

N01T: Si 'sje; quiere usar la herencte ots'' fU,pRe o j h(?rsde tes

tencin.k La contencin i^ru?t^ui^variable se qwfere derivar. B'lei iii y D esp ertador delega la funcionalidad eni$;ykiiabl# miembro fci* se fuede utilizar en para simular herencias mltiples en .NET (a

Polimorfismo
La herencia permite que u na clase derivada redefina el comport ami en to e s pe cificado par a una clase base. S up ongamos que creamos una clase base Animal. Hacemos esta clase base abs t ra c ta porque queremos codificar animales genricos siempre que sea posible, pero tambin crear animales especficos, como un gato y un perro. El siguiente fr agmento de cdigo mues tra cmo declarar la clase con su mtodo abstracto.
Abstract class Animal abstract void MakeNoise ( );

{
public

} Aho ra se pueden der ivar animales especficos, como Cat y Dog, a partir de la clase base abst ract a Animal:
class Cat : Animal override void M a k e N o i s e ( )

{
public

{
Consol.WriteLine("Me o w !") ;

} }
class Dog : Animal override void M a k e N o i s e ( )

{
public

{
C o n s o l . W r i t e L i n e (" W o o f !");

} } O b s e r v e qu e c a d a c l a s e t i en e su p r o p i a i m p l e m e n t a c i n del m t o d o MakeNoise (). Ahora la situacin es la indicada p ar a el polimorfismo. Como se apreci a en la figura 8.4. tenemos una clase base con un mtodo que est a n ul a

199

do en dos (o ms) clases derivadas. El p o lim o rfism o es la c apaci dad que tiene un lenguaje orientado a objetos de l lamar correctament e al mtodo anul ado en f u n cin de qu clase lo est llamando. Esto suele producirse cuando se al mac ena una coleccin de objetos derivados. El siguiente fragmento de cdigo crea una coleccin de animales, que recibe el a pr opia do nombre de zoo. A continuacin aade un perro y dos gatos a este zoo.
ArrayList Zoo; Zoo - new A r r a y L i s t (3); Cat Sasha, Koshka; Sasha = new C a t (); Koshka - new C a t (); D o g Milou; Milou = new Dog (! ;

Figura 8.4. Este ejemplo de herencia muestra una clase base y dos clases derivadas.

La coleccion zoo es una coleccin polimrfica porque todas sus clases derivan de la clase abstracta A n i m a l . Ahora se puede iterar la coleccin y hacer que cada animal emita el sonido correcto:
f or e a c h ( An ima 1 a m Zoo)

{
a . M a k e N o i s e ();

} Si ejecuta el codigo anterior p roducir el siguiente resultado:


Wo o f ! Me ow ! Me ow !

200

Que est p as and o? C om o C# permite el pol imorfismo, en el tiempo de ej ecu cin el p r o gr a ma es lo suficientemente inteligente como p a r a l lamar a la versin perro de MakeNoise cuando se obtiene un perro del zoo y la versin gato de MakeNoise cuando se obtiene un gato del zoo. El listado 8.1 mu es tr a el cdigo C # completo que explica el polimorfismo.
Listad o 8.1. Las clases Cat y Dog evidencia el polim orfismo using using System; System.Collections ; PolyMorphism class Animal void MakeNoise ( );

namespace

{
abstract

{
public abstract

}
class Cat : Animal override void M a k e N o i s e ( )

{
public

{
C o n s o l e . W r i t e L i n e (" M e o w !");

class

Dog

: Animal override void MakeNoise

{
public

{
C ons o l e . W r i t e L i n e ( " W o o f ! ");

} }
class PolyMorphism int M a i n (s t r i n g [] args)

{
static

{
ArrayList Zoo; Zoo = new A r r a y L i s t (3); Cat Sasha, Koshka; Sasha = new Cat ( ); Koshka = new Cat ( ); Dog M i l o u ; Milou = new Dog(); Z o o .Add(Mi 1o u ) ; Z o o .A d d (K o s h k a ); Z o o .A d d (S a s h a );

201

foreach

(Animal

a in Zoo)

{
a . M a k e N o i s e ();

}
// espera a que el usuario acepte los resultados Consol. W r i t e L m e ("Hit Enter to termnate ..."); C o n s o l .Read () ; r e t u rn 0 ;

Resumen
C# es un lenguaje orientado a objetos y los conceptos que se usan en los lenguajes orientados a objetos tambin se aplican a C#. Los tipos de datos abstractos son tipos de datos que se definen en el propio cdigo. Los tipos de datos abst ract os no forman parte de C#. a diferencia de los tipos de datos primitivos. Se pueden usar tipos de datos abstractos en el cdigo de la mi sma for ma que los tipos de datos primitivos, pero slo despus de haberlos definido en el cdigo. La encapsulacion es el acto de disear clases que proporcionen un conjunto completo de funcionalidad a los datos de las clases sin exponer directamente esos datos. Si se quiere escribir codigo que evite que otras partes del cdigo pro po rci o nen valores no vlidos a la clase, la encapsulacin permite "ocultar" los miembros de datos al hacerlos privados, mientras crea mtodos que acceden a ellos v e s t a blecen los valores de los mi embros de datos como pblicos. Otros fragment os de codigo pueden l lamar a los mtodos, que pueden c o mp r ob a r los valores y emitir un error si los valores no son apropiados. La herencia permite definir una clase por medio de otra. Las clases deriv adas heredan de la clase base. Las clases deriv adas aut omt icamente heredan el estado y los comport ami ent os de la clase base. Se puede usar la herencia para aadir nuevas funciones a clases ya existentes sin necesidad de rescribir desde cero una clase completamente nueva. Algunos lenguajes orientados a objetos permiten t a n to herencias simples como herencias mltiples, aunque C# solo permite la her en cia simple. El p o lim o rfism o permite t rat ar de forma uniforme a una coleccin de clases derivadas de una sola clase base. Las clases derivadas se recuperan como una clase base v C# aut omt icame nte llama al mtodo correcto en la clase derivada. Este captulo t rata los conceptos orientados a objetos en general, sin estudiar como se usan estos conceptos en el cdigo C#. El resto de los captulos de esta parte del libro explican como se i mplementan estos conceptos en C#.

202

Clases de C#

El diseo de C# est muy influido por los conceptos del desarrollo de software orientado a objetos. C omo la clase es la parte fundamental del software orientado a objetos, no es de sorprender que las clases sean el concepto ms importante de C#. Las clases en el mundo del desarrollo de s oftware orientado a objetos contie nen codigo y datos. En C#. los datos se implementan usando mi embros de datos y el cdigo se i mplementa us ando mtodos. Los m iem bros de datos son cualquier elemento al que se pueda p as ar datos dentro y fuera de la clase. Los dos princi pales tip os de mi embros de datos son los ca mpos y las propiedades. En el cdigo C# se pueden escribir tantos mi embros de datos y mtodos como se desee, pero todos deben incluirse en una o varias clases. El compi lador de C# emite un error si se intenta definir al guna variable o se implementa algn mtodo fuera de una definicin de clase. Este captulo t rata de los fundament os de la construccin de clases. Explica cmo crear constructores y destructores, aadir mtodos y m ie m bros. adems de a us ar clases despus de crearlos.

Cmo declarar una clase


La accin de declarar una clase resulta similar a declarar una estructura. La principal diferencia reside en que la declaracin empi eza con la pa la br a clave de

205

C# class y no con struct. Aun qu e ya hemos visto una definicin de clase en anteriores captulos, vamos a revisar el diseo de una declaracin de clase: Modificadores de clase opcionales La palabra clave class Un idcntificador que da nombre a la clase Informacin opcional de la clase base El cuerpo de la clase Un punt o y coma opcional La declaracin de clase m nima en C# es p ar eci da a lo siguiente:
class MyClass

{ } Las llaves delimitan el cuerpo de la clase. Los mtodos y variables de clase se colocan entre las llaves.

El mtodo Main
C ad a aplicacin de C# debe contener un mtodo llamado Main. Esto es el punt o de e nt rada p a r a que la aplicacin se ejecute. Se puede colocar este mtodo dentro de cualqui er clase del proyect o porque el c ompi lador es lo b as tant e inteli gente como p a r a buscarl o cuando lo necesite. El mt odo Main debe cumplir dos requisitos especiales p a r a que la aplicacin funcione correctamente. En primer lugar, el mtodo debe declararse como public. Esto as egu ra que se pueda acceder al mtodo. En segundo lugar, el mtodo debe declararse como static. La pal abr a clave static as e gu ra que slo se puede abrir una copia del mtodo a la vez. Teni endo en cuenta estas reglas, obser vemos este cdigo:
class Class1 static void Main()

{
public

{ } } Como puede apreciarse, este ejemplo contiene una clase llamada Class 1 . Esta clase contiene el mtodo Main de la aplicacin. Es en este mtodo Main donde se coloca todo el cdigo necesario p ar a ejecutar su aplicacin. Aunque es correcto colocar este mtodo en la misma clase y el mismo archivo que el resto del cdigo de la aplicacin, conviene cr ear una clase y un archivo s eparados p ar a el

206

mtodo Main. Esta operacin sirve de ayuda a los dems prog ramad ore s que quieran t rab aj ar con este cdigo.

Cmo usar argumentos de lnea de comandos


Mucha s de las aplicaciones de la p lat af orma W indows aceptan par met ros de lnea de comandos. Para acept ar p ar met ro s de lnea de comandos dentro la a pl i cacin C#. es necesario declarar una matriz de cadenas como nico par amet ro del m t o do Main, como se puede a pr eci ar en el siguiente cdigo:
class Classl static void M a i n ( s t r i n g [ ] args)

{
public

{
foreach (string arg i n args) System.Cons ole.WriteLine (arg) ;

} } Aqu, el mtodo Main est contenido en una clase tpica. Observe que el m t o do Main tiene un p ar m et ro definido, una matriz de c adenas que ser a l m a cenada en la variable args. Usa el comando foreach para recorrer todas las cadenas almac enada s dla matriz args y a continuacin se escriben esas c a d e nas en la consola. N O T A : Si se est usando Visual Studio .NET para programar C#, la ma triz de cadenas se aade automticamente cuando se crea una aplicacin de consola. Si se ejecuta la aplicacin anterior sin parmetros, no ocurrir nada. Si se ejecuta una aplicacin como la siguiente:
Sampleap.exe parameterl p a r a m e t:er 2

el resultado ser algo como esto:


pa r a m e t e r J par ame t e r 2

Los ar gument os de lnea de c omando son un modo excelente de prop or ci on ar modificadores a la aplicacin; por ejemplo, par a activar un archivo de registro mientras se ejecuta la aplicacin.

Cmo devolver valores


C uando se crea una aplicacin, suele ser til dev olver un valor a la aplicacin que la inici. Este valor indica al p rog rama que hace la llamada o a la secuencia

207

de comandos por lotes si el p ro g ra ma se ejecut con xito o fall. P ar a ello, basta con asignar al mtodo Main un valor de devolucin int en lugar de void. C uand o el mtodo Main est listo par a finalizar, slo hay que usar la pal ab ra clave return y un valor que devolver, como se puede apr eci ar en el siguiente ejemplo:
class Classl static == int M a i n ( s t r i n g [ ] args) "fail")

{
public

{
f (args [0]

return
return

1;
0;

} } Esta aplicacin acepta un par met ro f a i l o cualquier otra pal abr a (quizs,

success). Si la palabra fail se p as a a esta aplicacin como parmetro, el


p r o gr a ma devuelve el valor 1, lo que indica un fallo en el programa. En caso contrario, el p r o gr a ma devuelve 0. lo que indica que el p r o gr a ma finaliz con normalidad. Se puede c om p r o b a r el funcionamiento del p ro g r a m a simplemente haciendo que un archivo p or lotes ejecute la aplicacin y que luego realice a l g u nas acciones dependiendo del cdigo devuelto. El siguiente cdigo es un simple archivo por lotes que realiza esta funcin:
@echo off retval.exe goto success

a n s w e r :errorlevel

:answe r 0 echo Program had goto end

return code

(Success)

:answe r 1 echo Program had return code goto end :end echo D o n e !

(Failure)

En el cdigo anterior se puede apr eci ar que se llama al p ro g ra ma con un par met ro success. Al ejecutar este p ro g ra ma por lotes, aparece el siguiente mensaje:
Program had return code 0 (Success)

Si se edita este p ro gr am a por lotes par a que pase la pal ab ra fail como parmet ro, entonces a pa rec er un mensaje que confirma que el p ro gr ama termin con un cdigo de salida 1.

208

El cuerpo de la clase
El cuerpo de la clase puede incluir instrucciones cuya funcin se incluya en una de estas categoras. Constantes Campos Mtodos Propiedades Eventos Indizadorcs Operadores Constructores Destructores Tipos

Cmo usar constantes


Las constantes de clase son variables cuyo valor no cambia. El uso de c ons t a n t e s p e r m i t e q ue el c d i g o r e s u l t e m s l egi bl e p o r q u e p u e d e n i n cl u i r identificadores que describan el significado del valor a cualquiera que lea el cdi go. Se puede escribir un cdigo como el siguiente:
if (Ratio == 3.14159) System.Console.WriteLine ("Shape

a circle");

El compilador de C# acept a perfectamente este cdigo, pero puede ser un poco difcil de leer, especialmente p ar a alguien que lea cdigo por pr imer a vez y se pregunte qu es el valor de coma flotante. Si se le da un nombre a la constante, por ejemplo pi, se puede escribir el siguiente cdigo:
i f (Rat io == P i ) System.Console.WriteLine("Shape

a circle") ;

El uso de constantes presenta otras ventajas: Se le da valor a las constantes cuando se las declara y se usa su nombre, no su valor, en el cdigo. Si por al guna razn es necesario ca mbi ar el valor de la constante, slo hace falta cambi arl o en un sitio, donde se declara la constante. Si se escribe en las instrucciones de C# el valor real, un cambio en el valor significara que h abr a que revisar todo el cdigo y c amb ia r ese valor.

209

Las constantes indican cspecificamcntc al compi lador de C# que. a dife rencia de las variables normales, el valor de la constante no puede c a m biar. El compilador de C# emite un error si algn cdigo intenta ca mbi ar el valor de una constante. La es tructur a de la declaracin de una constante es la siguiente: La pal abra clave c o n s t Un tipo de dato par a la constante Un identificador Un signo igual El valor de la constante

La definicin de una constante p ar a pi sera:


class M y C l a ss

I
public public const stat i c double vo i d Pi 3.141592 6 5 3 5 8 9 7 9 3 2 3 8 4 6 2 6 433832795;

Main( )

{ } }

NOTA: Este captulo usa la palabra clave p u b l i c para indicar que los elementos del cuerpo de clase estn disponibles para el resto del cdigo de la aplicacin. Posteriormente se examinan algunas alternativas a la palabra clave p u b l i c que pueden usarse cuando se hereda una clase de otra.
C# permite colocar varias definiciones de constantes en la misma linea, s iem pre que todas las constantes tengan el mismo tipo. Se pueden s eparar las defini ciones de constantes con una coma, como en el siguiente ejemplo:
/ia s s M y C 1ass pub i i const mt One = 1, Two = 2, Th ree = 3;

p1 1b 1 ic s t a t ic v o i d M a i n O

i ) }

Cmo usar campos


Los cam pos son miembros de datos de una clase. Son variables que pertenecen a una clase v. en trminos de progr amaci n orientada a objetos, gestionan el

210

estado de la clase. Se puede acceder a los c ampo s definidos en una clase m e diante cualqui er mtodo definido en la mi s ma clase. Un c a mp o se define exact ament e igual que cualqui er variable. Los campos tienen un tipo y un i dent ifi cados Tambi n se puede definir un c a mpo sin un valor inicial:
class MyClass int Fieldl;

{
public public

static void M a i n ( )

{ } } T amb in se puede definir un ca mp o con un valor inicial:


class MyClass int Fieldl = 123;

{
public public

static

void M a i n ( )

{ } } Para indicar que los campos son de slo lectura escriba antes de la declaracin la pal abr a clave r e a d o n l y . Si usa la pal ab ra clave r e a d o n l y . deber escri birla j us t o antes del tipo del campo:
class MyClass readonly int Fieldl;

{
public public

static void M a i n ( )

{ } } Se puede establecer el valor de un c a mpo de slo lectura al dec la rar el campo o en el const ructor de la clase. Su valor no puede establecerse en ningn otro momento. Cual qui er intento de ca mb ia r el valor de un ca mpo de slo lectura es detectado por el compi lador de C# y devuelve un error:
error CS0191: No se puede asignar un campo de solo lectura (excepto en un constructor o inicial izador de variable)

Los campos de slo lectura se parecen a las constantes en la medida en que se inicializan cuando se crea un objeto de la clase. La principal diferencia entre u na constante y un ca mpo de slo lectura es que el valor de las constantes debe establecerse en tiempo de compilacin; en otras pal abr as, deben recibir su valor

211

cuando se escribe el cdigo. Los ca mpos de slo lectura permiten es tablecer el valor del c a mpo en tiempo de ejecucin. Como se puede a si gnar el valor de un ca mpo de slo lectura en un cons tructor de clase, se puede determinar su valor en tiempo de ejecucin y establecerlo cuando el cdigo se est ejecutando. Supongamos , por ejemplo, que estamos escribiendo una clase de C# que g e s tiona la lectura de un grupo de archivos de una base de datos. Quizs queramos que la clase publique un valor que especifique el nmero de archivos que hav en la base de datos. Una constante no es la eleccin correcta par a este valor porque el valor de una constante debe establecerse cuando se escribe el cdigo y no podemos saber c u n tos archivos contiene la clase hasta que se ejecute el cdigo. Podemos poner estos datos en un campo cuyo valor puede establecerse despus de que la clase haya empez ado a ejecutarse y se puede det erminar el n umero de archivos. C omo el numero de archivos no cambi a d urante la existencia de la clase, quizs queramos sealar el campo como de solo lectura p ar a que los otros fragmentos de cdigo no puedan c ambi ar su valor.

Cmo usar mtodos


Los m todos son bloques de codigo con nombre en una clase. Los mtodos proporci onan los comport ami ent os de las clases. Pueden ejecutarse por cualquier otro fragment o de cdigo en la clase y. como se expl icara en un capitulo p os te rior. tambin pueden ejecutarlos otras clases.

Cmo usar propiedades


En un capitulo anterior se exami na la est ructur a Point que puede describir un punto en una pantalla con una resolucin de 640 x 480 pxeles. Un modo de implementar esta est ructur a es definirla con miembros de datos pblicos que d es criban las coordenadas del punto:
st.ruct Point

(
pubi ic int X ; public int Y;

} Al u s a r una e s t r u c t u r a co mo sta, los clientes p ueden u s a r la s int axi s struct urename field para t rabaj ar con uno de los campos de la estructura:
Point MyPoint M y P o i n t .X = = new P o i n t ();

10 0;

Los clientes pueden escribir fcilmente este cdigo. Los clientes pueden a c c e der al ca mpo directamente y usar su valor en una expresin.

212

El p robl ema de este enfoque es que los clientes pueden est abl ecer un campo que C# permite, pero que no es logico par a el cdigo. Por ejemplo, si esta gest io nando una est ructura P o i n t que describe un punt o en una pantalla de 640 \ 480 pixeles. el valor lgico ms alto par a X debera ser 639 (suponiendo que los valores legales de X estn entre 0 y 639). Sin embargo, como se especifica que la coor denada X es un tipo i n t . los clientes pueden establecer como valor cualquier valor a ut ori zado dentro de los lmites de los tipos enteros:
MyPoint.X MyPoint.X = -bOO; = 9000;

El compi lador C# acept a este cdigo porque los valores que se asignan a X estn dentro de los lmites vlidos par a los v alores enteros. Una solucin a este probl ema es hacer que los valores sean privados, con lo que seran inaccesibles p ar a otros fragmentos de cdigo y luego aadir un mtodo publico a la es tructur a que establece los valores de X:
struct Point

{ p r v a t e i n t X; p r v a t e i n t Y;
public bool SetX(int NewXValue) | (NewXValue 63 9) )

{
f ( (NewXValue < 0) return false; X = NewXValue; return true;

La ventaja de este enfoque es que obliga a los clientes que quieran as ignar un v alor a X a llamar al mtodo para realizar la tarea:
Point MyPoint = new Point () ;

M y P o i n t .SetX (100) ;

La ventaja del mtodo es que se puede escribir cdigo que valide el nuevo valor antes de que se al macene realmente en el c a mp o y el cdigo del mtodo puede rechazar el nuevo valor si. por lgica, no es adecuado. As pues, los clien tes llaman al mtodo par a establecer un nuevo valor. Aunque este enfoque funciona, llamar a un mtodo par a asi gnar un valor re quiere un poco mas de cdigo que as ignar un valor directamente. Para el cdigo es mas natural asignar un valor a un campo que llamar a un mtodo para que lo asigne. En el mejor de los casos, quer remos lo mejor de los dos elementos, que los clientes puedan leer y escribir directamente los valores de los ca mpos usando

213

instrucciones de asignacin simples, pero tambin querremos que el cdigo inter venga por ant ici pado y haga todo lo necesario p a r a obtener el valor de un campo o validar el nuevo valor antes de que se asigne. Afor tunadament e, C# ofrece esta posibilidad con un concepto de clase llamado p ro pieda d. Las propiedades son mi embros identificados que pr opor ci onan acceso al e s ta do de un objeto. Las propiedades tienen un tipo y un identificador y tienen uno o dos fragment os de cdigo asociados a ellos: una base de cdigo get y una base de cdi go set. Estas bases de cdigo reciben el nombre de descriptores de a cc e so. C uan do un cliente accede a u na propiedad se ejecuta el descriptor de acceso get de la propiedad. Cu an do el cliente establece un nuevo valor p a r a la p rop ie dad se ejecuta el descri ptor de acceso set de la propiedad. Para mos trar cmo funcionan las propiedades, el listado 9.1 usa una clase Point que expone los valores de X e Y como propiedades.
L istad o 9.1. Valores Point como propiedades de clase class Point int int int X XCoordmate; YCoordmate;

{
prvate prvate public

{
get

(
return XCoordmate;

} set {
f ((valu >= 0) && (valu < 640)) X C o o r d m a t e = valu;

} }
public int Y

{
get

{
return YCoordmate;

} set {
f ( (valu >= 0) && (valu < 48 0)) YCoordinate = valu;

} }
public static void M a i n () = new P o i n t ();

{
Point MyPoint

214

MyPoint.X = 100; M y Point.Y = 2 00; System.Console . W r i t e L m e ( M y P o m t .X ) ; S y s t em .C on so le .W ri te Li ne (M yP oi nt .Y ); MyPoint.X = 600; My Po in t. Y = 600 ; System.Console.WriteLine ( My Po m t . X ) ; System. Con s o l e . W r i t e L m e (MyPoint. Y ) ;

Este cdigo dcclara una clase Point con los valores X e Y como p r op i ed a des. El mtodo Main ( ) crea un nuevo objeto de la clase Point y accede a las propiedades de la clase. La clase Point define dos ca mpos privados que contienen los valores de las coor denadas del punto. C omo estos ca mpos son privados, el cdigo que se e n cuentra fuera de la clase Point no puede acceder a sus valores. La clase tambin define dos propi edades pbl icas que permiten que otros fragment os de cdigo trabajen con los v alores de las coordenadas del punto. Las propiedades son publ i cas y pueden ser usadas por otras partes del codigo. La propiedad X es la p rop ie dad pblica que gestiona el valor del campo privado XCoord ina te y la propiedad Y es la propiedad pblica que gestiona el valor del campo privado YCoordi nate. Las dos propiedades tienen un descriptor de acceso get y otro set. La figura 9.1 muest ra el resultado del listado 9.1.
CV

C:\WINDOWS\System32\cmd.exe in g 9 ~ l. exe

-ini

C:\> L is t 100 200 600 200 C :\> _

Figura 9.1. Las propiedades de clase ayudan a almacenar los valores del punto

Descriptores de acceso get


Los descriptores de acceso get solamente devuelven el valor actual del campo correspondiente: el descri ptor de acceso de la propiedad X devuelve el valor ae-

215

tual de Xcoordinate y el descri ptor de acceso de la propiedad Y devuelve el valor actual de Ycoordinate. Cada descriptor de acceso get debe devolver un valor que coincida o pueda ser convertido implcitamente al tipo de la propiedad. Si el descriptor de acceso no devuelve un valor, el comp il ad or de C# emite el siguiente mensaje de error:
error CS0161: 'MyClass.Pr op e r t y .ge t ' : no todas codigo devuelven un valor las rutas de

Descriptores de acceso set


Los descriptores de acceso set del ejemplo son un poco ms compl icados porque tienen que validar el nuevo valor antes de que sea realmente as ignado al campo asociado. Observe que el descriptor de acceso usa la p al ab ra clave valu. El valor de este identificador es el valor de la expresin que aparece despus del signo de igualdad cuando se llama al descriptor de acceso set. Por ejemplo, examine la siguiente instruccin del listado 9. 1:
MyPoint.X = 100;

El c ompi lador de C# det ermina que la instruccin est asi gnando un nuevo valor a la propiedad X del objeto P o i n t . Ejecuta el descriptor de a cceso set de la clase p a r a realizar la asignacin. Como se est asignando a la propiedad el valor 100. el valor de la p al abr a clave valu del descriptor de acceso set ser 100. Los descriptores de acceso set del listado 9.1 asignan el valor al campo correspondiente, pero slo si el valor est dentro de los limites vlidos. En C#. no est permitido devolver valores de los descriptores de acceso.

4
r i o r r * ' / * ' %

la a sig id a c i ji

ft o ifr se pteilea ustr c c e p e i c | t * aSrSjar de ciqmer eitor. Estas excepciones s estudian m post*

Propiedades de slo lectura y de slo escritura


Las propiedades del listado 9.1 pueden leerse usando su descriptor de acceso

get y puede escribirse en ellas usando su descriptor de acceso set. Estas p r o


piedades reciben el nombre de p r o p ied a d es de lectura y escritura. Cua nd o se disean las clases de C#. hay que i mplementar una propi edad de slo lectura o de slo escritura. En C#. esto es sencillo. Si hace falta i mplementar una propiedad de slo lectura, se especifica una propiedad con un descri ptor de acceso get pero sin descri ptor de acceso set:

216

int X

{
ge t

{
retur n XCoordmate;

} } Si hace falta implementar una propiedad de solo escritura, se especifica una propi edad con un descri ptor de acceso s e t pero sin descriptor de acceso g e t :
int X

{ set {
( (valu > = 0) && (valu < 640))

XCoordmate

= valu;

} }

Cmo usar eventos


C# permite que las clases informen a otras partes del codigo c uando se p r o d u ce una accin sobre ella en la clase. Esta ca paci dad recibe el nombre de m e ca n is mo de evento x permite informar a los elementos que realizaron la llamada si se produce un evento en la clase de C#. Puede disear clases de CU que informen a otros fragment os de cdigo c uando se pr odu zcan determinados eventos en la c l a se. La clase puede devolver una notificacin de evento al fr agment o de codigo original. Quizs quiera usar un evento par a informar a otros fragmentos de cdi go de que se ha compl et ado una operacin muy larga. Suponga, por ejemplo, que quiere disear una clase de CU que lea una base de datos. Si la actividad sobre la base de datos va a requerir mucho tiempo, ser mejor que otras partes del cdigo realicen otras acciones mientras se lee la base de datos. Cu an do se completa la lectura, la clase de C U puede emitir un ev ento que indique "la lectura se ha c o m pletado". Tamb in se puede i nformar a otras partes del cdigo cuando se emita este ev ento y el codigo puede realizar la accin indicada c uando reciba el ev ento de la clase de C#.

Cmo usar indizadores


Algunas de las clases pueden ac tu ar como contenedores de otros valores. Supongamos , por ejemplo, que estamos escribiendo una clase de CU llamada R a i n b o w que permite a los clientes acceder a los valores de cadenas que n o m bran los colores del arco iris en orden. Queremos que los elementos que realizan llamadas puedan retirar los valores de las cadenas, de modo que usamos algunos mtodos pblicos que permiten a los elementos que realizan llamadas tener acceso a los valores. El listado 9.2 muest ra un ejemplo de este tipo de codigo.

217

Listad o 9.2. Una clase con un conjunto de valores de cadena lass Painbow int GetNumberOfCol ors ( )

public

( return

7;

public

bool

GetColor( m t

Colorlndex,

out

string

ColorName)

{
bool ReturnValue;

ReturnValue = true; s w i t c h (Colorlndex)

{
case 0: ColorName break; = "Red";

case 1 :
ColorName break; = "Orange";

c a s e 2:
ColorName break; case 3: ColorName break; case 4 : ColorName break; case 5 ; ColorName break; = "Yellow";

= "Green";

= "Bl ue ";

= "Indigo";

c a s e 6:
ColorName = "Violet"; break; default: ColorName = "" ; ReturnValue = false; break;

}
return ReturnValue;

public

static

void M a i n ( )

{
int ColorCount; int Colorlndex; Rainbow M y R a m b o w ColorCount

= new Rainbow ( );

= M y R a i n b o w .GetNumberOfCol ors ( );

string ColorName; bool Success; for (Colorlndex = 0; Colorlndex < ColorCount; Col orIndex + + ) out

{
Success = MyRainbow.GetColor(Colorlndex, C o l o r N a m e ); if(Success == true) System. Consol . W n t e L m e (ColorName ) ;

} } } La clase Ranbow del listado 9.2 tiene dos mtodos pblicos:

GetCol orCount ( ) . que devuelve el nmero de colores de la clase

GetColor ( ). que. bas n do se en un numero de color, devuelve el n o m


bre de uno de los colores de la clase

El mtodo Main ( ) crea un nuevo objeto de la clase Rainbow y pide al objeto el nmero de colores que contiene. A continuacin se coloca en un bucle for y solicita el nombre de cada color. El nombre del color aparece en la co ns o la. El resultado de esta aplicacin puede verse en la figura 9.2.
cV C:\WINDOWS\System32\cmd.exe C:\>List ing9--2 .exe Red Orange Vellou Gi'eert Blue Indigo U iolet C:\>_ -=!Ql

Ld

Figura 9.2. Los indizadores recuperan los nombres de los colores.

La clase mantiene una coleccin de valores del mismo tipo de valor, lo que es muy parecido a una matriz. De hecho, esta clase Rainbow t ambi n puede i mplementarse como una matriz y el elemento que realiza la llamada puede usar los corchetes de la sintaxis del descriptor de acceso a la matriz de elementos para recuper ar un nombre de color en particular:
ColorName = Rainbow[ColorIndex] ;

219

Los indizadores permiten que se acceda a las clases como si fuera una matriz. Para especificar qu se debe devolver cuando el elemento que hace la llamada usa corchetes par a acceder al elemento de la clase, se usa un fragmento de cdigo llamado descrip tor de acceso de indizador. Teniendo esto en cuenta, se puede reescribir la clase Rainbow para que permita a los elementos que la llaman acceder a los nombres de los colores u s a n do corchetes en su sintaxis. Se elimina el mtodo GetColor () y se sustituye por un indizador. y se sustituye el mtodo GetColorCount () por una p rop ie dad de slo lectura llamada Count. como se muest ra en el listado 9.3.
L istad o 9.3. Clase Rainbow con un indizador c ]a s s R a in bow

{
public int Count

{
get f return

7;

} }
public string this[int Colorlndex]

{
get

{
switch(Colorlndex)

{
case 0 : return case 1 : return case 2 : return case 3: return case 4 : return case 5 : return case 6 : return default : return "R e d "; "Orange" " Ye 11ow" "Gree n" ; "Blue"; "Indi g o " "Violet" "";

public

static

void M a i n ( )

{
in t Colorlndex;

220

Rainbow M y R a m b o w = new Rainbow ( ) string ColorName; = 0; Colorlndex < M y R a i n b o w .Count ;

for(ColorIndex ColorIndex++)

I
ColorName = M y R a i n b o w [C o 1orIndex ] ; System. Consol . W n t e L i n e (ColorName) ;

} } } Los indizadorcs se parecen a las propi edades porque tienen descriptores de acceso get y set. Si fuera necesario, se puede omitir cua lqui era de estos descriptores de acceso. El indizador del listado 9.3 no tiene el descri ptor de a c c e so set, lo que significa que la clase se puede leer, pero no se puede escribir en ella. Los indizadorcs se es truc tu ran segn los siguientes elementos: Un tipo que indica el tipo de datos que devuelve el descri ptor de acceso La palabra clave this. Un corchete de apertura. Una lista de parmet ros, es tructur ada igual que una lista de p ar met ros de un mtodo. Un corchete de cierre. Un cuerpo de cdigo, entre llaves. El indizador del listado 9.4 recibe un ar gume nt o integral y devuelve una c ade na. de forma par eci da al mtodo GetColor () del listado 9 2
L istado 9.4. Un argum ento entero que devuelve una cadena string ColorName; = 0; Colorlndex < M y R a m b o w .Count ; Co 1 o r Index + + )

f or (Col or Index

{
ColorName = = MyRainbow [Col or Index ] ; System.Consol.WriteLine (Col o r a m e ) ;

} El nuevo cdigo us a los corchetes de la sintaxis del elemento de matriz para obtener el nombre de un color del o b j e t o M y R a i n b o w . Esto hace que el compilador de C# llame al cdigo indizador de la clase, que pa sa el valor de Colorlndex como parmet ro. El indizador devuelve una cadena y la cadena se escribe en la consola.

221

Una clase puede i mplementar ms de un indizador. siempre que los indizadores tengan diferentes listas de parmetros. Las listas de parmet ros de los indizadores pueden tener ms de un par met ro y pueden ser de cualquier tipo que se pueda us ar en el cdigo. No es necesario que los indizadores usen valores enteros como indizadores. Se podr a haber implementado igualmente en la clase Rainbow un indizador que acept ase un valor double:
publie strmg this [double Colorlndex]

NOTA: Como en las propiedades, C# no permite que los descriptores de acceso s e t devuelvan valores. Sin embargo, pueden usarse excepciones para informar de cualquier error.

Cmo usar operadores


Un o per ado r permite definir el comport ami ent o de la clase cuando se usa en una expresin con un oper ador unario o binario. Esto significa que se puede ampl iar el comport ami ent o de operadores predefinidos par a que se ajusten a las necesidades de las clases. Por ejemplo, la clase Point puede i mplement ar c d i go que especifique que se pueden s u ma r dos objetos Point con el operador +. El resultado de la suma sera un tercer objeto Point cuyo estado es el resultado de s umar los otros dos puntos.

Cmo usar constructores


Los co nstructores de estructura son mtodos especiales que se ejecutan c u a n do se crea una v ariable del tipo de la estructura. Los constructores suelen usarse para inicializar una est ructur a con un estado conocido. Se pueden usar constructores en las clases de C# de la misma forma que las est ructuras. Se pueden definir tantos constructores como se desee, siempre que cada const ructor tenga una lista de parmet ros diferente. Se puede escribir una clase Point con constructores de la misma forma que se hizo con la estructura Poi nt. como se puede apr eci ar en el listado 9.5.
Listado 9.5. Una clase Point con dos constructores d a s s P o int

{
p u b 1ic int X; publio int Y; public Point ()

{
X - 0;

222

Y = 0;

}
public P o m t (int InitialX, int InitialY)

{
X = ImtialX; Y = ImtialY;

public

static void M a i n ( ) 200);

{
P o m t M y F i r s t P o m t = new Point(100, Point MySecondPoint = new P o m t { );

( } La clase Point del listado 9.5 tiene dos campos pblicos: X e Y. Tambi n i mplementa dos constructores. Uno de ellos no usa ningn p ar met ro y el otro usa dos parmetros. Los constructores de las clases de C# son muy parecidas a las e st ructuras de C#. Los constructores de clase no devuelven valores y su nombre debe coincidir con el nombre de la clase. La principal diferencia entre los c o ns tructores de estructura y los constructores de clase estriba en que los constructores de clase pueden implementar un const ructor sin parmetros, pero un constructor de es tructur a no puede hacerlo. Si se define una clase sin constructores. C# proporci ona un const ructor por defecto. Este constructor por defecto asigna a todos los campos de las clases sus valores por defecto. Si se inicializa con el signo igual cualqui er ca mp o de una clase, ste se inicializar antes de que se ejecute el constructor:
class Point int X = 100; int Y; P o m t (int ImtialY)

{
public public public

{
Y = I m t i a l Y + X;

} } En esta clase Point. una declaracin de asignacin inicializa el ca mpo X y el const ructor y inicializa el ca mp o Y. Al compilar este cdigo, el compi lador de C# se as egu ra de que el c a mpo X se inicial ice en pri mer lugar.

Cmo usar destructores


Las clases de C# pueden definir un destructor, que es un mtodo especial que se ejecuta cuando el C L R (Ent orno comn de ejecucin) destruye los objetos de

223

la clase. Puede pens ar en los destructores como en lo contrario de los c on s tr uc tores: los constructores se ejecutan cuando se crean objetos y los destructores se ejecutan cuando el recolector de objetos no utilizados destruye los objetos. Este proceso tiene lugar de modo oculto sin consecuencias p ar a el progr amador. Los destructores son opcionales. Es perfectamente vlido escribir una clase de C# sin un dest ructor (y hasta ahora, es lo que hemos estado haciendo en los ejemplos). Si se escribe un destructor, slo se puede escribir uno.

NOTA: A diferencia de los constructores, no se puede definir ms de un destructor para una clase.
Los destructores se disponen de la siguiente forma. El smbolo virgulilla (~). El identificador del destructor, que debe cor responder al nombre de la clase. Un conjunto de parntesis. El listado 9.6 actualiza la clase Point del listado 9.5 con un destructor.
Listado 9.6. Una clase point con un destructor class Point

{
public public publie int. X; int Y; P o m t ()

{
X - 0; Y = 0;

}
public Point (int InitialX, int ImtialY)

{
X = I nitialX; Y = In 1 1 1 a 1Y ;

} - P o i n t () {
X - ; Y - 0;

}
public st.atic void Main ()

224

Point MyFirstPoint = new Point(100, 200); Point M y S e c o n d P o m t = new Point ();

} } Los destructores no devuelven valores; ni tampoco pueden aceptar parmetros. Si se intenta llamar a un dest ructor en el cdigo, el compi lador de C# emite un error. En muchos lenguajes orientados a objetos, se llama a los destructores de clase cuando la variable ya no puede ser usada. Supongamos, por ejemplo, que escribi mos un mtodo y declaramos un objeto P o i n t como una variable local del mto do. C uando se llama al mtodo, se crea el objeto P o i n t y el mtodo puede traba jar con el. C uand o el mtodo llega al final de su bloque de cdigo, el objeto P o i n t va no volver a usarse. En lenguajes como C'++. esto hace que se llame al const ructor de la clase cuando ac aba el mtodo. En C#. esto no tiene por que ocurrir De hecho, no se puede llamar a un des tructor de clase. Recuerde que el C L R implementa una utilidad llamada recolector de objetos no utilizados que destruy e objetos que ya no se usan en el codigo. La recoleccin puede tener lugar mu ch o despus de que el objeto deje de ser accesible. Obs er ve el mtodo M a i n ( ) en el listado 9.7:
Listado 9.7. Demostracin del uso del recolector de objetos no utilizados mediante la estructura Point pubiic static void M a i n ( ) 200);

{
Point MyFirstPoint = new P o i n t (100, Point MySecondPoint = new P o i n t ();

} El mtodo M a i n ( ) crea dos objetos locales P o i n t . Cuando el mtodo M a i n ( ) termina su ejecucin, los objetos locales P o i n t ya no pueden volver a ser usados y el C L R los registra como objetos que pueden ser destruidos cuando se ejecute el recolector de objetos no utilizados. Sin embargo, el recolector de objetos no uti lizados no siempre se ejecuta i nmediatamente, lo que significa que no siempre se llama al dest ructor del objeto inmediatamente.

NOTA: Se llama a los destructores de las clases de C# cuando se destruye un objeto, no cuando su variable deja de ser accesible.
Por ejemplo, s uponga que quiere escribir una clase de C# que gestione un archivo en un disco. Escribiremos una clase llamada F i l e con un constructor que ab ra el archivo y un dest ructor que cierre el archivo:
class File

225

File (string

ame)

{
// abre el archivo

}
-File ()

{
// cierra el archivo

} } Si queremos que esta clase trabaj e en un mtodo:


public statc void M a m ( ) = new F i l e ("myfi1e .t x t ");

{
File MyFile

} El dest ructor de la clase File cierra el archivo, pero en realidad el destructor no se ejecuta hast a que el recolector de objetos no utilizados no se activa. Esto significa que el archivo puede todav a estar abierto mucho despus de que la variabl e MyFile sea inaccesible. Para asegurarnos de que el archivo se cierra lo antes posible, aadimos a la clase File un mtodo Cise (), que cierra el archivo cuando se le llama.

Cmo usar los tipos de clase


Las clases pueden u sar uno de los tipos integrados en C # (int, long o char, por ejemplo) y pueden definir sus propios tipos. Las clases pueden incluir declaraciones de otros elementos, como e st ructur as o incluso otras clases.

Cmo usar la palabra clave this como identificador


En C # se puede emplear la pal abr a clave this par a identificar un objeto cuyo cdigo se est ejecutando, lo que a su vez permite hacer referencia a ese objeto. La p al ab r a clave this se puede empl ear de varias maneras. Y a hemos visto cmo se u s a en un i ndi zador. T a m b i n se puede u s a r como prefi jo de un identificador de variable p ar a advertir al compi lador de que una determinada

226

expresin debe hacer referencia a un ca mpo de clase Observe, por ejemplo, la clase Point en el listado 9.8.
Listado 9.8. C am pos y parmetros con el mismo nombre class Point int X; int Y; int Y)

{
public public

Point (int X,

{
X = X; Y = Y;

)
public static voicl Main ()

{ } 1 Este cdigo no tiene el compo rt ami ent o esperado p orque los identificadores X e Y se emplean en dos ocasiones: como identificadores de ca mpo y en la lista de p ar met ros del constructor. El cdigo debe diferenciar el identificador de campo X del identificador de la lista de par met ros X. Si el codigo es ambiguo, el compi lador de C# interpreta que las referencias a X e Y en las declaraciones del const ructor se refieren a los par met ros y el codigo establece los par met ros con el valor que ya contienen. Se puede usar la p al abr a clave this p ar a diferenciar el identificado!- de c a m po del identificador de parmetro. El listado 9.9 muest ra el cdigo corregido, usando la pal abr a clave this como prefijo del c a mpo de nombre.
Listad o 9.9. Cmo usar this con campos class Point int X; int Y; int Y)

{
public public

Point(int X,

{
t h i s .X = X ; this.Y = Y;

}
public static void M a i n ( )

{ }

227

El modificador static
Cu an do se define un ca mpo o un mtodo en una clase, cada objeto de esa clase creado por el cdigo tiene su propi a copia de valores de ca mpo y mtodos. M e diante la pal abr a clave static. se puede invalidar este comport ami ent o, lo que permite que varios objetos de la mi sma clase compar tan valores de c a mpo y mtodos.

Cmo usar campos estticos


Ret omemos el ejemplo de la clase Po i n t . Una clase Po i nt puede tener dos campos par a las coordenadas ,v e v del punto. Todos los objetos creados a partir de la clase Point tienen copias de esos campos, pero cada objeto puede tener sus propios v alores para las coordenadas x e v. Asignar un v alor a las coordenadas x e v de un objeto no afecta a los v alores de otro objeto:
Point MyFirstPoint = new P o m t (100, 200); Point MySecondPoint = new P o i n t (150, 2 50);

En este ejemplo se crean dos objetos de la clase Point. El primer objeto asigna a su copia de las c o o r d e n ad a sx e v los v alores 100 y 200. respectiv amente y el segundo objeto asigna a su copia de las coordenadas .v e v los v alores 150 y 250. respectiv amente. C ad a objeto gu ar d a su propia copia de las c o o r d e na da s x e r. Si se coloca el modi fi cador static antes de una definicin de ca mpo se est indicando que todos los objetos de la misma clase compar tir n el mismo valor. Si un objeto asigna un valor esttico, todos los dems objetos de esa mi sma clase c ompar tir n ese mismo valor. Observ e el listado 9.10.
L istad o 9.10. C am pos estticos class Pomt static static mt X int X C o o r d m a t e ; m t '/Coordnate;

{
public public public

(
get

{
return XCoordmate;

} }
public mt Y

{
get

228

return

YCoordmate;

public

static void M a i n ( )

{
Point MyPoint = new P o i n t (); Sy st em .C on so le . W r i t e L i n e ( " B e f o r e " ) ; Sy s t e m .Console.WriteLine; System.Console . W n t e L m e ( M y P o m t .X) ; System.Console.WriteLine ( M y P o m t .Y) ; Point.XCoordinate Point. Y C o o r d m a t e =

100;
2 00 ;

Sy st em .C on so l .W r i t e L i n e ( " A f t e r " ) ; System.Consol.WriteLine ("----=") ; Sy s t e m . C o n s o l . W r i t e L i n e ( M y P o i n t .X); Sy st em .C on so l . W r i t e L i n e ( M y P o i n t . Y ) ;

} } La clase Point del listado 9.10 tiene dos campos estticos enteros llamados XCoord i nate e YCoord inate. Tambi n tiene dos propiedades de solo lectu ra. llamadas X e Y. que devuelven los valores de las variables estticas. El mtodo Ma i n () crea un nuevo objeto Point y escribe sus coordenadas en la consola. A continuacin ca mbi a los valores de los campos estticos y vuelve a escribir las coor denadas del objeto Point. El resultado puede verse en la figura 9.3.

Figura 9.3. El uso de cam pos estticos simplifica la codificacin.

Hay que tener en cuenta que los valores de las coor denadas del objeto P o i n t han cambiado, aunque los valores del propio objeto no hayan cambiado. Esto es

229

debido a que el objeto Point compar te campos estticos con todos los dems objetos Point y c uando los campos estticos de la clase Point cambian, todos los objetos de esa clase se ven afectados. Los ca mpos estticos que se usan en expresiones no estn prefijados con un identificador de objeto sino con el nombre de la clase que contiene los campos estticos. La siguiente instruccin es un error p o r q u e MyPoint hace referencia a un objeto v XCoordinate hace referencia a un campo esttico:
M y P o i n t .XCoordinate = 100;

Este codigo hace que se p r o du z ca el siguiente error del compi lador de C#:
error CS0176: No se puede obtener acceso al miembro esttico 'Point.XCoordinate' con una referencia de instancia; utilice un nombre de tipo en su lugar

El ca mpo esttico debe estar prefijado con el nombre de la clase:


Point.XCoordinate = 10 0;

Cmo usar constantes estticas


Las constantes operan de la mi sma forma que los campos a menos que esten precedidas por la pal abr a clave static; en ese caso, cada objeto de la clase contiene su propi a copia de la constante. Sin embargo, hacer que cada objeto de una clase contenga su propia copia de una constante supone desperdiciar m e m o ria. Sup on gamos que estamos escribiendo una clase llamada Circle. que g e s tiona un crculo. Como estamos trabaj ando con un crculo, usaremos bast ant e el valor pi. Decidimos que pi sea una constante p a r a referirnos siempre a ella con un nombre, en lugar de con un enorme nmero de coma flotante. A ho ra bien qu ocurre si creamos mil objetos c rc ul o7 Por defecto, cada uno de ellos tiene su propi a copia de pi en memoria. Esto es un desperdicio de m e mo ria. especialmente porque p i es una constante y su valor nunca cambia. Es mas lgico que ca da objeto de la clase Circle use una sola copia de la constante pi Para eso sirve la pal abr a clave static. Si se usa la pal abr a clave static con una constante ca da objeto de una clase t rabaj a con una sola copia del valor de la const ant e en memoria:
const double Pi = 3.1415926535897932384626433832795;

En general hay que intentar que todas las constantes sean estticas de modo que slo haya u na copia del val or de la constante en memori a a la vez.

Cmo usar mtodos estticos


Los mtodos que se definen mediante la p al ab r a clave static reciben el n om br e de mtodos estticos. Los mtodos que no se definen mediante la pal abra

230

clave static reciben el n ombre de m todos de instancia. Los mtodos estticos estn incluidos en una clase, pero no pertenecen a ningn objeto especfico. Igual que los c ampos estticos y las constantes estticas, todos los objetos de una clase compar ten una copia de un mtodo esttico. Los mtodos estticos no pueden hacer referencia a ni nguna parte de un objeto que no est t ambi n ma rc a do como esttico, como puede a pr eci ar se en el listado 9.11.
Listad o 9.11. M t o d o s e st t i c o s q u e l l a ma n a un m t o d o d e i n s t an c i a d e c l a s e class Listing9_9 static void M a i n ( )

{
public

{
CallMethod () ;

}
void CallMethod( ) from Cal lMethod ( ) ") ;

{
System. Consol . W r i t e L m e ("Helio

} } El cdigo anterior no se compi la y el comp il ado r de C# emite el siguiente error:


error CS0120: Se requiere una referencia campo, mtodo o propiedad no estticos ' L i s t i n g9 _9 .C al lM et ho d( )' a objeto para el

El error del cdigo del listado 9.11 es que hay un mtodo esttico, Main () . que intenta llamar a un mtodo de instancia. CallMethod (). Esto no est permitido porque los mtodos de instancia son parte de una instancia de objeto y los mtodos estticos no. P a ra corregir el cdigo, el mtodo esttico Main ( ) debe crear otro objeto de la clase y l lamar al mtodo de i nstancia desde el nuevo objeto, como mue st ra el listado 9.12.
L istad o 9.12. M t o d o s e s t t i c o s q u e l l a m a n a un m t o d o d e i n s t an c i a d e c l a s e class Listing9_10 static void M a i n ( ) - new Listing9_10 ( );

{
public

{
Listing9_10 MyObject

MyObject.CallMethod( );

}
void CallMethod()

231

S y s t e m .C o n s o l e .W r i t e L i n e ("Hel1o

from

C a l l M e t h o d ()");

} } La figura 9.4 muest ra el resultado del listado 9.12.


C. C:\WIINDOWS\System32\cmd.exe
i , i - t i i i f) v i u II.* l i e t i'.,;, G , l i m . - i . l t

Id
Figura 9.4. Ejemplo de una llamada a un mtodo esttico desde dentro de la misma clase

Como todos los elementos de las clases estticas, los mtodos estticos a p a r e cen slo una vez en memoria, por lo que se debe m ar c ar el mtodo Main ( ) como static. Cuand o el cdigo N E T se c arga en memoria, el C L R empieza a ejecu tar el mtodo Main ( ) Recuerde que slo puede haber un mtodo Main ( ) en m emori a a la vez Si una clase tiene varios mtodos Main (). el C L R no sabra qu m t odo Main ( ) ejecutar cuando el cdigo lo necesite. Usar la p al ab ra clave static en el mtodo Main ( ) hace que slo haya disponible en memori a una copi a del mtodo Main ( ) .

NOTA: Mediante el uso de parmetros de lneas de comandos en el compilador de C#, es posible incluir ms de un mtodo Main () dentro de una aplicacin. Esto puede ser muy til cuando se quiere probar ms de un mtodo para depurar el cdigo.

Resumen
C# es un lenguaje orientado a objetos y los conceptos que se emplean en los lenguajes orientados a objetos se pueden aplicar a C#. Las clases de C# pueden usar varios tipos de miembros de clase:

232

Las constantes dan nombre a un valor que no c ambi a en todo el cdigo. El uso de constantes hace que el cdigo sea ms legible porque se pueden usar los nombres de las constantes en lugar de los valores literales. Los cam pos contienen el estado de las clases. Son variables que estn asociadas a un objeto. Los mtodos contienen el comport ami en to de la clase. Son fragment os de codigo con nombre que realizan una accin det erminada p a r a la clase. Las pro p ied a d es permiten que los fragment os que hacen llamadas tengan acceso al estado de la clase. Los fragmentos que hacen la llamada acceden a las propiedades con la mi sma sintaxis object .identif ier que se emplea par a acceder a los campos. La ventaja de las propiedades sobre los campos es que se puede escribir cdigo que se ejecuta c uando se consultan o se asignan los valores de la propiedad. Esto permite escribir cdigos de validacin p a r a evitar que se asignen nuevos valores a las propiedades o par a calcul ar dinmi cament e el valor de una propiedad que est siendo consultada. Se pueden i mplementar propiedades de lectura y escritura, slo de lectura o slo de escritura. Los eventos permiten que la clase informe a las aplicaciones que hacen la l lamada cuando se produ zcan determinadas acciones en su interior. Las aplicaciones que hacen la llamada pueden suscribirse a los eventos de clase y recibir avisos cuando se pro du zcan dichos eventos. Los m d iza d o res permiten que se acceda a la clase como si fuera una m a triz. Las aplicaciones que hacen la llamada pueden u s ar la sintaxis de elemento de matriz de corchetes par a ejecutar el cdigo descriptor de ac ce so del indizador de la clase. Los indizadores se usan cuando una clase contiene una coleccin de valores y es ms lgico consi derarl a una matriz de elementos. Las clases pueden redefinir los operadores, como se vio en un capitulo anterior. Los operadores pueden ay ud a r a determinar cmo se comport a una clase cuando se usa en una expresin con un operador. Los co nstructores son mtodos especiales que son ejecutados cuando se crean objetos en la clase. Se puede definir ms de un constructor, cada uno con una lista de par met ros diferente. Tambi n se puede definir una clase sin constructores. En ese caso, el compi lador de C# genera un constructor por defecto que inicializa t odos los ca mpos del objeto con el valor cero. Los destructores son mtodos especiales que son ejecutados cuando se destruyen objetos en la clase. Una clase slo puede tener un destructor. Debido a la interaccin con el cdigo N E T y el CLR. los destructores se ejecutan c uando el recolector de objetos no utilizados recoge un objeto, no c uando el cdigo ya no puede ac ceder al identificador del objeto.

233

Las clascs pueden definir tipos propios y estos tipos pueden contener de finiciones de es tru ctur a e incluso definiciones de otras clases. Una vez definidos estos tipos, la clase puede usarlos de la mi sma forma que los tipos enteros en C#. La pal abr a clave this hace referencia a la instancia actual de un objeto. Se usa como prefijo p ar a diferenciar a un identificador de campo de un identificador de p ar me tr o con el mi smo nombre. La palabra clave static advierte al compi lador de C# de que todos los objetos de la clase compart en una sola copia de un campo o de un objeto Por defecto, cada ca mpo y cada mtodo de una clase de C# mantiene su propia copia de los valores del c a mp o en memoria. Los elementos de la clase que no usan la pal abr a clave static reciben el n ombre de m todos de instancia. Los el eme n tos de clase que usan la pal ab ra clave static reciben el nombre de m todos es t tic o s .

234

ifil Cmo sobrecargar operadores

C# define el c omport ami ent o de los operadores cuando se usan en una e x pr e sin que contiene tipos de datos integrados en C#. Por ejemplo. C# define el comport ami ent o del oper ado r suma calcul ando la s uma de dos operados y ofre ciendo la s uma como el valor de la expresin. En C#. se puede definir el c omport ami ent o de la may ora de los operadores estndar para que puedan usarse en est ructuras y clases propias. Se pueden escri bir mtodos especiales que definen el compo rt ami ent o de la clase cuando a p a r e cen en una expresin que usa un oper ador de C#. Esto permite que las clases se puedan empl ear en expresiones que par ecer a ms lgico que escribieran otras partes del cdigo. S upongamos , por ejemplo, que est amos escribiendo una clase que gestiona un conjunto de archiv os de una base de datos. Si algn otro f r agmen to de cdigo tiene dos objetos de esa clase, quer r poder escribir una expresin que sume los archiv os y los al macene en un tercer objeto Esto parece una o p e r a cin de s uma y parece lgico que otros fragment os del cdigo tengan partes como la siguiente:
Records Records 1; Records Records2; Records Records3; Records3 = Recordsl + Records2;

237

La clase Records puede incluir un mtodo que especifique cuntos objetos de la clase ac tua rn de una determinada forma cuando se usen en expresiones con el oper ado r de suma. Estos mtodos reciben el nombre de im plem entaciones de operadores definidas p o r el usuario y la operacin orientada a objetos para definir el c omport ami ent o de los oper adores de una clase recibe el nombre de sobreca rga de operador. Se emplea la p al abr a "sobrecarga" porque el cuerpo del cdigo s obr ecar ga el significado del mi smo op er ador y hace que se comport e de for ma diferente, dependiendo del contexto en el que se use el operador. Todos los mtodos de sobre carg a de operadores deben declarase con las p a l a bras clave static y public.

Operadores unarios sobrecargabas


C# permite sobrecargar en sus clases y estructuras el comportamiento de estos operadores unarios: U n a n o mas Unario menos Negacin lgica Ope rado r de compl ement o bit a bit Incremento prefijo Decrcmento prefijo La palabra clave true La palabra clave false

Cmo sobrecargar el unario ms


Si se quiere s obre carg ar el unario ms. el unario menos, una negacin o un o per ador de complemento bit a bit en una clase o estructura, hay que definir un mtodo con las siguientes caractersticas: Un tipo devuelto deseado La palabra clave operator El oper ador que se quiere sobre carga r Una lista de par met ros que especifique un slo par met ro del tipo o es tru ct ura que contiene el mtodo del oper ad or s obrecargado Ret omemos el ejemplo de la clase Point utilizada en un captulo anterior S upongamos que queremos aadir un o per ador unario ms a la clase que. cuando

238

se emplee, se asegure de que las dos coordenadas del punto sean positivas. Esto se implementa en el listado 10.1.
L istado 10.1. Cmo sobrecargar el operador unario ms class Pomt int X; int Y ; static Pomt operator + (Pomt RValue)

{
public public public

{
Pomt NewPomt = new P o m t ( );

f ( R Va lu e.X < 0) N e w P o m t .X = - (RValue .X ) ; e1se N e w P o m t . X = RValue.X; i f (R V a 1u e .Y < 0 ) N e w P o m t .Y = - (RValue .Y) ; e 1s e NewPoint.Y = RValue.Y; return NewPomt;

}
public static void M a i n ( ) = new Point ();

{
Point MyPoint

M y P o m t . X - -100; M y P o i n t .Y = 200; Sy st em .C on so l . W r i t e L i n e ( M y P o i n t . X ) ; Sy st em .C on so l . W r i t e L i n e ( M y P o i n t . Y ) ; MyPoint = + M y P o m t ; Sy st em .C on so l .W ri t e L i n e ( M y P o i n t . X ) ; Sy st em . C o n s o l . W r i t e L i n e ( M y P o i n t .Y );

} } El mt odo M a i n ( ) crea un objeto de tipo P o i n t y asigna a sus coordenadas iniciales los valores (100. 200). A continuacin aplica el oper ador unario ms al objeto y vuelve a as ignar el resultado al mismo punto. Por ltimo, escribe las coordenadas \ e y en la consola. En la figura 10.1 se puede ver el resultado del listado 10.1. Las coordenadas del punto han cambi ado de (-100. 200) a (100. 200). El cdigo con el oper ador s obrecargado se ejecuta cuando se llega a la siguiente instruccin:
MyPoint = +MyPoint;

239

ca C:\WINDOWS\System32\cmd.ene C :' . I-i-l u n 1H l . . *.: 1 Un 1HH 2 un C:\>_

Ld
Figura 10.1. Sobrecarga del operador unario

Cuando se llega a esta instruccin, se ejecuta la s obrecarga del operador unario ms para la clase Point. La expresin situada a la derecha del signo igual se u sar como el p ar m et ro del mtodo.

NOTA: La expresin situada a la derecha de un operador de asignacin suele ser denominada r v a lu e , que es la abreviatura de "valor derecho". La xpresin la izquierda del operador de asignacin suele ser denomina da Iv a l e , que 68 U abreviatura de "valor izquierdo". El uso de RValue par ap arar el mtodo de sobrecarga de operadores determina que se f|;|^iKacb el r v s lu e de la asignacin. Esto es slo na convenci de requisito. Si lo desea, puede asignar otro nombre a los idatifaror vlido permitido por #.
Este mtodo crca un nuevo objeto Point y a continuacin exami na las c o or denadas del rvalue proporcionado. Si alguno de los p ar met ro s es negativo, sus valores se cambi an de signo, volvindose por tanto valores positivos, y estos nuevos valores positivos se asignan al nuevo punto. Los valores que no son n e ga tivos se asignan al nuevo punto sin ninguna conversin. A continuacin el mtodo devuelve el nuevo punto. El valor devuelto por el o per ado r se usa c omo Iva le par a la declaracin original. El tipo de retorno de las sobrecargas del operador par a el unario ms. el unario menos, la negacin o los operadores de c o mp l e mento bit a bit no tienen el mi smo tipo que el rvalue. Puede ser cualquier tipo de C# que sea adecuado p ar a el operador.

Cmo sobrecargar el unario menos


Se puede ef ect uar la s obr ecar ga del unario menos de la mi sma maner a que se realiza la del unario ms.

240

El l i s ta d o 10.2 s o b r e c a r g a el o p e r a d o r m en os p a r a g e s t i o n a r la cl ase Point.


L istad o 10.2. S obrecarga del unario menos class Point int X; int Y; static Point operator (Point RValue)

{
public public pubJic

{
Point N e w P o m t if = new Point () ;

(RValue.X > 0) N e w P o m t . X = - (RValue.X) ; N e w P o m t . X = RValue.X;

else

if

(RValue.Y > 0) N e w P o m t . Y = - (RValue .Y) ; NewPoint.Y = RValue.Y;

else

return

NewPoint;

}
public static void M a i n ( )

{
Point MyPoint = new P o i n t (); M y P o m t . X = -100; MyPoint.Y = 200; Sy s t e m . C o n s o l e . W r i t e L i n e ( M y P o i n t .X ); S yst em .C o n s o l e . W r i t e L i n e ( M y P o i n t . Y ) ; MyPoint = -MyPoint; Sy st em . C o n s o l e . W r i t e L i n e ( M y P o i n t .X ); System.Console.WriteLine ( M y Po mt .Y ) ;

Tras definir el nuevo oper ad or Point. simplement e se define la accin que debe realizar cuando se presente con una variable del tipo Point. El listado 10.2 declara la c o o r d e n a d a x como -100 y la c oor denada ;' como 200. Estos valores se escriben en la consola p ar a u na verificacin visual y luego se usa el o per ador sobrecargado. Despus de que la aplicacin de ejemplo haya realizado la resta de la clase Point. los valores resultantes se escriben en la vent ana de la consola par a indicar que el comport ami ent o ha sido el esperado. La figura 10.2 muest ra el resultado del listado 10.2. Ha st a ahora, en este captulo hemos estudiado el unario ms y el unario m e nos. Estos operadores efectan operaciones sobre un valor dado (por eso se lia-

241

man "unarios"). Los dems operadores mat emt icos bsicos que pueden usarse sobre un valor se s obrecargan de la mi sma manera.
c;\ C:\WIINDOWS\System32\cmd.exe C :\> L ic t. in y l 0 2 . e x e 10 200 100 -2 0 0 C :\> _

-=Jni

Figura 10.2. Sobrecarga del unario menos

En la siguiente seccin se describe un oper ador de otro tipo, el oper ado r de compl ement o bit a bit.

Cmo sobrecargar complementos bit a bit


El op er ad or de compl ement o bit a bit slo tiene definiciones p ar a tipos int. uint. long y ulong. El listado 10.3 lo s obrecarga par a t rabaj ar con la clase po i n t .
Listado 10.3. Sobrecarga del operador de complem ento bit a bit class Point int X; int Y; static Point operator ~ (Point RValue)

{
public public public

{
Point NewPoint = new Point ( ); NewPoint.X = -RValue.X; NewPoint.Y = -RValue.Y; return NewPoint;

}
public static void M a i n ( ) = new P o i n t ();

{
Point MyPoint

242

M y P o i n t .X = 5; MyPoint.Y = 6 ; S ys te m.C on s ole . W r i t e L i n e ( M y P o i n t . X ) ; System.Console.WriteLine (MyPo i n t .Y) ; MyPoint = -MyPoint; S y s t e m . C o n s o l e . W ri te Li ne (M yP oi nt . X) ; S ys te m.C on s ole . W r i t e L i n e ( M y P o i n t . Y ) ;

} } El resultado de una operacin de compl ement o bit a bit no se conoce con exactitud hasta que se ven los resultados hexadcimales de la operacin. El l ista do 10.3 genera el compl ement o de los valores enteros 5 y 6. El resultado de esta operacion (que aparece en la figura 10.3) es -6 y -7. respectivamente. Cuand o se obs er van los valores hexadci mal es de los valores de ent rada y salida, es fcil deducir lo que est ocurriendo en realidad.
CV

C:\WINDOWS\System32\cmd.exe

'v;

- i i X i

5
6

C:\>Listingl0-3.exe
- 6

-7 C:\>_

I
DI
i

Figura 10.3. Sobrecarga de un complem ento bit a bit

Tabla 10.1. Valores de entrada y salida para operaciones de com plem ento bit a bit

Input
0x0000000000000005 0x0000000000000006

Output
0xf f f f f f f f f f f f f f f A 0xf f f f f f f f f f f f f f f 9

Antes de s ob re car ga r un operador, es necesario entender per fectamente como funciona. En caso contrario podra obtener resultados inesperados.

243

Cmo sobrecargar el incremento prefijo


Para sobrecargar los operadores de incremento prefijo o de decrcmento prefijo en una clase o estructura, se define un mtodo con las siguientes caracteristicas: Un tipo devuelto que especifica el tipo de clase o e st ruc tur a que contiene el mtodo del op er ado r sob re carga do La palabra clave op era to r El operador que se s obrecarga Una lista de par met ros que especifica un solo par met ro del tipo de la clase o est ructur a que contiene el mtodo del oper ado r s obrecargado Por ejemplo, observe el listado 10.4. Esta clase modifica la clase Point para sobre carga r el operador de incremento prefijo. El oper ador se sobrecarga para au ment ar en una unidad las coordenadas .v e v.
Listado 10.4. Cmo sobrecargar el incremento prefijo class Point public public public int X ; in t Y ; static Point operator ++ (Point RValue)

I
Point MewPomt - new Point () ;

NewPoint.X - RValue.X + 1; N e w P o m t . Y = RValue. Y + 1; return N e w P o m t ;

}
public static void M a m () = new P o i n t ();

{
Point M y P o m t

MyPoint.X = 10 0; M y P o m t . Y = 200 ; System.Consol.WriteLine ( M y Po mt .X ) ; System. Con s ole. W r i t e L m e ( M y P o m t . Y) ; M y P o m t = ++MyPomt; System.Con sol.WriteLine ( M y P om t. X) ; System.Con.sol.WriteLine(MyPoint.Y);

} } Si se compila y ejecuta el cdigo del listado 10.4 se escribe lo siguiente en la consola:

244

1o o
2 00

101 20 1

Cmo sobrecargar el decremento prefijo


Ahora vamos a apr ender a s ob re carga r el operador de decrcmento par a g e s tionar la clase Point. El listado 10.5 contiene el listado completo par a s obr e c a rg ar el oper ador de forma muy pareci da a como se hizo con el oper ador de incremento prefijo que ac a ba mos de estudiar.

Figura 10.4. R e s u l t a d o d e la e j e c u c i n del c d i g o c o m p i l a d o del listado 1 0 . 4

Listado 10.5. S o b r e c a r g a del o p e r a d o r d e d e c r e m e n t o prefijo class Point

{
public public public int X; int Y; static Point operator (Point RValue)

{
Point NewPoint = new P o i n t ();

N e w P o m t . X = RValue.X - 1; NewPoint.Y = RValue.Y - 1; return NewPoint;

}
public static void M a i n ( )

{
Point MyPoint = new P o i n t ();

245

MyPoint.X = 100; M y P o m t . Y = 200 ; S y s t e m . C o n s o l e . W ri te Li ne (M yP oi nt . X) ; System.Consol.WriteLine ( M y Po mt .Y ) ; MyPoint = M y P o i n t ; S yst em .C on so le .W ri t e L i n e ( M y P o i n t . X ) ; S yst em .C on so le .W ri t e L i n e ( M y P o i n t . Y ) ;

} } De nuevo, se pas a la coordenada v con el valor 100 y la coordenada v con el valor de 200. La figura 10.5 contiene el resultado de este p rog ram a despus de que la so bre carg a del o per ador de decrcmento haya restado una unidad de v y de y.
ca

C:\WINDOWS\System32\cmd.exe

C :\ >Lir; t inq 10-5 .e x e

100 200
99 199 C:\>.

Figura 10.5. S o b r e c a r g a del o p e r a d o r d e d e c r e m e n t o prefijo

C'uando se s obrecargan operadores siempre hay que estar preparado para lo peor. Siempre hay alguna posibilidad de que los datos que se estn pas ando sean incorrectos y nos encontr aremos con que la funcin s ob re car ga da no puede g es tionar los datos. Los anteriores ejemplos no mos trab an ninguna de las exc ep ci o nes que pueden aparecer cuando se pasan valores errneos o inesperados. Es recomendable experi ment ar con las funciones e intentar f orzar errores.

Cmo sobrecargar los operadores true y false


Para sobrecargar los operadores true o false en una clase o estructura hay que definir un mtodo con las siguientes caractersticas: Un tipo dev uelto boo 1 La palabra clave operator

246

El operador que se sobrecarga

Una lista de par met ros que especifica un solo par met ro del tipo de la clase o e st ru ct ur a que contiene el mtodo del oper ado r s obre carga do El listado 10.6 es un buen ejemplo. Modifica la clase point par a que devuel va true si el punto est en el origen o false en caso contrario.
Listado 10.6. Sobrecarga de los operadores true y false class Point

{
public public public int X; int Y; static bool operator && true (Point RValue)

{
i f ( (RV alue.X == 0) return true; return false; (R V alue.Y == 0))

}
public static bool operator && false (Point RValue)

{
if ( (RValue.X = - 0) return false; return true; (RValue. Y = = 0))

}
public static void M a i n ( ) = new P o i n t ();

(
Point MyPoint MyPomt.X MyPomt.Y

= 100; = 2 00 ;

if (MyPoint) System.Con so le .W ri te Li ne ("The

point

is

at

the

origin.");

else
System.Console.WriteLine("The point is not at the origin.");

La sobre carga de los operadores true y f al se permite que los objetos de la clase Point puedan usarse como expresiones booleanas. como en la instruccin if . Debido a que el objeto MyPoint no est en el origen, el objeto se evala como false. tal y como aparece en la figura 10.6. Si se sobrecarga el operador true o el operador false en una clase o es tructura. ambos deben ser sobrecargados. Si se s obrecarga uno de los dos. pero no el otro, el compi lador de C# emite un mensaje de error como el siguiente:

247

error CS0216: El o p era dor 'P o m t .o p er ato r t r u e ( P o i n t ) ' requi ere que t a m b i n se d efi n a un ope r a d o r c o i n c i d e n t e 'false'

C :\>I<ist in gl 0-6 .exe The point is not * t the C :\>

Ld
Figura 10.6. Sobrecarga de los operadores tr ue y fa lse

Operadores binarios sobrecargables


Estos son los operadores binarios que se pueden sobrecargar: Suma Resta Multiplicacin Divisin Resto AND OR OR exclusivo Despl azami ent o a la izquierda Despl azami ent o a la derecha Igualdad Desigualdad M a yo r que Menor que

248

M ayo r o igual que Meno r o igual que Si quiere sob re carga r cualquiera de los operadores binarios de una clase o estructura, hay que definir un mtodo con las siguientes caractersticas: Un tipo devuelto deseado La palabra clave operator El operador que se s obrecarga Una lista de par met ros que especifica dos parmetros, al menos uno de los cuales debe ser del tipo de la clase o es tructur a que contiene el mtodo del operador s obre carga do La s obrecarga de operadores binarios brinda mucha flexibilidad. Pueden u s a r se diferentes par met ros par a los dos par met ros de la lista, lo que significa que se puede aplicar el operador a dos valores de diferentes tipos si se desea. Tambi n se puede us ar cualqui er tipo disponible como el valor devuelto por el oper ador sobrecargado. Si se quiere s umar un objeto y un valor de coma flotante para obtener un resultado booleano. se puede escribir un mtodo sobrecargado como el siguiente:
static public bool operator + (Point MyPoint, float FloatValue)

Se pueden definir v arias sobrecargas par a el mismo operador, pero solo si las listas de par met ros usan tipos diferentes:
static public static public static public bool bool bool operator operator operator + + + (Point MyPoint, (Point MyPoint, (Point MyPoint, fioat FloatValue) int IntValuej uint UlntValuei

El listado 10.7 aade los operadores de igualdad y de desigualdad a la clase

Point. El oper ado r devuelve resultados booleanos que devuelven true si los dos objetos Point tienen las mismas coordenadas: en caso contrario, devuelven faise.
Listado 10.7. Sobrecarga de los operadores de igualdad y desigualdad c 1 a s s Point

{
public int X; publi c int Y ; public static bool operator -= (Point Pointl, Point Pomt2)

{
f ( P o m t l . X != P o m t 2 . X ) return false; if( Pointl. Y != P o m t 2 . Y )

249

return false; return true;

}
public override bool Equals (object o)

{
return true;

}
public override 0; int GetHashCode( )

{
return

}
public static bool operator != (Point Pointl, Point Point2)

{
if(Pointl.X != Point2.X) return true; if (Point2.Y != Point2.Y) return true; return false;

}
public static void M a i n ( )

{
Point MyFirstPoint = new P o i n t (); Point MySecondPoint = new P o i n t (); Point MyThirdPoint = new P o i n t (); M y F i r s t P o i n t .X = 100; M y F i r s t P o i n t .Y = 200; M y S e c o n d P o i n t .X = 500; MySecondPoint .Y - 750 ; M y T h i r d P o i n t .X - 100; M y T h i r d P o i n t .Y - 200; if(MyFirstPoint == MySecondPoint) System. Console . W r i t e L m e ("MyFirstPoint and MySecondPoint are at the same c oo rd inates."); else System.Console . W r i t e L m e ("MyFirstPoint and MySecondPoint are not at the same coordinates.") ; if(MyFirstPoint == MyThirdPoint) System.Conso le .W ri te Li ne ("MyFirstPoint are at the same c oo rd inates."); else Syst em .C on so le .W r i t e L i n e ("MyFirstPoint are not at the same coordinates.");

and

MyThirdPoint

and

MyThirdPoint

250

El mtodo Main ( ) define tres puntos:

MyFirstPoint. con coordenadas (100. 200) MySecondPoint. con coordenadas (500. 750) MyThirdPoint, con coordenadas (100. 200)
A continuacin el mtodo usa el o per ado r de igualdad par a det erminar si los puntos MyFirstPoint v MySecondPoint hacen referencia a la mismas coordenadas. Entonces usa el o per ador de igualdad p ar a determinar si los puntos MyFirstPoint vMySecondPoint hacen referencia a las mi smas coo r de na das. En la figura 10.7 se mues tra el resultado que se obtiene si se compila y ejecuta el cdigo del listado 10.7.
c* C:\WINDOWS\System32\cmd.exe
C :\>List ingl0-7.exe MyFirstPoint and MySecondPoint are not at the sane coordinates. MyFirstPoint and MyThirdPoint are at the sane coordinates.

x|

C:\>_

Figura 10.7. S obrecarga de los operadores de igualdad y desigualdad

Los siguientes pares de operadores deben ser s o brecargados conjuntamente. Igualdad y desigualdad Menor y m ayo r que Menor o igual que y mayor o igual que Si se s obrecarga uno de esto pares pero no el otro, el compi lador de C# emite un mensaje cmo el siguiente:
error CS0216: El operador 'Point .ope rator = = ( P o m t , Point) ' requiere que tambin se defina un operador coincidente '!='

Operadores de conversin sobrecargabas


Tambi n se pueden escribir mtodos de sobrecarga de operadores que convier tan un tipo en otro. El mtodo de sobrecarga tambin puede definir si el compilador

251

de C # debe t rat ar la conv ersin como implcita o explcita. Si quiere definir un nuev o oper ado r de conversin en una clase o estructura, debe definir un mtodo con las siguientes caractersticas. La palabra clave implicit si la conversin va a considerarse una co n versin implcita o la p al ab ra clave explicit si la conversin va a co n siderarse una conv ersin explcita La palabra clave operator Un tipo que especifica el tipo al que se va a hacer la conversin Una lista de par met ros que especifica el tipo original de la conversin L1 listado IO S define una conversin implcita de un objeto de la clase Point a doubJe. El tipo doble especifica la distancia desde el origen hasta el punto, usando el teorema de Pitgoras.
Listado 10.8. Cmo definir una conversin implcita cla s s Point

{
public publie public int X; int Y ; static implicit operator double(Point RValue)

I
double double Distance; Sum;

Sum = (RValue.X * RValue.X) + (RValue.Y * R V a lu e. Y) ; Distance = Sy st em .M at h.Sq rt (S um ); re t u rn D is t .a n c e ; l p u b lie s t a t .ie v od Main () i doub le )is t .anee ; Poi nt 1 4 yPo int = ne w Poir.t ) ; MyPoint. .X = lU; M y P o m t .Y = 2 0 U ; Di st anee = MyPomt; 3ys t . em. C o 1is o le.Wri t e L m e Distance) ;

I i

NOTA: .NET Framework define el mtodo System. M a t h .Sqrt () que calcula la raz cuadrada del parmetro proporcionado. El mtodo es estti co, por lo que se le puede llamar aunque no se tenga un objeto del tipo System.Math para llamarlo.

252

El mtodo Main ( ) declara un objeto del tipo Point y asigna a sus coor de nadas los valores (100. 200). A continuacin asigna el objeto a una variable de tipo double. lo que est permitido porque la clase Point define un oper ador de conversin que convierte un objeto Point a doble. Como el oper ad or de c onve r sin esta definido c omo una conversin implcita, no es necesaria una conversin explcita. A continuacin el mtodo Ma i n ( ) escribe el valor de double convert i do en la consola. La figura 10.8 muestra el resultado del listado IOS.
CA C:\WINDOWS\System3Z\cmd.exe C:\>Listincfl0-8 .exe 223,606797749979 C:\>_

-iP l

Figura 10.8. Definicin de una conversin implcita

Operadores que no pueden sobrecargarse


C# no permite redefinir el compo rt ami en to de los operadores de la siguiente lista. Esto se hace principalmente en beneficio de la simplicidad. Los pro gr amadores de C# quieren que estos oper adores no dejen de ser sencillos y que s iem pre realicen la misma funcin: por tanto, no esta permitido sobrecargarlos. Asignacin A ND condicional OR condicional Condicional Las palabras clave new. typeof. sir.eof e is

Resumen
CU permite per sonal izar el comport ami ent o de varios de los operadores inte grados. Las clases y las est ructur as pueden incluir mtodos llamados mtodos de

253

sobreca rga de op era dor que definen el c omport ami ent o de un o per ado r c u a n do aparece en una expresin con la clase o estructura. Para so bre carga r los operadores unario ms. unario menos, de negacin o de complemento bit a bit en una clase o estructura, hay que definir un mtodo con un tipo devuelto deseado, el oper ador que se est sobrecargando y un solo par met ro del tipo de la clase o est ructura que contiene el mtodo de operador sobrecargado. Para s obr ecar ga r los operadores de incremento o decrcmento prefijo en una clase o estructura, hay que definir un mtodo con un tipo de devolucin que especifica el tipo de clase o es tructur a que contiene el mtodo del operador s ob re cargado. Tambi n es necesario definir el operador que se est s obrecargando y un solo p a rm et ro del tipo de clase o es tru ctur a que contiene el mtodo del operador sobrecargado. Para sobrecargar los operadores t r u e o f a l s e en una clase o estructura. ha\ que definir un mtodo con un tipo de devolucin booleano y un solo parmetro del tipo de la clase o est ructura que contiene el mtodo de operador sobrecargado. Para sobre carga r cualquiera de los operadores binarios en una clase o es t ruc tura. hay que definir un mtodo con un tipo de devolucin, el operador que se esta s obrecargando y dos parmetros. Al menos uno de los dos parmet ros debe ser del tipo de clase o es truc tu ra que contiene el mtodo del oper ador sobrecargado. Tambi n se pueden definir nuevas conversiones par a las clases o estructuras. Se especifica si la conversin se considerara un o per ador implcito o explcito. El mtodo del operador de conversin especifica el tipo de la variable que se convier te v el tipo al que debe ser convertida.

254

11 Herencia de clase

Los p ro gr amas mas simples de C# pueden u sar una o dos clases. Sin embargo, probablemente se necesiten varias clases en los p ro gr amas ms grandes. Muchas de estas clases pueden tener ca mpos o mtodos similares y seria logico compar tir el codigo comn entre el conjunto de clases. C# inclu\ e el concepto orientado a objetos de herencia, que permite que una clase adopte cdigo de otras clases. Las clases de C# pueden derivarse de las clases primarias y las instrucciones heredadas pueden ser usadas en otras clases. La herencia se usa en el desarrollo de s oftware orientado a objetos par a reutilizar los codigos mas comunes. Observ e, por ejemplo, los cuadros de lista de seleccin mltiple y de seleccin simple de Wi ndows. Estos cuadros de lista tie nen diferentes funcionalidades: uno permite que se seleccionen varios elementos y el otro lo impide, pero tambin tienen m uchas similitudes. Tienen el mismo aspecto, se comport an de la misma forma cuando el usuario se desplaza por la lista y usan el mismo color p ar a m ar c ar un elemento seleccionado. Si hubiera que escribir estos dos cuadros de lista como clases de C'#. se podrian escribir por separado, sin que uno conozca la existencia del otro. Sin embargo, eso sera un desperdicio. La may or parte del cdigo segurament e sea idntico. Sera ms lo gico escribir una clase que cont uvi era el cdigo comn y disponer de clases deri v a d a s de la e l a s e de c d i g o c o m n y qu e i m p l e m e n t a s e n las d i f e r e n t e s funcionalidades. Se puede escribir una clase llamada List Box par a que. por

257

ejemplo, contenga el cdigo comn y. a continuacin, escribir una clase de C# l lamada SingleSelectionListBox que herede de ListBox y pro po rci o ne el cdigo nico al c ua dro de lista de seleccin simple. Tambi n se puede escribir una clase de C # llamada MultipleSelectionListBox que t am bin herede de ListBox pero que proporcione el cdigo nico al cuadro de lista de seleccin simple. Otra de las ventajas consiste en que. si encuentra un error en el cuadro de lista, se le puede seguir fcilmente la pista hasta el error en el cdigo comn. Si se puede reparar el error en el cdigo comn, al volver a compilar el programa se repararn esos errores en las clases de cuadros de lista de seleccin mltiple y seleccin simple. Basta reparar un error p ar a solucionar el problema en las dos clases. En terminologa orientada a objetos, se habla de herencia en trmi nos de clase base y clase derivada. La clase de la que se hereda recibe el nombre de clase base y la clase que hereda de la clase base recibe el nombre de clase derivada. En el ejemplo de los cuadros de lista, la clase ListBox es la clase base v las clases SingleSelect ionListBox y MultipleSelectionListBox son las clases derivadas.

Cmo compilar con clases mltiples


T r a ba ja r con herencias en C# significa que se va a t raba jar con ms de una clase de C#. C# no es muy estricto respecto a cmo se relacionar! estas clases con los archivos fuente. Se pueden poner todas las clases en un solo archivo fuente o se puede poner c ada clase en un archivo fuente diferente. Obviamente, excepto en los pr ogr a ma s ms pequeos, implementar todas las clases en un solo archivo no es un buen modo de o rganizar el cdigo. Ha y que tener en cuenta que todas las clases se r ecompilan cada vez que se hace un cambio en al guna parte del programa. Para compilar un p ro g ra ma que usa archivos fuen te separados desde una lnea de comandos, tan slo hay que escribir cada archivo despus del nombre del compilador, como se ve en el ejemplo:
ese filel.es file2.es flle3.es

Por defecto, el compilador de C# da al ejecutable resultante el nombre del pri mer archivo fuente. La anterior lnea de comandos produce un ejecutable llamado filel .exe. Se puede usar el argumento /out para cambi ar el nombre del archivo:
esc / o u t :m y a p p .exe filel.es flle2.es flle3.es

E s t a l nea de c o m a n d o s del c o m p i l a d o r g e n e r a un e j e c u t a b l e l l am ad o myapp. exe.

NOTA: Uha, y slo una, de sus clases debe especificar un mtodo estticMinO.

258

Cmo especificar una clase base en C#


Vol vamos al ejemplo de la clase Point par a ver cmo funciona la herencia en C //. Supongamos C[ue Hemos designado una clase llamada Point2D. que describe un punt o en un espacio bidimensional con las coor denadas X e Y:
class P o in 12 D

{
public int X; public int Y; // mas codigo

} A h o r a s u p o n g a m o s qu e q u e r e m o s t r a b a j a r con p u n t o s en un e s p a c i o tridimensional, pero mant eni endo la clase Point2D. La herencia nos permite crear una nueva clase que mantiene todo el cdigo de la clase Point2D y le aade una coordenada Z. Para n om br ar la clase base de C# se escribe el nombre de la clase derivada seguido por dos puntos y del nombre de la clase base. A continuacin, se incluye un ejemplo de cmo se derivara la clase Point3Da partir de la clase Point2D:
class Point3D : Point2D

{
public int Z ; // codigo para la clase Point3D

} Dependiendo de las reglas de mbi to de la clase base, todos los campos y propiedades de la clase base (Point2D) pueden ser empl eadas en la clase der i vada (Point3D). Por ejemplo, cuando una clase se deriva de una clase base, el cdigo de la clase derivada puede acceder a los ca mpos y propi edades de la clase base, si el mbi to lo permite. Slo se puede escribir una clase cuando una clase se hereda de otra. Algunos lenguajes orientados a objetos, como C++. permiten especificar ms de una clase base p ar a una clase derivada. Este concepto recibe el nombre de herencia m lti ple. CU admite la herencia simple, pero no la mltiple. En el a pa r ta do dedicado a la contencin se explica una t xmca p a r a simular herencias mltiples en CU. El listado 11.1 ensea a usar las clases Point3D y Point 2D juntas.
Listado 11.1. Cmo derivar Point3D a partir de Point2D class Point2D

{
public public int X; int Y;

}
class P o in 1 3 D : P o i n 12 D

259

public

int

Z;

;
class MyMainClass static void M a i n ( ) My2DPomt My3DPoint = new P o m t 2 D ( ) ; = new P o m t 3 D ( ) ;

{
public

{
Pomt2D PomtBD

My2DPoint.X My2DPomt.Y

= 100; = 200 ;

M y 3 D P o 1 n t .X - 150; M y 3 D P oln t .Y = 2 5 0 ; My3DPoint.Z = 350;

El mtodo Main ( ) crea un objeto Point2D y otro Point3D. El objeto Poi nt3D tiene c ampos par a las coordenadas X. Y y Z. aunque la declaracin de PointBD slo declare un ca mpo llamado Z Los campos X e Y se heredan de la clase base Point2D y pueden ser usados exact ament e igual que si se hubieran declarado di rectamente en la clase Point3D.

m bito
Al disear la estructura de la herencia de clase, puede decidir qu miembros de la clase base no deben ser visibles para las clases derivadas o para los dems progr amadores . Por ejemplo, se puede escribir un mtodo en una clase base que ayude a calcul ar un valor. Si ese clculo no es de utilidad en una clase derivada, se puede ev itar que la clase deriv ada llame al mtodo. En terminologa de la programacin, la v isibilidad de una variable o mtodo se conoce como su mbito. Algunas variables o mtodos pueden ser declaradas corno de mbi to publico, otras pueden ser declaradas como de mbito privado y otras pueden estar entre estos dos casos. C# define cinco pal ab ras clave que permiten definir el mbi to de cualquier mi embro (variable o mtodo) de una clase. El mbi to de un miembro afecta a su visibilidad par a las clases derivadas y el cdigo que crea las instancias de la clase. Estas pal abr as clave, resaltadas en la siguiente lista, se colocan antes de cualquier otra p al abr a clav e en una declaracin de miembro. Los mi embros marc ado s como public son visibles par a las clases deri vadas y par a el cdigo que crea los objetos de la clase. Hast a ahora hemos usado public.

260

Los mi embros mar cad os como prvate slo son visibles p ar a la clase en la que se definen. Los mi embros privados no son accesibles desde las clases derivadas ni desde el cdigo que crea los objetos de la clase. Los mi embros m ar cad os como protected slo son visibles p ar a la c la se en la que se definen o desde las clases derivadas de esa clase. No se puede acceder a los mi embros protegidos desde el cdigo que crea los objetos de su clase. Los mi embros marcados como interna 1 son visibles par a cualquier cdigo en el mi smo archivo binario, pero no son visibles p ar a otros a r c h i vos binarios. Recuerde que N E T Framework acepta el concepto de e ns am blados. que son bibliotecas de cdigo va compiladas que pueden ser usadas por aplicaciones externas. Si se escribe una clase en C# y se compila la clase par a obtener un ensambl ado, cualqui er fragment o de cdigo del e n s ambl ad o podr acceder a los mi embros de clase interna. Sin embargo, si otro fragment o de cdigo usa ese ensambl ado, no tendr acceso al mi em bro. aunque derive una clase de la clase del ensamblado. Los miembros marcados como protected internal son visibles par a todo el cdigo incluido en el mismo archiv o binario y par a las clases externas que se deriven de su clase. Si se escribe una clase en C# y se compila la clase para obtener un ensamblado, cualquier fragmento de codigo del ens amb la do puede acceder a los mi embros de clase interna. Si otro fragment o de codigo externo usa el ens amb la do y deriva una clase de la clase del ensamblado, el mi embro interno protegido sera accesible p ar a la clase derivada. Sin embargo, el cdigo que t rabaja con los objetos de la clase base no tendr acceso al miembro.

C# permite especificar un mi embro de clase sin especificar ninguna pal abr a clave de mbito. Si se declara un mi embro de clase sin especificar ninguna p al ab ra clave de mbito, al mi embro se le asigna por defecto accesibilidad privada. Los miembros que se han declarado sin usar ninguna pal ab ra clave de mbito pueden usarse en otras partes de la clase, pero no pueden ser usados por clases derivadas ni por codigo que use objetos de la clase.

Cmo reutilizar identificadores de miembros en las clases derivadas


C# permite reutilizar identificadores de clase base en las clases derivadas, pero el compi lador de C# emite un aviso cuando lo detecta. Preste atencin al cdigo del listado 1 1.2.

261

Listado 11.2. C m o reutilizar identificad ores de clase base eiass P o in 12 D

{
public m t pubi i c m t X; Y;

}
class Pomt3D : Point2D X; Y; Z;

{
public m t public m t pubi c m t

}
class MyMamClass static void M a i n ( ) My2DPomt My3DPomt = new P o m t 2 D = new P o m t 3 D

{
public

{
Pomt2D Pomt3D

My2DPoint.X My2DPomt.Y

= 100; = 200 ;

My3DPoint .X = 150 M y 3 D P o m t .Y - 250 M y 3 D P o m t .Z = 350

La clase derivada Point3D define los c ampos X e Y que coinciden con los identificadores usados en la clase base Point2D. El compi lador de C # emite las siguientes advertencias cuando se compi la este cdigo:
warning CS0108: La 'Pomt3D.X' porque warning CS0108: La 'Pomt3D.Y' porque palabra clave new oculta el miembro palabra clave new oculta el miembro es necesaria en heredado 'Point2D.X' es necesaria en heredado 'Pomt2D.Y'

El compilador de C# emite avisos porque los identificadores de la clase deriva da ocultan las definiciones que usan el mi smo identificador en la clase base. Si se quieren reutilizar los nombres, pero no que el compi lador emita avisos, se puede usar el operador new al reutilizar los identificadores en la clase derivada. El cdigo del listado 1 1.3 compila sin emitir avisos.
Listado 11.3. C m o usar new para reutilizar identificadores de clase class P o m t 2 D

{
public public mt mt X; Y;

262

class

Point 3 D

: Point 2 D int X; int Y; Z;

{
new public new public public int

}
class MyMainClass static void M a i n ( ) My2DPomt My3DPomt = new P o m t 2 D ( ) ; = new P o m t 3 D ( ) ;

{
public

{
Pomt2D Pomt3D

My2 D P o m t .X = 100; M y 2 D P o i n t .Y = 200; My3DPoint.X = 150; My3DPoint.Y = 250; M y 3 D P o i n t .Z = 350;

} }

Cmo trabajar con mtodos heredados


C# permite que los mtodos de la clase base y de las clases derivadas se relacionen de varios modos. C# permite los siguientes mtodos: Mtodos virtuales y de reemplazo Mtodos abstractos

Mtodos virtuales y de reemplazo


Qui zs quiera que una elase derivada cambie la i mplementacin de un mtodo en una clase base, pero mant eni endo el nombre del mtodo. Suponga, por ej em . plo. que la clase Point2D implementa un mtodo llamado PrintToConsole () que escribe las coordenadas X e Y del punto en la consola. Qui zs tambin quiera que la clase derivada Point3D p r o p or c io n e su p r op i a i m pl eme nt aci n de PrintToConsole (). Sin embargo, no puede us ar el mtodo PrintToCon sole () de la clase Point2D. porque esa implementacin slo funciona con las coordenadas X e Y y la clase Point3D tambin tiene una coor denada Z. La clase Point3D debe facilitar su pro pi a implement aci n del mi smo mtodo PrintToConsole (). Los nombres de mtodos pueden reutilizarse en clases derivadas si el mtodo de clase base permite que el mtodo pueda volver a ser

263

implcmcntado. La operacin de reimpl ement ar un mtodo de clase base en una clase der ivada recibe el nombre de reem pla za r el mtodo de clase base. Al re em pl azar un mtodo de clase base en C# hay que tener en cuenta los dos requisitos: El mtodo de clase base debe declararse con la pal ab ra clave v i r t u a l . El mtodo de la clase d er iva da debe dec la rar se con la p a l ab r a clave override. Los mtodos de clase base que usan la pal abr a clave v i r t u a l reciben el nombre de m todos virtuales y los de clase base que usan la p al abr a clave o v e r r i d e reciben el n ombre de mtodos de r e e m p la z o . El listado 1 1.4 d emues tra cmo puede i mplement arse el mtodo P r i n t T o C o n s o l e ( ) para las clase P oint2D y Point3D.
Listado 11.4. Cmo reemplazar mtodos virtuales class Pomt2D

{
publie int X ; p u b 1 1 e int Y ; public virtual void PrmtToConsole ( ) {1} ) " , X , Y) ;

{
System.Console.WriteLine (" ({0} ,

} }
e 1a s s P o in t 3 D : P o in t 2 D Z; void Pr in tT o C o n s o l e ( ) {2})", X, Y, Z);

{
public public int

override

{
S ystem. Con sol. W r i t e L m e (" ((0} , {1}/

} }
class MyMamClass static void M a i n ( ) - new P o m t 2 D ( ) ; new P o m t 3 D ( ) ;

{
public

{
Pomt2D My2DPomt PointBD M y B D P o m t

M y 2 D P o m t . X - 100; M y 2 D P o m t .Y = 2 00 ; M y J D P o m t . X = 150; My 3 D P o m t .Y = 2 50 ; M y i D P o m t . Z = 350 ;

264

My2DPoint.PrintToConsole(); M y 3 D P o m t .PrintToConsole ( );

} }

NOTA: La sintaxis de las llamadas W r it e L in e () hechas en el listado


11.4 es diferente de la sintaxis usada con ant&iioridad. LoSnmeros entre llaves de la cadena son comodines. Los valoris de losotros parmetros escoben en la consola en lugar del comodn. El comodn {0 J es reemplazado por el valor del primer parmetro, el comodn {1} es reemplazado por el valor del segundo parmetro y as sucesivamente.
El listado 1 1.4 escribe esto en la consola:
(10 0

200)

(150,

250,

350)

No se puede reempl azar un mtodo de clase base a menos que use la pal ab ra clave virtual. Si intenta hacerlo sin usar la pal abr a clave, el compilador de C# emite el siguiente error:
error CSQ506: 'Point3D.PrintToConsole() ' : no se puede reemplazar el miembro heredado 'Point2D.PrintToConsole( )' porque no esta marcado como virtual, abstract u override

Sin embargo, est permitido r eempl azar un mtodo override. Si. por al gu na extraa razn, se quiere implementar una clase Point4D y derivarla de Point3D. es posible re empl aza r el mtodo de PointSD PrintToConsole ().

Polimorfismo
El concepto de reemplazo de mtodos lleva al concepto d c polimorfismo. Cuando r eempl azamos un mtodo, queremos llamar al mtodo ap rop ia do desde cualquier mtodo que llame a este mtodo reemplazado. El listado 11.5 presenta este concepto en accin. Se ha aadido a Point2D un m t o d o U s e P r i n t T o C o n s o 1 e ( ) q u e l l a m a al m t o d o v i r t u a l PrintToConsole (). Point3D hereda este mtodo de Point2D. Cuando se llama a PrintToConsole ( ) en esta funcin, se quiere llamar a la versin q u e p e r t e n e c e a la c l a s e a p r o p i a d a . En o t r a s p a l a b r a s , en el m t o d o UsePrintToConsole ( ) que pertenece a la clase Point2D, se pretende lla m ar al mtodo PrintToConsole () que pertenece a la clase Poi nt2 D . En el mt odo UsePr intToConsole ( ) que pertenece a la clase Point3D. se pre tende llamar al mtodo r eempl azado PrintToConsole ( ) que pertenece a la clase Point3D. C omo el mtodo PrintToConsole ( ) fue declarado como

265

un mtodo virtual, la deteccin de la versin que debe ejecutarse tiene lugar aut omt icamente. El listado 1 1.5 escribe lo siguiente en la consola:
(1 0 0 ,

200)

(150,

25 0,

350) Listado 11.5. Polimorfismo

class

Point2D int X; int Y; virtual void PrintToConsole () {1})", X, Y) ;

{
public public public

{
S ystem. Console.W r i t e L i n e (" ({0 ) ,

}
public void U s ePrintToConsole ()

{
P r i n t T o C o n s o l e ();

} }
class Point 3D : Poin12D Z; void PrintToConsole ( ) {2})", X, Y, Z)

{
pu b i lc int public

override

{
System.C o n s o l e . WriteLine("({0 ( , {1},

} }
dass MyMainClass static void M a i n ( ) = new P o m t 2 D ( ) ; = new P o m t 3 D ( ) ;

{
public

{
Point2D M y 2 D P o m t Point3D M y 3 D P o m t My2DPomt.X My2DPomt.Y My3DPomt.X My3DPomt.Y My3DPomt.Z

= 100; = 200 ; = 150 = 250 = 350

M y 2 D P o m t .UsePnntToConsole ( ) My3DPoint . U s e P n n t T o C o n s o l e ()

266

Mtodos abstractos
Algunas clases base pueden no ser capaces de propor ci onar la implementacin de un mtodo, pero puede que queremos que las clases derivadas proporcionen una implementacin. Supon gamos , por ejemplo, que est amos escribiendo en C# una aplicacin de geomet ra y escribimos clases llamadas Square y Circle. Decidiremos las funciones comunes que u sar ca da for ma de la aplicacin y por lo tanto implementamos una clase base llamada Shape y derivamos las clases Square y Circle de Shape:
Class Shape

{ }
class Circle : Shape

{ }
class Square : Shape

( } Ahora supo ng amos que decidimos que todas las formas deben ser capaces de calcular su arca, de modo que escribimos un mtodo llamado GetArea (). El probl ema de escribir ese cdigo en la clase base es que la clase base no tiene suficiente informacin par a calcular un rea. Cad a forma calcula su rea usando una frmula diferente. Lo que podemos hacer es definir un mtodo abs tra ct o en la clase base Shape. Los mtodos abs tra ct os no propor ci onan una implementacin propia sino que p ropor ci onan una firma de mtodo que las clases derivadas deben implementar. Los mtodos a bs tra ct os dicen "Yo no se implement ar este mtodo, pero mi clase derivada lo hara. de modo que asegrese de que la implementen con los parmetros y el codigo devuelto que yo especifico." Los siguientes fragment os demuest ran cmo declarar un mtodo abs tra ct o en la clase Shape.
abstract class Shape double G e t A r e a ();

{
public abstract

NOTA: Las clases abstractas usan la palabra clave a b s t r a c t . No tienen cuerpo de mtodo; en su lugar hay un punto y coma despus de la lista de parmetros.
Las clases abs tra ct as tambin son. por definicin, mtodos virtuales y debe usarse la palabra clave overriele par a reemplazarlos por clases derivadas:

267

class Square : Shape

{
public override double GetArea( ) rea

{
// implemente el calculo del

} } Las clases que contienen al menos un mtodo abs tra ct o reciben el nombre de clases abs tra ct as y deben incluir la p al ab ra clave abstract antes de la pal abra clave de la clase. Si no se incluye la p a la br a clave abstract al definir la clase se o bt endr un error del compi lador de C#:
error CS0513: 'S h a p e .GetArea ()' en la clase nonabstract 'Shape' es abstract pero est incluida

El compilador de CU no permite crear objetos a partir de clases abstractas. Si se intenta el compi lador de CU emite un error:
error CS0144: No se puede crear una interfaz abstracta 'Shape' instancia de la clase o

Las clases abst ract as suelen usarse p ar a crear una elase base comn a un conjunto de clases. Esto permite usar el pol imorfismo al a lmac enar clases d er iva das en algn tipo de coleccin, como se vio en un captulo anterior.

Clases base: Cmo trabajar con propiedades e indizadores heredados


En CU. se pueden m ar car como virtual, override o abstract. p ro piedades e indizadores de clases base y derivadas, igual que si fueran mtodos.

Las propiedades virtual y override y los i ndizadores funcionan como las p ropi edades virtual y override. Las propiedades y los indizadores p u e den m ar car se como virtuales en una clase base y como reemplazados en una clase derivada. Las clases base pueden definir propiedades e indizadores, que no tienen implementacin propia. Las clases base que contienen al menos una propiedad ab st ra ct a o un indizador deben ser m arc adas como si fueran una clase abstracta. Las propiedades abst ract as y los indizadores deben ser reemplazados en una clase base.

268

Cmo usar la palabra clave base


C# proporciona la p al ab ra clave base par a que las clases derivadas puedan acceder a las funciones de su clase base. Se puede usar la p al ab ra clave base par a llamar a un const ructor de clase base cuando se crea un objeto de una clase derivada. Para llamar a un const ructor de clase base hay que colocar despus del constructor de la clase derivada dos puntos, la p al abr a clave base y a cont inua cin los par met ros que se van a p a s ar a la clase base. El listado 1 1.6 demuestra el funcionamiento de todo esto. Aade const ructores p ar a las clases Point2D y Point3D y el const ructor Point3D llama al const ructor de su clase base.
Listado 11.6. Cmo llamar a constructores de clase base class Point2D int X; int Y; Point2D(mt X, int Y)

{
public public public

{
t h i s .X = X ; this.Y = Y;

}
public virtual void PrintToConsole () {1})", X, Y);

{
System. Consol. W r i t e L m e ( " ( { 0 } ,

} }
class Point3D int : Point2D Z; X, int Y, int Z) : base(X, Y)

{
public public

Point3D(int

{
t h i s .Z = Z ;

}
public override void PrintToConsole () {1}/ {2})", X, Y, Z);

{
Sy st em .Consol.WriteLine("((0},

} }
class MyMamClass static void M a i n ( ) = new P o m t 2 D ( 1 0 0 , 200) ; - new Point3D(150/ 250, 350);

{
public

{
Point2D My2DPoint Point3D My3DPoint

269

M y 2 D P o m t .Pn nt To Co ns ol e ( ); M y 3 D P o m t .P r m t T o C o n s o l e ( );

) } El constructor de la clase P o i n t 2 D establece los campos X e Y de la clase mediante los dos enteros que se pasan al constructor. El const ructor de la clase P o i n t 3 D admite tres parmetros. Los primeros dos parmetros se pasan al cons tructor de la clase base usando la pal abr a clave base y el tercero se usa para establecer el valor del campo Z de la clase derivada.

Cmo acceder a campos de clase base con la palabra clave base


Tambi n se puede usar la pal abr a clave base par a acceder a miembros de la clase base. Para t rabaj ar con un miembro de clase base en la clase derivada. ha\ que anteponer al nombre del miembro la p al abr a clave base v un punto. Se puede acceder a los campos de la clase base mediante la siguiente sintaxis:
base.Z = 10 0;

Tambi n se puede invocar a mtodos de clase base con esta otra sintaxis:
base .Prmt.ToConsol () ;

Clases selladas
Si no quiere que se derive codigo de una determinada clase, puede m ar c a r la clase con la pal abr a clave sealed. No se puede derivar una clase de una clase sellada. Se puede especificar una clase sellada escribiendo la palabra clav e sealed antes de la pal ab ra clav e class. como en este ejemplo:
sealed class MySealedClass

Si se intenta derivar una clase de una clase derivada, el compi lador de C# emite un error:
error CS059: 'Pomt. 3D' sealed ' P o m t 2 D' : no se puede heredar de la clase

Contencin y delegacin
Si la herencia es una relacin ES-UN. la contencin es una relacin T I EN E UN. Un gat o de Bi rmani a ES UN gat o (por lo que puede her edar la clase

270

DcBi rmani a de la clase genrica Gato); pero un Coche T I E N E 4 ruedas (por lo que la clase Coche puede tener cuatro objetos Rueda). El aspecto ms interesante de la contencin es que se puede empl ear como sustituto de la herencia. El pri nci pal inconveniente de u sar la contencin en lugar de la herencia es que se pierden las ventajas del polimorfismo. Sin embargo, se obtienen los beneficios de la reutilizacin del cdigo. En C#. hay dos casos comunes en los que prcticamente slo se puede emplear la contencin y no la herencia: cuando se t r abaj a con herencias mltiples y c u a n do se t rabaj a con clases selladas. A continuacin se incluye un ejemplo que m u es tra cmo funciona esta tcnica. Adems, ver t raba jar al polimorfismo. S u po ng amo s que t enemos una clase AlarmClock y una clase Radio como las que a p a r e c e n en el s i g u i e n t e f r a g m e n t o y q u e r e m o s c r e a r u n a c las e ClockRadio que combine estas dos clases. Si C# admitiese herencias ml ti ples. se podra hacer que ClockRadio heredase de las clases AlarmClock y Radio. A continuacin se podra aadir una variable booleana radioAlarm que determine si se activa la al ar ma o la radio v que reemplace SoundAlarm ( ) par a usar esta variable. Por desgracia. C# no admite herencias mltiples. Por suerte, se puede empl ear la contencin en lugar de la herencia y obtener todas las ventajas de la reutilizacin de cdigo. Observe cmo funciona, paso a paso:
class Radio bool on off;

{
protected public

void O n ( ) s now on !" ) ;

{
i f ( !on off) C ons ol e . W n t e L m e ("Radio on_off = true;

}
public void O f f ( )

{
if (on_of f ) Consol.WriteLine ("Radio on off = false; s now off!") ;

} }
class AlarmClock int int void currentTime; alarmTime; SoundAlarm()

{
prvate prvate prvate

{
C o n s o l e . W r i t e L m e ("Buzz !") ;

}
public void R u n ( )

271

for

(int currTime

= 0;

currTime < 43200;

currTime++)

{
Se tC ur re n t T i m e ( c u r r T i m e ) ; f (GetCurrentTime ( ) == GetAlarmTime ( ))

{
Con sol. W r i t e L m e ("Current SoundAlarm( ); break; Time = {0 } !" , cur rentTime ) ;

} } }
public int G et C u r r e n t T i m e ( ) curren tT im e;

{
return

}
public void Se t C u r r e n t T i m e (int = aTime; aTime)

{
currentTime

}
public int GetAlarmTime( ) alar m T i m e ;

{
return

)
public void SetAlarmTiroe ( m t = aTime; aTime)

{
alarmTime

} ) C om o queremos re empl aza r el mtodo SoundAlarm( ) de AlarmClock. es recomendable hacer que ClockRadio herede de AlarmClock. Esto re quiere un pequeo c ambi o en la i mplementacin de AlarmClock. Sin embargo, a cambi o se consiguen todos los beneficios del polimorfismo. Una vez que se ha seleccionado una clase base, no podemos heredar de Radio. En lugar de heredar, c r e a r e m o s u n a v a r i a b l e de m i e m b r o p r i v a d a R a d i o d e n t r o de la c las e ClockRadio. Crea mos el mi embro privado en el cons tructor ClockRadio y delegamos el trabajo de los mtodos RadioOn ( ) y RadioOf f ( ) en este miembro privado. Ca da vez que la i mplementacin de la clase Radio cambi a (por e)emplo. para reparar algn error), la clase AlarmClock incorporar automticamente estos cambios. Un inconveniente del enfoque cont encin/delegacin es que para aadir una nueva f uncionalidad de la clase contenida (por ejemplo, aadir nuevos mtodos p ar a aj us tar el volumen) es necesario hacer cambi os en la clase conteni da par a delegar esta nueva funcionalidad en el mi embro priv ado.
class ClockRadio : AlarmClock

272

prvate Radio radio; // Declarar otras variables public ClockRadio( )

de m i e m b r o . ..

{
radio = new R a d i o (); // Establecer el valor de otras variables de miembro. . .

}
//---------public void Delegar en Radro RadioOn( ) -----------

{
r a d r o .On () ;

}
public void RadioOff( )

{
r a d i o .O f f () ;

} } Ya hemos implementado compl et ament e la funcionalidad de la radio mediante el patrn contencin/delegacin. Es hora de aadir la funcionalidad A l a r m C l o c k . En primer lugar, se aade una variable pri vada r a d i o A . 1 arrri que determina si debe sonar la radio o si debe sonar el timbre cuando se dispare la alarma:
class ClockRadio : AlarmClock

{
prvate bool radioAlarm; // Declarar otras variables m i e m b r o . .. publrc C l o c k R a d i o ( )

{
radioAlarm = false; // Establecer el valor de otras variables miembro. . .

}
//---------public void Nueva funcionalidad C lo ckRadio---------SetRadioAlarm (bool useRadio)

I
radioAlarm = useRadio;

} } Como queremos reempl azar la funcin S o u n d A l a r m ( ) de A l a r m C l o c k . . necesitamos c amb ia r la declaracin del mtodo S o u n d A l a r m ( ) para que sea protegida. Adems, como queremos que la funcin P u n ( ) tenga un c o mp or t a miento polimrfico. tendremos que hacer este mtodo v irtual:
class AlarmClock int int currentTime; alarmTime;

prvate private

273

protected

virtual

void

SoundAlarm()

{
C o n s o l . W n t e L i n e ("Buzz !") ;

}
// Otros m t o d o s . ..

} R e em p la z ar SoundAlarm ( ) en AlarmClock es sencillo. De pendi endo de los valores de radioAlarm. se enciende la radio o se l lama al mt odo SoundAlarm ( ) de la clase base que hace sonar el timbre, como sigue:
ClockRadio : AlarmClock Radio radio; bool radioAlarm;

{
prvate prvate

//---------AlarmClock Reemplazado ----------protected override void SoundAlarm))

{
f (radioAlarm) R a d i o O n ();

{ }
e 1se

{
b a s e .S o u n d A l a r m ();

} }
/ / Ot ros met o d o s . . .

} Y en esto consiste bsicamente! Algo muy interesante est ocurriendo dentro del mt odo Run ( ) de la clase AlarmClock (que aparece en el siguiente fr a g mento de cdigo): el compo rt ami en to polimrfico al que aludamos. La clase ClockRadio hereda este mtodo de su clase base y no lo reemplaza. Por tanto, este mt odo Run ( ) puede ser ejecutado desde un objeto de AlarmClock o un objeto de RadioClock. Como dec la ramos SoundAlarm ( ) de modo que f u e se v i r t u a l . C # es lo s u f i c i e n t e m e n t e i n t e l i g e n t e c o m o p a r a l l a m a r al SoundAlarm ( ) ap ro p ia d o dependiendo de qu clase est i nvocando al mtodo

Run () .
class AlarmClock int int void currentTime; alarmTime; Run () = 0; currTime < 43200; currTime++)

{
prvate prvate public

(
for (int currTime

274

Se tC ur re n t T i m e ( c u r r T i m e ) ; f (GetCurrentTime () == G e t A l a r m T i m e ( ))

{
Consol . W r i t e L m e ("Current Time = S oundAla r m ( ); break; {0 } \ " , curren t .Ti me ) ;

//

Otros

m t o d o s ...

} Este ejemplo resalta uno de los puntos fuertes de la herencia: el polimorfismo. Ademas, cuando se aaden nuevos mtodos pblicos (o protegidos) a la clase base, estn automt icamente disponibles en la clase derivada. El listado 1 1.7 es el listado compl et o con un mtodo m a i n ( ) de ejemplo par a que pueda e xpe r im en tar con l.
Listado 11.7. La herencia mltiple puede ser simulada usando la contencin
u s i ng System; Containment Radio bool on_off;

namespace

{
class

{
protected public

void

On( )

{
f (!on off) Consol . W r i t e L m e ("Radio on off - true; s now
011 !" ; ;

}
p ub l ic v oid Off( ) s n ow of f !" 1 ;

{
f (on off) C o n s o l e . W n t e L i n e ("Radio on off = false;

} }
class AlarmClock

{
prvate prvate int int currentTime; alarmTrme;
voi d SoundAlarmu

protected

virtual

{
C o n s o l . W r i t e L m e ("Buzz !" ) ;

275

public

void

Run( ) = 0; currTime < 43200; c urrTime++)

{
for (int currTime

{
if S et Cu r r e n t T i m e ( c u r r T i m e ) ; (GetCurrentTime () == GetAlarmTime () ) C o n s o l e .WriteLine ("Current cur r e n t T i m e ) ; S o u n d A l a r m (); break; Time =

{ {0 } ! " ,

public

int

GetCurrentTime ( ) curre nt Ti me ;

{
return

}
public void Se t C u r r e n t T i m e (int = aTime; aTime)

{
currentTime

}
public int G e t A l a r m T i m e ()

{
return alarmTime;

}
public void SetAlarmTime ( m t = aTime; aTime)

{
alarmTime

class

ClockRadio

: AlarmClock

{
private private public Radio radio; bool radioAlarm; ClockRadio( )

{
radio = new R a d i o (); radioAlarm = false;

}
//---------public void Delegar en Radio RadioOn( )

{
r a d i o .O n () ;

276

public

void

RadioOff()

{
radio.Off ( );

}
AlarmClock Reemplazado ---------//---------protected override void S o u n d A l a r m ( )

{
if (radioAlarm) RadioOn () ;

{ }
else

(
b a s e .S o u n d A l a r m ();

} }
//---------public void Nueva funcionalidad de ClockRadio SetRadioAlarm(bool useRadio)

{
radioAlarm = useRadio;

class

Contlnh int M a i n ( s t r i n g [] args)

{
static

{
ClockRadio clockRadio clockRadio; = new C l o c k R a d i o ( );

c l o c k R a d i o . S e t R a d i o A l a r m (true ) ; clockRadio.SetAlarmTime (10 0) ; c l o c k R a d i o .R u n ( ); // esperar a que el usuario reconozca los resultados Consol . W r i t e L m e ("Hit Enter to termnate..."); C o n s o l .Read ( ); return 0;

} } }

La clase de objeto .NET


Todas las clases de C# derivan en ltima instancia de una clase construida en N E T F ramework l lamada o b j e c t . Si se escribe una clase en C# y no se define

277

una clase base par a ella, el compi lador de C # la deriva de o b j e c t sin ningn aviso. S upongamos que escribimos una declaracin de clase de C# sin una d ecla racin de clase, como en este ejemplo:
class P o in 12 D

Esto es equivalente a derivar la clase de la clase base . NET S y s t e m . Ob j e c t :


class Point2D : System.Object

La pal abra clave obj ect puede usarse como si fuera un alias del identificador S y s t e m . Obj e c t :
class Point2D : object

Si se deriva desde una clase base, hay que tener en cuenta que la clase base se deriva desde obj ect o desde otra clase base que herede de obj ect. Al final, la j er ar qu a de las clases base siempre i ncl i ne la clase N E T object. Graci as a las reglas de herencia de C#. la funcionalidad de la clase NE T object esta disponible para todas las clases de C#. La clase N ET object contiene los siguientes mtodos:

public virtual bool Equal s (ob j ect obj) :Compara dos objetos y devuelve true si son iguales y false en caso contrario. Este mtodo esta m ar cad o c omo virtual, lo que significa que se puede re empl a zar en las clases de C#. Quizs quiera reemplazar este mtodo para c o m p a rar el estado de dos objetos de la clase. Si los objetos tienen los mismos valores para los campos, puede dev olv er true: si los valores son diferen tes puede devolver false. public virtual int GetHashCode ( ) : Calcula un cdigo hash para el objeto. Este mtodo esta marcado como virtual, lo que significa que se puede reemplazar en las clases de C'#. Las colecciones de clase de NET pueden llamar a este mtodo para generar un codigo hash que ayude en las consultas y clasificaciones y las clases pueden reempl azar a este mtodo par a que genere un codigo hash que tenga sentido para la clase.

N O T A : El cdigo hash es una clave nica para el objeto especificado.

Type GetType ( ) : Devuelve un objeto de una clase NET llamado Type que proporci ona informacin sobre la clase actual. Este mtodo no esta m ar cado como virtual, lo que significa que no se puede reempl azar en las clases de C#. public public virtual s t n n g ToString ( ) : Devuelve una re pres en tacin de cadena del objeto. Este mtodo est marcado como virtual, lo que

278

si gni fi ca que se p ued e r e e m p l a z a r en las cl as es de C#. Un mt od o T o S t r m g ( ) es i n v o c a d o c u a n d o a l g n m t o d o N E T c o m o S y s t e m .Consol .WriteLine ( ) necesita convertir una variable en una cadena. Se puede reemplazar este mtodo p ar a que devuelva una c a de na ms apr opi ad a par a representar el estado de una clase determinada. Qui zs quiera, por ejemplo, aadir el signo adecuado a cada divisa junto a la representacin de cadena de la clase Money.

protected

virtual

void

Finalize(): Puede ser llamado (o

puede no serlo) cuando el recolector de objetos no utilizados del entorno de ejecucin comn destruye el objeto. Este mtodo est m a rc a do como vi r tual. lo que significa que se puede r eemplazar en las clases de C#. Tambin est m a r c ad o como protegido, lo que significa que slo puede ser l lamado desde dentro de la clase o desde una clase deriv ada y no puede ser llamado desde fuera de una j erarqu a de clase. La i mplement aci n del objeto Finalize ( ) de N E T no hace nada, pero puede implementarlo si quiere. Tambi n puede escribir un dest ructor p ar a su clase, lo que produce el mi smo efecto (pero tenga cui dado al usarlo). De hecho, el compi lador de C# convierte el cdigo destructor en un mtodo reemplazado Finalize ().

protected object MemberwiseClone ( ) : Crea una copia idntica del objeto, asi gna al clon el mismo estado que el objeto original y devuelve el objeto copiado. Este mtodo no est m ar cado como v irtual, lo que signi fica que no se puede reempl azar en las clases de C#. Tambi n est m a r c a do como protegido, lo que significa que slo puede ser llamado desde dentro de la clase o desde una clase derivada y no puede ser llamado desde fuera de una j erarqua de clase.
Las est ructur as de C# no pueden tener clases bases definidas explcitamente pero se derivan implcitamente de la clase base ob j ec t . To do el c o mp or t a mi e n to de la clase object est disponible p ar a las estructuras y las clases de C#.

Cmo usar boxing y unboxing para convertir a tipo object y desde el tipo object
Como todas las clases y estructuras derivan en ultima instancia del tipo obj ect de NET. ste suele usarse a menudo en listas de par met ro s cuando el mtodo necesita ser flexible respecto a los datos que recibe. Observe, por ejemplo, el mtodo S y s t e m .Consol .WriteLine ( ) u s a do en este libro. Este mismo mtodo ha sido usado p a r a escribir cadenas, enteros y tipos dobles en la consola sin usar ningn oper ador de conversin explcita. En el listado 1 1.4. se escribe una cadena con comodines y los comodines son s us ti tuidos por los valores de los p ar met ro s que se le proporcionan. C mo funciona

279

en re al idad 9 Cmo sabe S y s t e m . C o n s o l . W r i t e L i n e ( ) qu tipos le va a pasar'.' La r e s p u e s t a es que no p ue de s aberl o. M i c r o s o f t c o n s t r u y el mt odo S y s t e m .Consol .Wr iteLine ( ) mucho antes de que t raba js emos con el listado 1 1.4. por lo que no poda saber qu tipos de datos le pasara. Microsoft implemento un mtodo System .Consol .Wr i teLine ( ) con la siguiente forma:
public static void WriteLine (string format, params obj ect [] arg) ;

El primer p ar amet ro es la cadena que se va a generar y el segundo parmet ro es una matriz de parmet ros que contiene una cantidad de elementos que se c a lc u la cuando se compila el codigo. Pero cul es el tipo de la matriz de p a r m e t r o s '} La m a t r i z de p a r m e t r o s es del t ipo ob j ect. O b s e r v e e st a l l a m a d a a

WrrteLine ():
System.Consolp.WriteLine (" ((0) , { 1} ) ", X , Y );

El compilador de C# convierte los parmetros X e Y en una matriz de parmetros y llama a WriteLine (). Los parmetros X e Y son de tipo entero, lo que. como ya ha visto, es un alias de una est ructura llamada System .Int32 . Como las estructuras de C# heredan del tipo de obj ect de NET. estas variables heredan del tipo obj ect y pueden ser us adas en una matriz de parmetros. Los literales, que se han estudiado con anterioridad, son algo ms co mp l ic a dos. En lugar de usar objetos, puede igualmente escribir el siguiente cdigo:
S ys t e m .C ons ole.WriteLine (" ({0} , {1})", 100, 2 0 0);

Este codigo tambin funciona correctamente. C mo sabe C# cmo conv ertir un valor literal en un objeto par a que pueda ser us ado en una llamada de mtodo que necesite un obj et o9 La respuesta esta en una tcnica llamada b oxm g. La tcnica de boxing permite que cualquier tipo de valor, incluso un literal, se pueda convertir en un objeto. Cuand o el compi lador de C# encuent ra un tipo de valor par a el que se necesita un tipo de referencia, crea una variable de objeto temporal y la asigna el valor del tipo de valor. Esta tcnica "encierra" el valor en un objeto. Observe nuevament e la anterior llamada WriteLine ():
System.Console.WriteLine (" ({0} , {1})", 100, 200);

El compi lador de C# encuent ra los literales y los encierra en objetos. Los objetos se envan a la llamada del mtodo en la matriz de parmet ros y a cont inua cin se eliminan los objetos temporales. Observe las siguientes instrucciones:
int MyVa le = J2 3; object MyOb]ect = MyValue;

C# encierra el valor de MyValue en el objeto MyObject.

280

C# tambin permite la tcnica de unboxing. que es simplemente el proceso opuesto al boxing. El unboxi ng reconvierte los tipos de referencia en tipos de valor. Por ltimo, cada tipo es un objeto. El boxing y el unboxing nos ayudan a visualizar esta idea. Como todo es un objeto, todo (incluidos los literales) puede ser tratado como tal y los mtodos de la clase object pueden llamarlos. El siguiente codigo funciona graci as a la tcnica de boxing del compi lador de C#.:
strinq M y S t r m g ; M y S t n n g = 12 3 .ToS t r ing ( );

El c o m p i l a d o r de C# a p l i c a la o p e r a c i n b o x i n g al v a l o r literal 123. t ras formnd ol a en un objeto v llama al mtodo ToString () sobre ese objeto.

Resum en
En la terminologa de la pro gr amaci n de software orientado a objetos, la herencia se usa par a describir una clase que hereda miembros de una clase base. C# admite la herencia simple, en la que una clase puede derivarse de una sola clase base. C# no admite la herencia mltiple, que si es admitida por algunos lenguajes orientados a objetos par a permitir que una clase pueda deriv arse de mas de una clase base. Las clases base de C# se especifican al declarar una clase. El identificado!' de clase base sigue al nombre de la clase deriv ada cuando se declara la clase C# permite que los miembros de clase pertenezcan a un at ri but o de mbito. El mbito de un miembro determina su accesibilidad para las clases derivadas y los fragmentos de cdigo que t rabaj an con los objetos de la clase. Los miembros de clase marcados como public son visibles par a las clases derivadas y para el codigo que crea los objetos de la clase. Los mi embros de clase marc ados como private solo son visibles para la clase en la que estn definidos o desde clases derivadas de la clase. Los miembros de clase marcados como internet 1 son visibles para todo el codigo en su mismo archivo binario, pero no son visibles fuera de los archivos binarios. Los miembros de clase marcados como prot ected internal son visibles par a cualquier codigo en su mismo archivo binario y para las clases externas que se deriven de la clase. Los mi embros de clase que no tienen ni nguna pal abr a clave de mbito son. por defecto, privados. Los mtodos y las propiedades de clases base pueden implementarse de nuevo en clases derivadas para prop or ci on ar nuevas implementaciones. Los mtodos y propiedades virtuales, que estn mareados con la pal abr a clave de C# v i r t . u a 1. pueden i mplementarse nuevament e en clases derivadas, siempre que la nueva i mpl eme nt ac ion m a n t e n g a el mi s mo i dent ifi cador . tipo d ev ue lt o y lista de par met ros. Las nuevas implementaciones de mtodos virtuales reciben el n o m bre de r e e m p la z a d a s x deben e st ar m a r c a d a s con la p a l a b r a clave de C# o v errid e.

281

Los m to d o s a b s tr a c to s son mt odo s de clases bas e que no pueden ser implementados. Los mtodos abs tr act os no suelen i mplement arse en clases base porque la clase base no tiene suficiente informacin como par a ofrecer una implementacin completa. Las clases que contienen al menos un mtodo abstracto reciben el nombre de clases abs tra ct as y deben usar la p al ab ra clave abstract en la declaracin de la clase. C# dispone de la pal abr a clave base que permite que las clases derivadas accedan a los miembros de una clase base. Se puede anteponer a los idcntificadores de miembros la pal abr a clave base y se puede usar esta p al abr a clave para llamar a un const ructor de clase base desde un const ructor de clase derivada. Por defecto, se puede us ar cualquier clase de C# como clase base y cualquier clase puede derivarse de cualqui er otra clase. Puede evitar este comport ami ent o marcando una clase de C # con la p al abr a clave sealed. Las clases selladas no pueden us ar se como clase base y el compi lador de C# no permite que se deriven clases a partir de clases selladas. Todas las clases de C# y. de hecho, cualqui er clase i mplement ada en un len guaje NET. deriva en ltima instancia de la clase N E T S y s t e m .Ob j e c t . La pal abra clave de C# object es otro nombre p ar a el identificador de clase System .Object. La clase Sys t e m .Ob j ect contiene algunos mtodos que pueden usar las clases derivadas y muchos de estos mtodos pueden ser r eempl a zados. La clase System. Object proporciona funcionalidad par a definir igualdad de objetos, clculo de cdigo hash. representaciones de cadenas, finalizacin de cdigo y clonacin de objetos. El tipo ob j ect puede ser us ado como un mtodo o variable de nombre de tipo y cualquier variable de C# puede usarse como un objeto object. C# convierte a ut omt icame nte al gunos tipos de valor, como tipos de valor y literales numricos y objetos de tipo ob j ect mediante las t cni cas de boxing y unboxing. La tcnica de Boxing encierra un valor en un objeto v la t cnica de unboxi ng devuelve el valor del objeto a su tipo de valor original.

282

Parte III

C# avanzado

283

Cmo trabajar con espacios de nombre


h vl
Las clases que disee las us ar a en su cdigo y p robablement e en el codigo de otras personas. Las clases de CU pueden ser usadas por una aplicacin V B .N E T o desde dentro de una pagina A S P. NE T. Ademas, las clases pueden ser usadas en combinacin con otras clascs di seadas por otros progr amadores de N E T El codigo escrito en un lenguaje N E T hace referencia a las clases por sus nombres y todas estas clases usadas en combinacin suscitan un dilema eviden te: (,Que ocurre si un p ro g ra ma do r quiere usar dos clases al mismo tiempo.' Supongamos que escribe una clase de CU que lee archivos de una base de datos y llama a esa clase Recordset. El codigo que quiera usar la clase puede crear objetos como el siguiente:
Recordset MyRecordset - new Recordset , ;

Ahora s upongamos que empaquet a las clases en un ens ambl ado . NET y di s tribuye ese ensambl ado par a que sea usado por otras aplicaciones. Ademas, s u ponga que alguien consigue su ens ambl ado y lo ntegra en su aplicacin. <,Que ocurri r si la misma aplicacin tambin hace uso de otro ens ambl ado escrito por otra persona y que tambin contiene una clase llamada Recordset ? Cuando el cdigo de la aplicacin crea un nuevo objeto Recordset. qu clase se usa para crear el objeto) La nuestra o la clase del otro cns ambl ado., Este problema puede resolverse mediante el concepto de CU de los espacios de nom bres. Los espacios

285

de nombres organizan las clases mediante un g ru po designado y el nombre del espacio de nombre puede ser us ado p ar a diferenciar dos clases con el mismo nombre. El cdigo C# debe us ar espacios de nombre p ar a posteriormente ayudar a identificar nuestras clases mediante un grupo comn, especialmente si est p l a neando construir un ensambl ado p ar a que sea usado por otros programadores. Los espacios de nombre pueden incluso ser tiles en las aplicaciones de C # que cons truyamos , porque de este modo pueden u sar e nsambl ados externos que usen nombres de clase iguales a los nuestros.

Cmo declarar un espacio de nombre


Un espacio de nombre se declara con la pal abr a clave de C# namespace seguida por un identificador de espacio de nombre y llaves. Las clases que se incluirn en el espacio de nombre deben declararse dentro de las llaves del espacio de nombre, como se puede ver en el siguiente cdigo:
namespace MyClasses MyFirstClass

{
class

Este fragmento de cdigo declara una clase llamada MyFirstClass en un espaci o de nombre llamado MyClasses. Otro pr og ra ma dor tambin podra es cribir otra clase llamada MyFirstClass, pero mientras el otro p ro gr amad or use un espacio de nombre diferente, el compi lador de C# encontr ar la clase ade cuada que debe usar par a una instruccin particular. Es posible declarar espacios de nombre dentro de otros espacios de nombre. Basta con encerr ar la declaracin del segundo espacio de nombre en el interior de la pri mera declaracin.
namespace MyClasses MylnnerNamespace MyFirstClass

{
namespace

{
class

w: pfoii%' <&?oiapiwm yaiganas

286

rutinas de emulacin de terminales. Estos espacios de nombre seran


W i d g e t .Compression y W i d g e t .Emulation, que agrupan los

productos de la compaa pero tambin los mantiene separados mediante el espacio de nombre Widget,
Si no quiere ani dar los espacios de n ombre de esta manera, puede conseguir el mismo efecto declarando las dos declaraciones de espacio de nombre en la misma instruccin y separndol os con un punto, como se indica a continuacin:
namespace MyClasses.MylnnerNamespace MyFirstClass

{
class

{ } } Los siguientes tipos de declaraciones pueden aparecer en un espacio de nombre: Clases Estructuras Interfaces Enumeraciones Delegados Cual qui er declaracin de un tipo que no est en esta lista produce errores del compi lador c uando se intenta compi lar la aplicacin.

Cmo declarar un espacio de nombre en varios archivos fuente


El compi lador de C# permite el uso del mi smo nombre de espaci o de nombre en varios archivos fuente. A continuacin crca un archivo binario que combina todas las clases en el mi smo espacio de nombre. Supongamos, por ejemplo, que quiere construir un ens ambl ado cuyas clases residan en un espacio de nombre llamado M y A s s e m b l y . que quiere escribir dos clases p ar a incluirlas en ese ensambl ado y que quiere definir las clases en a r ch i vos separados. Puede simplemente reutilizar el nombre del espacio de nombre en los dos archivos fuente. El primer archiv o fuente puede contener la declaracin de la pri mera clase, como en el siguiente ejemplo:
namespace MyAssembly

287

class MyFirstClass

{ } } El segundo archivo fuente puede contener la declaracin de la segunda clase y puede us ar el mismo nombre de espacio de nombre:
namespace MyAssembly MySeconde 1ass

{
class

{ } } C uand o los dos archivos fuente se construyen en un solo ensambl ado, el c o m p i l a d o r de C# c r e a un e n s a m b l a d o con un sol o e s p a c i o de n o m br e. M y A s s e m b l y . con dos clases en el espacio de nombre. Esto tiene una ventaja par a el pr ogr amad or en caso de que quiera separar a lgunas funcionalidades en distintos archiv os o simplemente, si quiere reducir al mnimo la longitud de cada archiv o fuente.

Cmo usar clases en un espacio de nombre


Si quiere hacer referencia a una clase en un espacio de nombre especfico, ant eponga al nombre de la clase el nombre de su espacio de nombre:
M y C 1 a s s e s .My F i r s t C 1 ass MyObj ect - new MyClasses.MyFirstClass (;

Esta sintaxis ayuda a distinguir entre las clases de diferentes codigos base con el mismo nombre. El compi lador de C# ya tiene suficiente informacin par a en cont rar la clase correcta, porque tambin sabe a qu espacio de nombre debe dirigirse par a encontrar las clases que estamos buscando. C uand o se t rabaja con clases declaradas en espacios de nombre anidados, deben a pa rec er todos los nombres de espacios de nombre cuando se hace referen cia a esa clase:
Name^space 1 .Namespace! .MyClass MyObj ect N a m e s p a c e 1.N a m e s p a c e 2 . M y C l a s s (i; = new

El listado 12.1 ilustra el concepto de espacio de nombre


Listado 12.1. Clases en espacios de nombre diferentes namespace N am e s p a c e 1 TestClass

{
class

288

public TestClass()

{
System. Consol . W r i t e L m e ("Helio a m e s p a c e l . T e s t C l a s s !"); from

} } }
namespace Namespace2 TestClass TestClass( ) from

{
class

{
public

{
System. Consol.WriteLine("Helio N a m e s p a c e 2 . T e s t C l a s s !");

} } }
class MainClass static void M a i n () Objectl 0bject2 = new N am e sp ac e1.TestClass ( ); = new Namespace2.TestClass ( );

{
public

{
N a m e s pa ce 1.TestClass amespace2.TestClass

} } El cdigo del listado 12.1 declara dos clases llamadas T e s t C l a s s . Cada una de las declaraciones de clase est en un espacio de nombre diferente y el const ructor de cada clase escribe un mensaje en la consola. Los mensajes son ligeramente diferentes de modo que se puede saber cual es el mensaje que emite cada clase. El m t o d o M a i n ( ) del l i s t a d o 12.1 c r e a d os o b j e t o s , u n o de t i p o N a m e s p a c e l . T e s t C l a s s v otro de tipo N a m e s p a c e . T e s t C l a s s . Como los constructores de las clases escriben mensajes en la consola, si se ejecuta el cdigo del listado 12.1 obtendremos como resultado la figura 12.1. Observe que la clase M a i n C l a s s del listado 12.1 no est encerrada en una declaracin de espacio de nombre. Esto es per fectamente valido en C#. No es necesario encerr ar las clases en declaraciones de espacio de nombre. Sin e m b a r go. las clases que no estn encerradas en espacios de nombre no pueden usar el mi smo nombre en ot ra clase definida sin un espacio de nombre Si necesita usar una clase que est declarada en un espacio de nombre, debe usar el nombre de su espacio de nombre al usar el nombre de la clase. Si no hace esto, el compilador de C# emitir un mensaje de error. Suponga, por ejemplo, que el mtodo M a i n ( ) del listado 12.1 intenta crear un objeto de la clase T e s t C l a s s :
TestClass Objectl = new TestClass ();

289

C :\W IN D 0W S\System 32\cm d.exe


C : \ > 1. i r; *. i n y 1 A. 1 .e x o

He l io f rom N<u;pac e 1 .Te^tClas Helio fi'on NancniJrt(:e2 .Te:;tClai

C: \ >

Figura 12.1. C mo hacer referencia a clases dentro de espacios de nombre

El compi lador de C# no puede encontrar una clase llamada TestClass definida fuera de un espacio de nombre y emite el siguiente error:
error CS0234: El tipo o el nombre del espacio de nombres 'TestClass' no existe en la clase o el espacio de nombres 'MamClass' (falta una referencia de ensamblado?)

Si revisa los ejemplos de los captulos anteriores, co mp ro b ar que esta es la sintaxis que hemos estado usando en todas nuestras llamadas a WriteLine () . como m ues tra el siguiente ejemplo:
System .C on so l .W r i t e L i n e ("Helio from C#!");

El mtodo WriteLine ( ) est en una clase llamada Consol y la clase Consol est definida en un espacio de nombre de N E T llamado System.

Cmo ayudar a los espacios de nombre mediante la palabra clave using


Hay varias maneras de usar la pal ab ra clave de C# using par a facilitar el t rabajo con los espacios de nombre y a hor rar u na buena cantidad de cdigo. A primera vista, la pal ab ra clave using parece la tpica directiva #include de C/ C++. No se deje engaar; sus ventajas son mu ch o ms potentes. Las siguientes secciones describen algunas de estas ventajas.

Cmo crear alias de nombres de clase con la palabra clave using


Escribi r nombres de clase per fectamente vlidos y que incluyan nombres de espacio puede ser un poco tedioso, especialmente si los nombres son largos. Pue-

290

de usar la p al abr a clave u s i n g p ar a crear un alias p ar a el identificador de clase completo y, c ua ndo se h a ya est abl eci do el alias, puede us ar lo en l ugar del identificador de clase completo. Puede cr ear un alias mediante una instruccin que tenga la siguiente estructura: La p al ab ra clave using El nombre del alias Un signo igual El nombre de la clase c ompl et a con el identificador de espaci o de nombre Un punt o y c oma de fin de instruccin El listado 12.2 se aade al listado 12.1 creando alias p a r a los nombres de clase y acort ando as sus equivalentes. El mtodo M a i n ( ) utiliza los nombres a c o r t a dos p ar a t rab aj ar con los objetos de las clases.
Listado 12.2. C m o crear alias de los nombres de clase using Classl using Class2 namespace = N a m e s p a c e l .T e s t C la ss ; = N a m e s p a c e 2 .TestClass ;

Namespacel TestClass TestClass( ) from

{
class

{
public

{
System. Consol.WriteLine("Helio N a m e s p a c e 1.T e s t C l a s s !");

} } }
namespace Namespace2 TestClass TestClass( ) from

{
class

{
public

{
System. Consol.WriteLine("Helio N a m e sp ac e2 . T e s tC la ss !");

} } }
class MainClass static void M a i n ( )

{
public

291

Cla ssl Object 1 = new Cassi ( ); C lass2 Object2 = new Class2()

} El listado 12.2 escribe los mismos mensajes que el anterior ejemplo. Puede ver estos resultados en la figura 12 . 2 .
CV

C:\WIND0WS\System32\cmd.ene

JJQJxJ

C:\>Listinyl2 2.exe Hello fron Nanccpacel .Ies fcClass * Hello fron Name-,; pace2 .Tes t C 1as s ?

Figura 12.2. Cmo crear alias de los nombres de clase

Las instrucciones u s i n g deben incluirse en el cdigo fuente antes de que se declaren los espacios de nombres. Si aparecen despus de las declaraciones de espaci o de nombre, recibir el siguiente mensaje de error del compi lador de C'#:
error CS152 9: Una clausula using debe ir delante elementos restantes del espacio de nombres de todos los

En captulos anteriores ya vimos que las p al ab ras clave de C# que definen los tipos de variable son en realidad est ructuras definidas por N E T Framework. Observe de nuevo la tabla 7 . 1 y preste atencin a lo siguiente: Las es tructur as de tipo de valor residen en el espacio de nombre de NET S ystem . La pal abra clave u s i n g se usa par a crear alias de los nombres de estruc t uras de N E T con las pal ab ras clave de C # equivalentes. Puede imaginar como se implementa la tabla 7 . 1 en N E T Framework mediante instruccio nes de C# como las siguientes:
using sbyte = System.SByte; using byte = System.Byte; using short = Sy stem.In116 ; // ... mas declaraciones . . .

292

Puede crear alias de nombres de espacio de nombres as como de clases, como demuest ra el listado 12.3.
Listado 12.3. Creacin de alias de espacios de nombre using NI - Namespacel; using N2 - Namespace2; namespace Namespacel

{
c1a s s Tstelass

{
p u b 1 ic Te s tClass ( )
f

{
S ys t.em. Consol e .WriteLine ("Helio ame space 1 .Tes t C 1ass !"! ; r om

} } )
namespace Namespace2

{
c 1a s s Tes t C 1ass

{
public TestClass () trom

1
S ystem. Con sol. W r i t e L m e ("Helio N a m e s p a c e l . T e s t C l a s s !");

} ) }
class MainClas s static void M a m ( ) Objectl Object2 = new N I .TestClass ( ); = new N2.TestClass ( );

{
public

{
NI .TestClass N2.TestClass

} }

Cmo declarar directivas de espacio de nombre con la palabra clave using


Si usa una clase declarada en un espacio de nombre, debe anteponer al nombre de clase el nombre del espacio de nombre, aunque no este t r ab aj and o con ningn otro espacio de nombre que pueda tener una clase con el mismo nombre. Esta es la razn por la que los ejemplos que hemos usado hast a este moment o siempre han llamado a WriteLine ( ) con el calificador del espacio de nombre System:
Syst em.Consol.WriteLine ("Helio f rom C# !" ) ;

293

Por defecto, si no se usa el nombre de espacio de nombre, el compi lador de C# emite un error:
error CS0234: El tipo o el nombre del espacio de nombres 'TestClass' no existe en la clase o el espacio de nombres 'MainClass' (falta una referencia de ensamblado?)

An teponer ca da n ombre de clase con nombres de espacios de n ombre como

System es tedioso, especialmente si hay que hacerlo muchas veces. A f o r t un ad a mente, se puede u s ar la p a l ab r a clave using p a r a reducir el t iempo de codi fi ca
cin. Al usar la palabra clave using con un n ombr e de espacio de n om br e se advierte al compi lador de C# que se quiere hacer referencia a clases en el espacio de nombres desi gnado sin a nt epone r a los n ombres de clase el nombre de espacio de nombre. Observe, p or ejemplo, la siguiente instruccin:
using System;

Esto recibe el nombre de directiva de espacio de nombre. Las directivas de espacio de n ombre avisan al c ompi lador de C# de que el cdigo u s a r clases del espacio de nombres y que las clases no llevarn ant epuest o el nombre del e s p a cio de nombre. El c ompi lador de C# se en car ga de encontr ar la definicin de c ada clase en ca da espacio de n ombre al que se hace referencia en u na directiva de espacio de nombre. El listado 12.4 es un a modificacin del listado 12.2; incluye un a instruccin using que hace referencia al espacio de nombre de . NET System.
Listado 12.4. Cmo usar una directiva de espacio de nombre using System; using using Classl Class2 = N a m es pa ce 1.T e s t C la ss ; = amespace2.T e s tC la ss ;

namespace

Namespacel TestClass TestClass( ) from N a m e s p a c e l .T e s t C l a s s !");

{
class

{
public

(
C o n s o l .W r i t e L i n e ("Helio

} } }
namespace Namespace2 TestClass TestClass( )

{
class

{
public

294

Console. W r i t e L m e ("Hello

from

Namespace2.TestClass !" )

class

MainClass static void M a i n ( )

{
public

{
Class i O b j e c t 1 = new C l a s s 1 ( ); Class2 0bject2 = new C l a s s 2 ();

} } La directiva de espacio de nombre System del listado 12.4 permite que el cdigo haga referencia a la clase Consol sin que se le ant ep on ga el espacio de nombre System.

Un rpido recorrido por los espacios de nombre de .NET


. NET F ramework tiene clases en multitud de espacios de nombre predefinidos que pueden usarse en otros cdigos de C#. La siguiente lista describe al gunos de ellos: El e s p a c i o de n o m b r e S y s t e m c o n t i e n e c l a s e s q ue i m p l e m e n t a n funcionalidades bsicas, como conversiones de tipos de datos, operaciones matemticas, invocacin a p rogr amas y gestin del entorno de procesos. El espaci o de n ombre System es el m ayo r de los propor ci onados por NET. N E T Fr amewo rk tambi n contiene el espacio de nombre Microsoft que b ri nda compat ibi lidad con versiones anteriores, adems de otros ele mentos generalmente tiles. El espacio de n ombr e S y s t e m .CodeDOM contiene clases que r epr es en tan los elementos de un do cument o de cdigo fuente. El espacio de nombre System. Collections contiene clases que i mplementan colecciones de objetos, como listas, colas, matrices, tablas hash y diccionarios. El espacio de nombre S y s t e m .ComponentMode 1 contiene clases que se usan p a r a crear componentes v controles durante el t iempo de diseo y ejecucin. Este espacio de nombre pro po rci ona interfaces y clases par a crear atributos, establecer enlaces a varias fuentes de datos, conceder li cencias de componentes, ade m s de p a r a convertidores de tipos.

295

El espacio de nombre System. Data contiene clases que c omponen la arquitectura de acceso a datos de A DO . N ET . La arquitectura A D O . N E T permite construir componentes que pueden gestionar datos de varias fuen tes de datos en modo desconect ado o conectado. El espacio de nombre System. Diagnostics contiene clases que a y u dan a detectar errores en aplicaciones de . NET y supervisar la ejecucin del cdigo. El espacio de nombre S y s t e m .Diagnostics tambin c on tiene clases que permiten supervisar la actuacin de la aplicacin mediante contadores de rendimiento y registros de eventos. Aunque la funcionalidad no se considera realmente un diagnstico, este espacio de nombre tambin permite iniciar y detener procesos. El espacio de nombre System. Drawing contiene clases que implementan funcionalidad de dibujo del Dispositivo de mt erfaz grfica (GDI). Este espacio de nombre no est disponible por defecto; hay que crear una refe rencia a l desde el men Proyecto. El espacio de nombre System. 10 contiene clases que pueden leer y es cribir flujos de datos y archivos de disco. Las clases contenidas en este espacio de nombre pueden gestionar la entrada y salida de archivos sincr nica y asincrnica. El espacio de nombre Sys t e m .Messaging contiene clases que t r a b a jan con colas de mensajes. Este espacio de nombre no est disponible por defecto; hay que crear una referencia a l desde el men Proyecto. El espaci o de n ombre System. Net contiene clases que p ropor ci onan un contenedor de clase p ar a los muchos protocolos que se utilizan a c tu al me n te en las redes. Este espacio de nombre consta de clases p ar a gestionar peticiones de DNS. H T T P y peticiones de FTP. Adems de las clases gene rales de acceso a redes, tambin hay muchas clases de seguridad de redes que tratan los diferentes aspectos de la seguridad, desde accesos a sitios We b hast a accesos de nivel de socket. El espacio de nombre System. Reflection contiene clases que p ro porcionan una vista de tipos, mtodos y campos disponibles par a una apli cacin de NET. Incluso es posible crear e invocar tipos dinmicamente en el t i e m p o de e j e c u c i n u s a n d o las c l a s e s del e s p a c i o de n o m b r e

System.Reflection.
El espaci o de nombre S y s t e m .Resources proporciona clases que per miten a los progr amadores crear, al macenar y admi ni strar recursos espec ficos de las referencias culturales que se utilizan en las aplicaciones El espacio de nombre System. Runtime no es muy til por s mismo. Sin embargo, dispone de docenas de clases que p ropor ci onan una enorme

fu nc io na l id a d. Po r ej empl o. System. R u n t i m e . I n t e r o p S e r vices permite el ac ceso a objetos C O M y a los API nativos desde NET. El espacio de nombre System. Security contiene clases que pe r mi ten el acceso a la est ructur a subyacente de seguridad de N E T Framework. El espacio de nombre de seguridad es el punto de par ti da p ar a otros e s p a cios de nombre ms avanzados de muchos servicios de cifrado. Estos ser vicios incluyen el cifrado y descifrado de datos, generacin de hash y generacin de nmeros aleatorios. El espacio de nombre System. Text contiene clases que permiten t r a baj ar con codificaciones de caracteres ASCII. Unicode. UTF-7 y UTF-8. El espacio de nombre S y s t e m .Threading contiene clases que p e r m i ten i mplcmentar varios subprocesos del sistema operativo en las apl icaci o nes N ET , creando as una autntica aplicacin multiproceso. El espacio de nombre S y s t e m .Timers contiene clases que permiten des encade nar un evento en un intervalo de tiempo det er minado o en unos plazos ms complejos. Estos t empori zadores se basan en el servidor. Un t empori za dor b as a do en un servidor tiene la capaci dad de moverse entre los s ubprocesos p a r a iniciar el evento, lo que propor ci ona una flexibilidad m ay or que el t emp ori za dor tpico de Wi ndows. El espacio de n ombre System. Web contiene clases que i mplementan el protocolo de transmisin del hipertexto ( H T T P ) que utilizan los clientes We b p ar a acceder a pginas de Internet. Este espacio de nombre no est disponible por defecto; hay que crear una referencia a l desde el men Proyecto. El espacio de nombre S y s t e m .Windows .Forms contiene clases par a crear aplicaciones completas par a Windows. Las clases del espacio de nombre S y s t e m .Windows .Forms propor ci onan un entorno de clase NE T con los controles tpicos de Windows como cuadros de dilogo, mens y botones. Este espacio de nombre no est disponible por defecto; hay que crear una referencia a l desde el men Proyecto. El espaci o de nombre S y s t e m .Xml contiene clases que pueden procesar datos XML. Este espacio de nombre i n cl i n e compatibilidad con espacios de nombre X M L 1.0. XML. esquemas XML. XPath. X SL y XSLT. DOM Level 2. y S OAP 1.1. Aunque no es una lista completa, debera darle una idea de la inmensa cantidad de espacios de nombre ya i mplcmentados por N E T F ramework Consulte la d o cumentacin del S D K de N E T F ramework p ar a conseguir una lista completa de espacios de nombre y clases.

297

Resumen
Las clases y est ructuras que desarrolle se pueden enc ap su lar en los l lama dos espacios de nombre. Los espacios de nombre ayudan a diferenciar unas clases y est ructuras de otras que t engan el mismo nombre. Una clase o es t ru ct ur a compl et a incluye el nombre del espacio de nombre que alberga a la clase o estructura. Cuand o se hace referencia a una clase o es tr uc tu ra en un espacio de nombre, hay que cualificar el nombre ant eponi en do el n ombre del espacio de nombre y un punto. Se puede usar la pal abra clave u s i n g p ar a facilitar el trabajo con los nombres de espacios de nombre en el cdigo de C#. La p al ab r a clave u s i n g puede usarse par a propor ci onar un alias par a una clase particular en un e spa cio de nombre concreto. Tamb in puede us ar se c omo una directiva de espacio de nombre, que avisa al compi lador de C# de que nuestro cdigo va a hacer referencia a clases en un espacio de nombre especfico y de que el cdigo no ant epondr el identificador de espacio de nombre a las clases de ese espacio de nombre. Puede crear sus propios espacios de nombre y puede u sar el cdigo incluido en espacios de nombre desarrollados por otras personas mediante las tcnicas reseadas en este captulo. . NET F ramework incluye una gran cantidad de espacios de nombres llenos de clases, lo que facilita la labor de codificar cualquier cosa, desde aplicaciones Wi ndo ws has ta procesadores de X M L y p rog ra ma s de seguridad. Los espacios de nombre de N E T F ramework t a m bin proporci onan clases que pueden usarse p a r a cr ear cdigo C# mediante tcnicas avanzadas, como el s oftware de multi proceso y la reflexin.

298

13 Interfaces

Una interfaz de C# es un conjunto de firmas de mtodos, propiedades, exen tos o indizadores agr up ad os con un nombre comn. Las interfaces funcionan como conjuntos de funcionalidades definidas que pueden i mplement arse en una clase o est ructura de C#. Las clases o est ructuras que implementa una interfaz propor ci onan implementaciones p ar a todos los mtodos definidos en la interfaz. Supongamos , por ejemplo, que queremos que las clases de nuestro provecto puedan g uar dar los valores de sus campos en una base de datos y recuperarlos ms tarde. Al i mplementar este requisito, podr amos decidir que todas las clases deban i mplement ar un mtodo ll amado Load ( ) y otro llamado Save ( ) . T a m bin p odr amos definir los mtodos en una interfaz llamada I Per s is tToDis k (los nombres de una interfaz c omienzan normal ment e con la letra I. aunque no es obligatorio en C#) y exigir que nuestras clases implementen esta interfaz. El cdigo de C# puede consul tar un objeto p ar a determinar si admite una interfaz. Consult ar a un objeto acerca de una interfaz es bsicamente hacer la p regunta "Admites esta i nt erfa z7" El objeto responde "S" o "No". Si el objeto responde "S", se puede llamar al mtodo en la interfaz. Los mtodos llamados en una interfaz siempre tienen la mi sma lista de par met ros y valores devueltos, aunque sus implementaciones pueden ser diferentes. Imagi ne u n a i nt erfaz como un c ont ra to, una p r o m e s a de que una clase implement ar un conjunto especfico de funcionalidades. Si un objeto responde

301

"S. vo admito la mtcrfaz por la que est preguntando", est asegurando que p r o porciona una implementacin par a cada uno de los mtodos definidos en la interfaz. Las interfaces no propor ci onan sus propi as implementaciones de mtodos. Slo p ropor ci onan identificadorcs de mtodos, listas de p ar met ro s y cdigos devuel tos. Las clases que implementan la mt crfaz son las responsables de proporci onar una implementacin. Dos clases que implement an la mi sma interfaz pueden i mplementar los mtodos de la i nterfaz de modos muy distintos. Esto es correcto, siempre que las clases sigan definiendo las firmas de los mtodos en la definicin de la interfaz. Vamos a usar la interfaz IPersistToDisk como ejemplo. Puede tener objetos en su aplicacin que necesiten abrir su estado desde un disco y g ua r da r su e s t a d o de n u e v o en un d i s c o . P o d r a d e c i d i r i m p l e m e n t a r la i n t e r f a z IPersistToDisk en estos objetos. Para cada uno de los objetos que mplcmenten IPersistToDisk. necesitar escribir cdigo p ar a los mtodos Load ( ) y Save ( ) de la interfaz. Algunos de los objetos pueden tener necesidades de a l m a cenami ent o bsicas, de modo que esos objetos pueden implement ar los mtodos Save ( ) y Load ( ) mediante un simple cdigo de E/S de disco. Otros objetos pueden ser ms complicados y necesitan compatibilidad con la E/S transaccional. en la que toda la operacin de persistencia debe tener xito o f r aca sa r como un todo. Para esos objetos, quizs prefiera implementar los mtodos Load ( ) y Save ( ) usando cdigo transaccional. ms robusto. La clave est en que el cdi go que usan estos objetos no necesita saber si el objeto us a cdigo simple o transacci onal en su implementacin. Slo p re gu nt a a cada objeto "Admites el m t o do IPersistToDisk ?" Para los objetos que responden "s", el cdigo que usa los objetos puede llamar a Load ( ) o Save ( ) sin necesidad de saber cmo estn implementados realmente esos mtodos. Conceptualmente, las interfaces son muy parecidas a clases base abstractas: las dos proporcionan una lista de mtodos que deben ser implcmentadas por otros fragmentos de cdigo. Sin embargo, hay una diferencia importante: las interfaces pueden ser implcmentadas sin importar la posicin de la clase de implementacin en una jerarqua de clases. Si se usan clases base abstractas, todas las clases que quieran i mplementar la funcionalidad deben derivarse directa o indirectamente de la clase base abstracta. Esto no ocurre con las interfaces: las interfaces pueden implementarse en cualquier clase, sin importar su clase base. Las clases no nece sitan derivarse de una clase base especfica antes de poder implementar una interfaz. El concept o de interfaz como modelo de diseo de soft ware no es nueva; sin embargo, el modelo de objetos de componentes ( C O M ) de Mi crosoft popul ari z el concepto. C O M t rajo la idea de las i nterfaces (conjunt os espec fi cos de funcionalidad implementados por un objeto) a la vang ua rd ia del desarrollo de soft ware b as ado en Wi ndows. C # llev ms all el concepto, promovi endo el concepto como una ca rac te r st ic a de lenguaje en el nivel de cdigo. Aunque las primeras versiones de C ++ o Visual Basic ya tenan interfaces C O M integradas, estos lenguajes no eran compatibles con el concepto como rasgo de lenguaje. La

302

palabra clave de C # interface hace que el concepto de p rog ra ma ci n de interfaz sea compat ibl e con el cdigo fuente y est disponible p a r a el cdigo, aunque el cdigo no use C OM . Este captulo le ensea a t raba jar con interfaces usando C#. Aprender a defi nir una interfaz usando la pal abr a clave interface. Tambi n aprender a definir e implcmentar mtodos, propiedades, indizadores y eventos en una interfaz y a acceder a una interfaz i mplementada por un objeto.

Cmo definir una interfaz


El primer paso al t ra ba j ar con interfaces en C# consiste en definir los mtodos que componen la interfaz. Las interfaces se definen en C# con la siguiente sin taxis: La pal abra clave interface Un identificador de interfaz Interfaces base opcionales Una llave de apert ura Una o ms declaraciones de mi embro de interfaz Una llave de cierre Las interfaces pueden definir mtodos, propiedades, indizadores y eventos. Estos constructores de lenguaje trabaj an sobre las interfaces del mismo modo que traba jar an con las clases de C#. Los mtodos de interfaz definen bloques de codigo con nombre; las propi edades definen variables que pueden ser validadas mediante cdigo descri ptor de acceso y los ev entos definen acciones que pueden ocurrir en el cdigo.

Cmo definir mtodos de interfaz


La agregacin de un mtodo a una interfaz significa que cualqui er objeto que desee i mplcmentar la interfaz debe p rop o rc io na r una implementacin del mtodo de interfaz. Esto gar ant iza al cdigo que los objetos que i mplementan la interfaz. i ncluyendo una implementacin del mtodo, pueden ser llamados por el cdigo. Para definir un mtodo en una interfaz. realice una declaracin de mtodo que proporcione el tipo devuelto por el mtodo, el identificador y la lista de parmetros. La definicin en C# de la interfaz I Per s is tToDis k que aparece al principio del captulo sera:
interface IPersistToDisk

{
bool Load(string FileName);

303

bool Save ( s t n n g FileName);

} La intcrfaz define dos mtodos, pero no prop or ci on a ni nguna i mplementacin p a r a los mtodos. Las declaraciones de mtodo t erminan con un punt o y coma. Las clases de C# que implementa la interfaz IPersistToDisk prometen que pr opo rci onar n una implementacin de los mtodos Load () y Save ( ) tal y como se definen en la interfaz.

definir propiedades de interfaz


piedades definen variables que pueden ser definidas por una interfaz. Al igual que las propiedades de clase, las propiedades de interfaz estn asociadas con funciones de descriptores de acceso que definen el cdigo que debe ejecutarse cuando se lea o escriba el valor de la propiedad. Para definir una propiedad en una interfaz hay que indicar el tipo de propiedad, el identificador y las pal abr as clave descriptoras de acceso seguidas de puntos y comas. Las pal abr as clave descriptoras de acceso aparecen entre llaves. La clase o estructura que implementa la interfaz es la responsable de proporcionar la implementacin de los descriptores de acceso de la propiedad. Para definir una propiedad de lectura/escritura en una interfaz hay que usar las pal abr as clave descriptoras de acceso get y set:
interface Interfacel { get; set; }

{
int RecordCount

} Para definir una propiedad de slo lectura en una interfaz. bast a con incluir la p a l a br a clave descriptora de acceso get:
interface Interfacel { get; }

{
int RecordCount

} P ar a definir una propiedad de slo escritura en una interfaz. b as ta con incluir la p al ab ra clave descriptora de acceso set:
interface Interfacel { set; }

{
int RecordCount

Cmo definir indizadores de interfaz


Los indizadores son propi edades especiales que permiten al cdigo acceder a datos como si estuvieran al macenados en una matriz. Los indizadores pueden definirse en una interfaz del mismo modo que se definen en una clase. Para definir

304

un indizador en una interfaz hay que indicar el tipo del indizador. la pal abr a clave this. la lista de par met ros del indizador entre corchetes y las pal ab ras clave descriptoras de acceso seguidas de puntos y comas. Las palabras clave descriptoras de acceso aparecen entre llaves. La clase o est ructur a que implementa la interfaz es la responsable de proporci onar la implementacin de los descriptores de acceso del indizador. P a ra definir un indizador de l ectura/escritura en una interfaz. use las pal abras clave descriptoras de acceso get y s e t :
m t e r f a c e Interfacel

{
in t this [mt Index] { get; set; }

} Para definir un indizador de slo lectura en una interfaz. basta con incluir la p al ab r a clave descri ptora de acceso get:
mterface Interfacel [mt Index] { get; }

{
int this

} Para definir un indizador de de slo escritura en una interfaz. bas ta con incluir la pal abr a clave descriptora de acceso s e t :
mterface Interfacel [mt Index] { set; }

{
int this

Cmo definir eventos de interfaz


Los eventos pueden definirse en una interfaz del mismo modo que se definen en una clase. Quizs quiera aadir un evento a la interfaz IPersistToDisk m e n ci onada al principio del captulo p ar a que. por ejemplo, se desencadene cuando las implement aci ones de Save ( ) y Load ( ) empiecen a t rab aj ar realmente con el disco par a abrir o g ua r d a r los datos del objeto. Para definir un evento en una interfaz hay que us ar la pal abr a clave event. el tipo del evento y un identificador de evento:
mterface Interfacel EventHandler ClickEvent;

{
event

Cmo derivar a partir de interfaces base


Las interfaces pueden derivarse de interfaces base, igual que las clases deri van de clases base. Las interfaces base se escriben tras los dos puntos que

305

siguen al nombre de la interfaz derivada. A diferencia de las clases base, las interfaces pueden derivarse de ms de una interfaz base. Los diferentes nombres de interfaces base se separan por comas, como se puede apreciar en el siguiente ejemplo:
interface Interface!

{
void Method 1 ( );

}
interface Interiace2

{
void M et h od 2 ( );

}
interface Interiace3 : Interfacel, Interface2

Es til derivar de una interfaz base cuando una interfaz contiene un conjunto de firmas de mtodo, propiedad y evento que deben ser aadidas a una interfaz ya progr amada. Por ejemplo. N E T F ramework define varias mterfaces que p u e den i mplementarse y usarse en C#. Como las interfaces ya son una parte de N E T Framework, la lista de mtodos, propiedades, indizadores y eventos que admiten se ha consolidado y no puede cambiar. Si quiere u sar una interfaz defini da y necesita aadir ms firmas a la interfaz p ar a uso propio, debera considerar la posibilidad de derivar desde la interfaz ya definida y aadir sus nuevas firmas en la interfaz derivada. Las cl ases que i m pl e m e n t a n u n a i n t e rf a z d e r i v a d a d eben p r o p o r c i o n a r implementacioncs para todos los mtodos definidos por las interfaces base. C u a n do una clase implementa una interfaz. debe pr op or ci on ar el cdigo par a cada uno de los mtodos definidos en la interfaz. Si una clase i mplementa Inter face 3 . por u sar el ejemplo anterior, la clase debe pr op or ci on ar las implementacioncs de mtodo p ar a Methodl () y Method2 (). No se puede derivar una interfaz de ella misma. Obser ve la siguiente definicin de una interfaz:
mterface Interfacel : Interfacel

{
void M e t h o d 1();

} Este error hace que el c ompi lador de C# p rod uz ca el siguiente mensaje de error:
error
en la

CS0529:

La interfaz
de la

heredada

'Interfacel'

crea un ciclo

jerarqua

inter faz

'Interfacel'

Este mensaje de error indica que el cdigo est intentando deriv ar una interfaz de s misma, lo que no se permite en C#. Las interfaces slo pueden derivarse de otras interfaces.

306

Cmo usar la palabra clave new para reutilizar identificadores


Se puede usar la pal abr a clave new p a r a redefinir un identificador usado en una clase base. S uponga que est t raba jando con una interfaz que define una propi edad l lamada ID:
interface Baselnterface { get; }

{
int ID

} Ahora s uponga que quiere derivar de esa interfaz. pero le g us t ar a usar el identificador ID como nombre de un mtodo:
interface Derivedlnterface : Baselnterface

{
int ID() ;

} Esta const rucci n hace que el compi lador de C # emita un aviso sobre la reutilizacin del identificador ID:
warning CS0108: La palabra clave new es necesaria en 'Derivedlnterface .I D ( ) ' porgue oculta el miembro heredado 'Baselnterface.ID'

El compi lador est avi sando de que el identificador ID se est usando dos veces: una vez en la interfaz base y otra en la interfaz derivada como un nombre de mtodo. La reutilizacin de este nombre puede confundir fcilmente a los usuarios de la interfaz. El aviso del compi lador significa que el uso de la pa la br a clave ID en la interfaz derivada tiene prioridad sobre el uso de la p al ab ra clave I D en la interfaz base. Si un fr a gm en t o de cdi go recibe una i mpl eme nt aci n de la interfaz Derivedlnterface. el cdigo ser i ncapaz de llamar al mtodo ID ( ) pero no puede acceder a la p ropiedad I D de la interfaz base. La r c ut il i zac i n del i d en t if ic ad o r ID en la i nt er fa z d e r i v a d a o c u l t a el identificador ID en la clase base por lo que los clientes no pueden acceder a la propiedad de la interfaz base. Para resolver este probl ema se puede us ar la p al ab ra clave new al reutilizar el identificador. El uso de la p al abr a clave new. mos trad o en el siguiente ejemplo, indica al compi lador de C# que se quiere dar un nuevo uso al smbolo reutilizado:
interface Derivedlnterface ID ( ); : Baselnterface

{
new int

307

Cmo implementar interfaces en clases y estructuras


Tras definir una interfaz. se puede i mplementar esa interfaz en clases v es tru c turas. Esto indica a los usuarios de la clase o est ructur a que sta proporciona i mplementaciones a los const ructores definidos en la interfaz. Por eiemplo. si i mplementamos en una clase la interfaz IPersistToDisk que apareca en la introduccin, i nformar emos a los usuar ios de la clase que sta propor ci ona implementaciones de los mtodos Save ( ) y Load ( ) y que se puede llamar a los mtodos. Las interfaces que se estn i mplementando se identifican de la mi sma forma que las clases base, con una lista de nombres tras dos puntos que siguen al identificador de clase o de estructura:
mterface Interfacel

{
v o ie l M e t h o d 1 () ;

}
class MyClas.s : Interfacel

{
void M e t h o d 1()

{ } } Este cdigo define una interfaz llamada Interfacel. El mtodo Interface 1 declara un mtodo: un mtodo llamado Method 1 (). El codigo tambin declara una clase l l a m a d a MyClass. que implementa la interfaz Interfacel. La clase MyClass incluye una i mplementacin par a el mtodo Method 1 ( ) definido por la interfaz Interfacel. Aunque la clase slo puede derivarse de una clase base, puede implementar tantas interfaces como se deseen. Solamente hay que escribir las interfaces tras el identificador de clase y s epa rar cada interfaz con dos puntos:
class MyClass : Interfacel, Interface2, Interface3

La implementacin de interfaz mltiple se usa en todo N E T Framework. Por ejemplo, la clase System. String implementa cuatro interfaces definidas por N E T Framework: IComparabl e. que c o mp ar a los valores de dos objetos del mi smo tipo. ICloneable. que crea un nuevo objeto que tiene el mi smo estado que otro objeto. IConvertible. que convierte el valor de un tipo a un valor de otro tipo. IEnumerable, que permite que el cdigo itere a travs de una coleccin

308

Como la clase S ystem. S t r i n g i mplementa estas cua tr o interfaces. la funcionalidad que cada una de las interfaces propor ci ona es compatible con la clase System. String. Esto significa que las cadenas pueden ser comp ar ad as con otras cadenas, pueden ser clonadas, pueden convertirse en otros tipos y se puede iterar a travs de sus caracteres como si fuera una coleccin. El concepto de i mplementacin de interfaz mltiple tambin est disponible p ar a cualquier p ro gr a ma do r de C#. C# tambin permite derivar una clase de una clase base e implement ar interfaces al mismo tiempo.
class MyDerivedClass : CM yB aseClass, Interfacel, Interface2

Las clases deben implement ar cualqui er declaracin de evento, mtodo, p r o piedad o indizador encontrado en una interfaz que implcmenten. En caso c o nt r a rio. el compi lador de C# emitir un error. El siguiente codigo no funciona porque la clase M y C l a s s i m p l e me n t a I n t e r f a c e l per o no p r o p o r c i o n a una imp le me nt aci n del m t o d o M e t ho d 1 ( ) definido en Interfacel:
interface Interfacel

{
void M e t h o d 1();

}
class MyClass : Interfacel void M a i n ( )

{
public static

{ } } El compilador de C # emite el siguiente mensaje de error al compi lar el codigo:


error CS0535: 'MyClass' no implementa el miembro de interfaz 'Interfacel. Met ho d1()'

La clase debe propor ci onar una implementacin p ar a la interfaz Me thod 1 ( ) definida por Interfacel. dado que la clase implementa Interfacel. El siguiente ejemplo corrige el error:
mterface Interfacel

{
void M e t h o d 1();

}
class MyClass : Interfacel

{
public static void M a i n ( )

{ }
public void M e t h o d l ( )

{ } }

309

Cmo implementar mtodos de interfaz con el mismo nombre


Debido a que es posible que el nombre de un mtodo a p a re z ca en ms de una interfaz v como es posible que un a clase de C# implemente ms de una interfaz. puede o c u r ri r que se le pi da a u na clase de C# que p ro po r ci o ne mltiples i mplementaciones de diferentes interfaces que t engan el mi smo nombre. Observe el mt o do D o Wo r k ( ) en el siguiente cdigo:
interface Interfacel

{
v o i d D oW o r k () ;

}
interface Interface2

{
void DoWork( );

}
class MyClass : Interfacel, Interface2

{
v o id D o W o r k ( )

{ ) } Este cdigo no se puede compilar. El c ompi lador de C# emite el siguiente mensaje que indica el error que produce:
error CS0536: 'MyClass' no implementa el miembro de interfaz 'Interfacel.D o W o r k ( ) ' . M y C 1as s .D o W o r k ()' es esttico, no publico, o tiene un tipo de valor devuelto incorrecto, error CS0536: 'MyClass' no implementa el miembro de interfaz 'Interface2.DoWor k () ' . M y C 1as s .D o W o r k ()' es esttico, no publico, o tiene un tipo de valor devuelto incorrecto.

En los mensajes de error se muest ra la sintaxis i nterfaz/nombre p ar a recordar la sintaxis correcta de las implementaciones de clase. El p ro bl em a es que la clase M y C l a s s necesita p r o p o r c i o n a r cdigo de implementacin p ar a el mtodo D o Wo r k ( ) definido por I n t e r f a c e l y del m t od o Do Wo r k ( ) definido por I n t e r f a c e 2 y las dos interfaccs reutilizan el nombre de mtodo D o Wo r k ( ) . Una clase de C# no puede incluir dos mtodos con el mi smo nombre, de modo que cmo se pueden definir los dos mtodos de interfaz7 La solucin es ant eponer el nombre de la interfaz a la implementacin del mtodo v escribir un punto que separe el nombre de la interfaz del nombre de la implementacin. como se mu es tr a a continuacin:

310

class MyClass : Interfacel,

Interface2

{
void Inter fa ce l.D o W o r k ()

{ }
void Interface2.D o W o r k ( )

{ } } Esta clase se compi la cor rectament e ya que contiene dos implementaciones

DoWork (). una por cada interfaz definida. C omo los nombres de mtodo estn
calificados con los nombres de interfaz. el compilador de C# puede distinguir uno de otro y puede verificar que las dos interfaces han sido implement adas en la clase.

Cm o acceder a m iem bros de interfaz


T r a b a j a r con clases que implementan interfaces es sencillo en C#. N o r m a l mente se realizan estas operaciones cuando se t rab aj a con objetos cuy as clases implementan interfaces: Consult ar un objeto p ar a verificar que es compatible con una interfaz es pecifica. Acceder a una interfaz en un objeto. Acceder a un mi embro de la clase de un objeto definido inicialmente en una interfaz. Las prxi mas secciones estudian estas operaciones.

Consultar a un objeto por una interfaz


Dado que disea e implementa su propio cdigo, ya sabe qu clases se usan en su aplicacin y qu interfaces admiten. Sin embargo, cuando se escribe cdigo que puede ser empleado por otras aplicaciones N E T y se reciben objetos de otros cdigos, nunca se puede estar realmente seguro de qu interfaces admiten esos objetos. Por ejemplo, si est escribiendo un ens amb la do y escribe cdigo que a cept a un tipo de objeto genrico, no puede saber si el objeto admite una interfaz dada. Puede us ar la pal ab ra clave i s par a co mp ro ba r si un objeto admite o no una interfaz. La pal abra clave i s se emplea como una parte de una expresin booleana que se c onst ruye como se indica a continuacin:

311

Un identificador de objeto.

La palabra clave i s . Un identificador de interfaz. La expresin devuelve T r u e si el objeto admite la interfaz indicada y F a l s e en caso contrario El listado 13.1 muest ra el funcionamiento de la pa la br a clave is :
L istado 13.1. C mo usar la palabra clave is para trabajar con una interfaz
u sing System; public n te r f a c e P n n t () ; I P n n t M e s s age

(
v o id

};
class Class1 void Pnnt ) f r ora C 1 a s s 1 !" ) ;

{
p ub l i c

{
C ons o l e . W r i t e L m e ("Helio

} }
class Class2 void

: I P r m t M e s sage
Pnnt ( ) fr om C 1 a s s 2 !" ) ;

{
p ub l ic

(
C o n s o l . W n t e L m e ("Helio

} }
class MainClass stat i c v oid Main( )

{
public

(
PrintClassPrintObject

= new

PrintClass ( );

P r i n t O b j e c t . P r i n t M e s s a ge s () ;

1 (
class Pr i n t C l a s s void P r m t M e s s a g e s ()

{
pu b l i c

{
Class 1 Class2 Object'l 0 bj e ct 2

= new = new

Classl () ;
C l a s s 2();

PrintMessageFromObject(Objectl);

312

PrintMessageFromObject(Object2) ;

}
prvate void is PrintMessageFromObject (object IPrintMessage) PrintMessage; obj )

{
if(obj

{
IPrintMessage

P r m t M e s s a g e = (IPrintMessage) ob] ; PrintMessage.Print ( );

} } } El listado 13.1 define una interfaz llamada IPrintMessage. La interfaz IPrintMessage define un mtodo llamado Print. Al igual que todos los miembros de interfaz de C#. la interfaz IPrintMessage define mi embros pero no los implementa. A continuacin el listado implementa dos clases de control l lamadas C l a s s l y C l a s s 2 . La c l a s e C l a s s l implementa un mtodo llamado calied Print (). C om o Classl no hereda de la interfaz IPrintMessage. el mtodo Print ( ) implementado por la clase no tiene ninguna relacin con el mtodo Print ( ) definido por la interfaz IPrintMessage. La clase Classl implement a un mt odo l lamado Print ( ). C o m o Classl hereda de la interfaz IPrintMessage. el compi lador de C # c o n s i d e r a q ue el m t o d o P r i n t ( ) i m p l e m e n t a d o p o r la c l a s e es una implementacin del mtodo Print ( ) definido por la interfaz IPrintMessage. A continuacin el listado 1.^.1 define una clase llamada Ma^nClass. que i m p l e m e n t a el m t o d o M a i n ( ) de la a p l i c a c i n y o t r a c l a s e l l a m a d a PrintClass. El mtodo Main ( ) del listado 13.1 crea un objeto de la clase PrintClass y llama a su mtodo pblico para que haga el trabajo de verdad. El listado 13.1 termina declarando una clase llamada PrintClass. L a c l a s e PrintClass implementa un mtodo publ ico llamado PrintMessages ( ) y un mtodo de ayuda privado llamado PrintMessageFromObj ect (). El mtodo PrintMessages ( ) es el mtodo al que llama el mtodo Main ( ) . Como PrintMessageFromObj ect ( ) esta marc ad o como privado, solo se le puede l lamar desde otros fragment os de codigo del objeto PrintClass y no puede ser llamado desde el cdigo en otras clases. El mtodo PrintMessages ( ) crea un objeto de clase Classl y un objeto a partir de Classl y pasa cada objeto al mtodo privado PrintMessageFromObj ect ( ) . El mtodo p r iv a do PrintMessageFromObj ect ( ) acepta un parmet ro de tipo object como parametro.

NOTA: Es posible usar un parmetro de tipo obj ect gracias a que todos los tipos de variable que el CLR admite derivan en ltima instancia de

313

System.Object y la palabra clave de C# object es un alias para el tipo System.Object. Cualquier tipo de variable que pueda ser repre

sentada en C# puede ser usada como parmetro para un mtodo que espere un tipo de objeto porque todos los tipos son, en ltima instancia, objetos de System.O b j ect.
En la siguiente lnea del listado 13.1. el mtodo PrintMessageFromObject ( ) comienza exa mi na ndo el objeto p ar a c o mp r ob a r si implementa la interfaz IPrintMessage:
if(obj s IPrintMessage)

Si el o b j et o i m p l e m e n t a la i nt er fa z. la e x p r e s i n b o o l e a n a obj s IPrintMessage devuelve True y el codigo situado por debajo de la condi cin i f se ejecuta. Si el objeto no implementa la interfaz. la expresin booleana obj is IPrintMessage devuelve False y el cdigo situado por debajo de la condicin i f no se ejecuta. Si el objeto admite la interfaz. se puede acceder a la i mplemcntacin del objeto de la interfaz. Se puede acceder a la i mplemcntacin de la interfaz de un objeto declarando una variable del tipo de la interfaz y luego convirticndo expl ci tamen te el objeto al tipo de la interfaz. como se indica a continuacin:
IPrintMessage P r m t M e s s a g e ; P n n t M e s s a g e = (IPrintMessage) ob] ;

T ra s imcializar una variable del tipo de la interfaz. se puede acceder a los mi embros de la interfaz usando la habitual notacin con punto:
P n n t M e s s a g e . Print ( );

En el listado 13-2. se pa sa Objectl al mtodo PrintMessageFromOb j ect () y no se escribe nada en la consola porque el objeto Obj ect 1 es de la c l a s e C l a s s l y Classi no implementa la interfaz IPrintMessage. Cuando se pasa Objectl al mtodo PrintMessageFromOb j ect (). se escribe en la consol a el siguiente texto:
Helio from Class2!

Este mensaje aparece porque el objeto Ob ject2 es de clase Class2 y Class2 i mplementa la interfaz IPrintMessage. Si se llama a la i mplemcntacin del objeto del mtodo Print de la interfaz se escribe el siguiente mensaje en la consola.

Cmo acceder a una interfaz en un objeto


Usar el operador i s p ar a t ra ba j ar con una interfaz requiere que el cdigo ac ceda a un objeto dos veces:

314

Una vez p a r a consul tar al objeto y c o m p r ob a r si el objeto implementa una interfaz. Una vez p a r a acceder a la i mplementacin de la interfaz del objeto us ando el op er ad or de conversin explcita.

Se pueden c om bi nar estos dos accesos mediante el op er ad or as. El operador as realiza dos tarcas en una sola instruccin. El listado 13.2 es una versin modi fi cada del listado 13.1 que usa la instruccin as en lugar de la instruccin is:
L istado 13.2. C m o u s a r la p a l a b r a c l a v e as p a r a t r a b a j a r c o n u n a i n t e r f a z us m g public Sys t em; interface P r i n t (); IPrintMessage

{
void

};
class Classl void Print() from Classl!");

{
public

{
Console.WriteLine("Helio

class

Class 2 v o id

: IPrintMessage Print( ) from C l a s s 2 !");

{
public

{
C o n s o l e . W r i t e L i n e (" Hello

} }
class MainClass sta tic void M a i n ( ) = new P r i n t C l a s s ();

{
public

{
PrintClassPrintObject

Pr i n t O b j e c t . P r i n t M e s s a g e s ( );

} }
class Pri ntC l a s s v oi d PrintMessages( ) = n e w C l a s s l (); = n e w Class2();

{
pu b l i c

{
Classl Class2 Objectl O bje ct2

315

PrintMessa geFromObject (Objectl) ; P r m t M e s s a g e FromOb] e ct (Ob j e c 1 2 ) ;

}
prvate void Pr in tM es sageFromObject(object PrmtMessage; obj)

{
IPrmtMessage

P r m t M e s s a g e = obj as TP rm t M e s s a g e ; jf (P r m t M e s s a g e != nuil) Pr intMc-ssaq e .P r in t ) ;

t i oper ado r a s se usa como parte de una expresin que se construye como se indica a continuacin: Un identificado!' de objeto. La palabra clave a s . Un identificado!'de mterfaz. Si el ob| eto designado en la expresin implementa la interfaz designada en la expresin, la implementacion del objeto de la mt erfaz se devuelve como el resul tado de la expresin. Si el objeto designado en la expresin no implementa la mterfaz designada en la expresin, se asigna al resultado de la expresin un valor vaco representado por la pal abra clave de C# nuil. La nueva implementacin del mtodo pri vado Pr intMes sage FromOb j ect () usa el operador a s . De clara una variable local del tipo de la interfaz I Pr intMes sage v usa el op er a dor as para acceder a la implementacin del objeto del mtodo. Una vez que se ha compl et ado la operacion as. se c omprue ba la variable de implementacin de la interfaz par a d escubri r si tiene el valor nuil. Si la variable no es nuil, se sabe que el objeto propor ci onado implementa la interfaz v se puede llamar al mtodo de la interfaz. El listado 13 .2 es funcionalmente equivalente al listado 13.1 v escribe el si guiente texto en la consola:
Helio f rom C ]a s s 2 !

Declaraciones de interfaz y palabras clave de mbito


Al d e s i g n a r una int erfaz. se puede m a r c a r la i nt erfaz como public. protected. internal o private. Si decide usar una de estas palabras claves para pr opor ci onar un nivel de mbito par a la interfaz. debe colocarse i nmediatamente antes de la pal ab ra clave interface.

316

Las interfaces marc adas como p ub li c son visibles par a cualquier fr ag mento de cdigo que tenga acceso al cdigo en el que la definicin de la interfaz pueda resolverse en tiempo de ejecucin. Si se desarrolla un e n s ambl ado y se implementa una interfaz pblica en ese ensamblado, c u a l quier aplicacin de . NET que acceda al ensambl ado podra t raba jar con la interfaz. Las interfaces marc adas c o m o p r i vate solo son visibles para la clase en la que se definen. Solo las interfaces cuyas definiciones estn anidadas en clases pueden m ar car se como private. Las interfaces mareadas como protector] solo son visibles para las clases en la que son definidas o desde clases derivadas de la clase. Solo las interfaces cuyas definiciones estn ani dadas en clases pueden marcarse com o p r o t o c t e d . Las interfaces marcadas como i n t e r n a l son visibles para cualquier eodigo en el mismo archivo binario, pero no son visibles para el codigo que se encuentre en otros archiv os binarios Si se define una interfaz en ( # > se compila la clase for mando un ensamblado, cualqui er fr agmento de codigo del ens ambl ado puede acceder a las interfaces internas. No obstante, si otro fragmento de codigo usa ese ensamblado, no tendr acceso a la interfaz. C# permite especificar una interfaz sin especificar ninguna pal abr a clave de mbito. Si se declara una interfaz sin especificar ni nguna pal ab ra clav e de m b i to. por defecto se le concede a la interfaz accesibilidad publica.

Cmo implementar interfaces definidas por .NET Framework


N E T F ramework define v a n a s interfaces que se pueden implementar en otras clases. En este ca p tul o ya se ha menci ona do que N E T F r am ew o rk define interfaces, como las interfaces ICloneable. TEnumerable. ICompareab]e e IConvert ible que implementa la clase S y s t e m .String. Implementar interfaces definidas por N E T Framework puede a yu da r a las clases a integrarse en N E T Framework v en el entorno comn de ejecucin (el CLR. para a b r e viar). Observe este ejemplo.

Cmo implementar foreach mediante lEnumerable lEnumerator


El listado 9.3 del captulo 9. implementa una clase llamada Rainbow, que incluye un indizador que permite utilizar los contenidos de la clase (cadenas que

317

n om br an los colores del arco iris) como elementos de u na matriz, como se m u e s t ra en el siguiente ejemplo:
Rainbow MyRainbow = new Ra in bo w( ); for (Color Index = 0; Colorlndex < M y R a i n b o w .C o u n t ; ColorIndex + + )

{
string ColorName;

ColorName = M yR ai nb ow [Colorlndex]; S y s t e m . C on so l .W ri te Li ne (C ol or Na m e);

Se puede reducir an ms este cdigo usando la p a la br a clave f oreach con la clase, como se mues tra en el siguiente fragment o de cdigo:
Rambow MyRainbow = new R a m b o w ( ) ;

foreach ( s t n n g Color in MyRainbow) C o n s o l . W r i t e L i n e (C o l o r N a m e );

Por defecto, las clases no admiten la pal ab ra clave foreach y usarla para a cceder a los elementos de la clase hace que el c ompi lador de C# genere el si guiente mensaje de error:
error CS1579: La instruccin foreach no funciona en variables del tipo 'Rainbow' porgue 'GetEnumerator' no contiene una definicin para 'miembro' o es inaccesible

Sin embargo, se puede u s ar foreach en las clases si la clase implementa una interfaz de N E T Framework llamada IEnumerable. La interfaz IEnumerable contiene mtodos que N E T F ramework us a p ar a extraer elementos de los objetos. Si la clase contiene u na coleccin de elementos y se quiere que otras partes del cdigo usen la p a la br a clave foreach pa r a iterar c ada uno de los elementos de la coleccin, hay que implement ar la interfaz IEnumerable en la clase. La interfaz IEnumerable contiene una sola definicin de mtodo:
IEnumerator GetEnumerator ( );

El mt odo GetEnumerator ( ) debe implement arse en la clase y debe de v ol ve r un o bj et o que i m p l e m e n t a o t r a i n t e rf a z N E T F r a m e w o r k l l am ad a IEnumerator. La interfaz IEnumerator es la responsabl e de implementar el cdigo que devuelven los elementos de clase individuales. La interfaz IEnumerator define u na p ropi eda d y dos mtodos como sigue:

object Current bool void

{get;}

MoveNext( ); R e s e t ();

318

La propiedad Current devuelve una referencia al elemento actual de la coleccin. El mtodo MoveNext ( ) se mueve al siguiente elemento de la col ec cin y devuelve True si hay otro elemento a continuacin o False si se ha llegado al final de la coleccin y no hay otro elemento a continuacin. El mtodo Reset ( ) devuelve el integrador al principio de la coleccion. C uando se accede a los datos de una clase con el const ructor foreach. NET Framework accede a las interfaces de las clases IEnumerable e IEnumerator con cdigo c omo el del siguiente pseudo-codigo:
IEnumerable IEnumerableImplementation; IEnume rat or IEnume rat orImplement at ion; IEnumerablelmplementation = YourClass if (IEnumerabie Imp1ementat i on !- null) as Enumerable;

{
IEnumerator Implementation IEnume r a b 1e Im p 1ement at ion.Get Enume r at o r ( ); I f (IEnumeratorImplementat ion != null)

{
w h i l e (IEnumeratorlmplementation.G e t N e x t ( ) == true) CurrentValue = IE nu meratorImplementation.C u r r e n t ;

} } Las interfaces Enumerable e Enumerator estn definidas en un e s p a cio de nombre de N E T F ramework llamado System. Collections y hay que hacer referencia a ese espacio de nombre cuando se trabaja con estas interfaces Se puede hacer referencia a los nombres de espacio explcitamente:
class MyClass : S ystem.C o l l e c t i o n s .IEnume rabie, S ystem.C o l l e c t i o n s .IEnume r at o r

Si se quiere, se puede us ar en su lugar la pal abr a clave using para hacer referencia a los espacios de nombre.
using System. Collections ;

class MyClass : Enumerable, Enumerator

El listado 13.3 remodela el listado 9.3 y usa la clase Rainbow para implementar las interfaces Enumerable e Enumerator; tambin usa el constructor foreach del mtodo Main ( ) par a recorrer los elementos de la clase.
Listado 13.3. Cmo admitir foreach mediante Enumerable lEnum erato r using System; using System. Collections ;

319

ass Rainbow : IEnumerable, private public short

IEnumerator = -1;

Iterator Index

IEnumerator this;

GetEnumerator ()

{
return

}
public object Current

{
get

{
switch(Iteratorlndex)

{
case 0 : return return return case 3 : return
case
4 :

"R e d "; "Orange"; "Yellow"; "Green"; "Blu e" ; " Indigo"; "Violet"; ERROR * * *" ;

return

ca s e 5:
return

case

r:

return default : return

public

bool

M o v e N e x t )

{
11 e r a t o r I n d e + + ; if (Itera to r ln d ex -r eturn false; r e turn t r u e ; 7)

public

void

Reset)> = -1;

{
Iteratorlndex

}
public static void M a i n ( )

(
Rainbow MyRainbow = new R a i n b o w ( ) foreach(string ColorName in MyRainbow)

Consol . W n t e L m e (Colorame )

Si se ejecuta el cdigo del listado 13.3 se escribe el siguiente texto en la consola:


Red Orange Ye 11ow

Creen
Blue Indigo Vi o 1 e t

La c las e R a i n b o w i m p l e m e n t a las i n t c r f a c e s E n u m e r a b l e e IEnumerator. La clase mantiene un campo p r n a d o llamado IteratorIndex que se usa p ar a seguir el rastro del siguiente elemento que debe devolverse en el bucle foreach. Se inicial iza a -1: veremos por que cuando exami nemos la implement aci n deMoveNext ( ) en las siguientes paginas. La implementacin de clase de Enumerable .GetEnumerator () d e vuelve una referencia al objeto que se llama con la siguiente instruccin:
return this;

Recuerde que el mtodo debe devolver una referencia a una clase que implementc el mterfaz IEnumerator. Como el objeto usado para llamar a Enumerable. Get Enumerator ( ) tambi'n implementa la clase IEnumerator. se puede devolver el objeto al que se esta llamando. Se puede usar la p al ab ra clave this como v alor dev uelto. En este contexto, la pal ab ra clave this hace referencia al objeto cuyo codigo se este e jecutando en ese momento. Como el compi lador de C# puede det er minar en tiempo real que el objeto que se ejecuta en ese moment o implementa Enumerable, el codigo no necesita c o n v e r t i r e x p l c i t a m e n t e la p a l a b r a cl ave this a u na v a r i a b l e de tipo IEnumerator. El codigo resultante podra ser como el siguiente:
return this as IEnumerator;

Sin embargo, esto es redundante porque el compi lador de C# ya puede c o m probar que el objeto this (el objeto que se esta ej ecutando en ese momento) implementa la interfaz IEnumerator. Si se usa este codigo par a devolver una referencia IEnumerator. recibir el siguiente aviso del compi lador de C#:
warning CS0183: La expresin dada es siempre del tipo proporcionado ('System.Collections.I En umerator')

El resto de la c las e R a i n b o w i m p l e m e n t a m i e m b r o s de la i n t e r f a z Enumerator. El primer mi embro propor ci ona la implementacin par a la p r o piedad Enumerator .Current . Exami na el valor de la propiedad privada de

321

la clase Iteratorlndex y devuelve una cadena que representa el color del a r c o iris en el n d i c e al q u e h a c e r e f e r e n c i a el v a l o r de la p r o p i e d a d Iteratorlndex. La propiedad Current devuelve u na var ia bl e de tipo object. pero como las cadenas son objetos igual que todos los otros tipos de datos, el C L R acepta los valores devueltos basados en cadenas. La i mplementacin del mt odo IEnumerator .MoveNext () i ncrementa el valor de la propiedad pri vada Iteratorlndex. C omo el arco iris tiene siete colores. la implement aci n MoveNext ( ) da por sentado que los valores vlidos de Iteratorlndex van de 0 a 6. Si el valor llega a 7. la implementacin de MoveNext ( ) as ume que el iterador ha llegado a su lmite y devolver False. En c a so con tra ri o, la i mp le me nt ac i n devue lve True. La i ns trucci n que i n c r e m e n t a el v a lo r de I t e r a t o r l n d e x e xi ge que el v a l o r ini ci al de Iteratorlndex sea - I . C uando se llama a MoveNext ( ) por vez primera, la i nstruccin de incremento aument a el valor de Iteratorlndex de -1 a 0. dndole a Iteratorlndex un valor vlido en la pri mera iteracin del bucle. La i mplement aci n del mt odo IEnumerator .Reset ( ) s implemente res tablece el valor de Iteratorlndex a -1. A este mtodo se le llama si se llama a ms de un const ructor f oreach y N E T F r amew or k necesita devolver el est a do de la enumeraci n a su valor inicial. To d a esta implementacin hace que el mtodo Main ( ) sea muy claro. El mtodo puede crear un objeto de la clase Rainbow y us ar f oreach para iterar c a da nombre de color de la clase.

Cmo implementar limpieza mediante IDisposable


El C L R contiene un mecani smo p a r a la eliminacin aut omt i ca de objetos l lamada recoleccin de objetos no utilizados. Es import ant e co mprender cmo funciona este mecani smo, en qu se diferencia de otros sistemas y cmo hacer el cdigo C# lo ms compatible posible con este algoritmo p ar a eliminar objetos creados. En C ++, un objeto se crea con la pal ab ra clave new y la operaci n devuelve al objeto un puntero ya que se crea en el montn de memori a de la aplicacin. El p ro g ra ma do r en C + + debe liberar esta m emori a invocando al oper ado r delete sobre ese mi smo puntero cuando el objeto ya no sea necesario. Al invocar al o per ado r delete se libera la memori a u sad a por el objeto y se llama al destruc tor de la clase par a que la clase pueda realizar cualquier operacin de limpieza especfica de clase. Si no se invoca al operador delete sobre un puntero de objeto devuelto por new. se produce prdida de memoria. En al gunos entornos de ejecucin, como Visual Basic y C O M. se lleva la cuenta de las referencias de los objetos. Los entornos de ejecucin llevan la cuen ta de los s ubprocesos asociados a un objeto y libera aut omt icamente el objeto c uando su cont ador de referencias llega a cero. Esto permite al programador

322

olvidarse de tener que llamar a una instruccin de destruccin como delete y ayuda a eliminar toda un tipo de errores relacionados con la prdida de memoria. C L R usa un es quema de recuperaci n de memori a llamado recoleccin de objetos no utilizados. Los objetos no se destruyen cuando se libera su ltima referencia, como ocurre con los sistemas que cuentan las referencias, como C O M y COM+. En su lugar, los objetos se destruyen algo ms tarde, cuando el recolector de objetos no utilizados de C L R se ejecuta y destruye los objetos preparados para ser borrados. Los destructores de objetos de C# se ejecutan, no cuando se libera la ltima referencia del objeto, sino cuando el recolector de objetos no utilizados libera las estructuras de datos internas de C L R usadas para seguir la pista al objeto. Es i mportante tener en cuenta este diseo de recoleccin de objetos no utilizados al p ro gr a ma r las clases de C#. Las clases que gestionan recursos y necesitan ser explicitamente cerradas cuando se destruye el objeto, como los controladores de conexiones de bases de datos, deben cerrarse tan pronto como el objeto deje de usarse. Insertar cdigo de limpieza en el dest ructor de la clase significa que los recursos no sern liberados hast a que el recolector de objetos no utilizados dest ruya el objeto, que puede ser mucho despus de que se libere la ltima referencia al objeto. .NET F ramework admite una interfaz llamada IDisposable que las clases pueden implementar p ar a admitir recursos de limpieza de clases. La interfaz IDisposable se incluve en el espacio de nombre System de N E T Framework. Admite un solo mtodo llamado Dispose (). que no toma par met ros y no devuelve nada, como se mu es tra en el siguiente ejemplo:
using public System; class MyClass MyClass( ) : IDisposable

{
public

i }
'MyClass( )

{ }
public void D i s p o s e ( )

{ } } Esta clase admite un constructor, al que se llama cuando se crean los objetos de la clase; un destructor, al que se llama cuando el recolector de objetos no utilizados destruye los objetos de la clase; y Dispose (). al que se puede l lamar cuando el cdigo cliente se deshace del objeto. El cdigo cliente puede consul tar los objetos p ar a ver si son compatibles con la interfaz IDisposable y puede llamar a su mtodo Dispose ( ) par a libe

323

rar recursos de clase antes de que el recolector de objetos no utilizados destruya el objeto. El lenguaje C# realiza esta consulta de for ma sencilla mediante una sintaxis especial que incluye la p a l ab r a clave using. La pal abra clave using puede usarse en una expresin con parntesis que incluye la creacin de un n u e vo objeto:
using(MyClass MyObj ect = new MyClass ( ))

{
// use agu "MyObject"

} En este ejemplo, la p al ab ra clave using se usa par a crear un nuevo objeto ll amado MyObj ect. El nuevo objeto pertenece a la clase MyObj ect. El objeto puede usarse en cualquier instruccin que est incluida entre las llaves que si guen a la pal abr a clave using. El objeto es a ut omt icame nte destruido cuando la ruta de acceso del cdigo llega a la llave de cierre del bloque using. Si la clase del objeto creado en la instruccin using admite IDisposable. ent on ces el mt odo Dispose ( ) de la clase es i nvocado aut omt i came nt e sin que el cliente deba hacer nada. El listado 13.4 mues tra una clase llamada MyClass que i mplementa la interfaz IDisposable.
Listado 13.4. IDisposable y la palabra clave using using public System; class MyClass MyClass( ) : IDisposable

{
public

i
Consol. W r i t e L m e ("constructor") ;

)
~ M y C 1a s s ( )

{
Consol.WriteLine("destructor");

}
public void Dispose( ) of

{
Consol.WriteLine ("impiement a1 1 on I D i s p o s a b l e .D i s p o s e ()");

} )
public class MamClass

{
static void M a i n ( ) = new MyClass ())

{
using (MyClass MyObject

324

Esta aplicacin de consola i mplementa la clase MyClass mo s tr ad a en el lis tado 13.4 v contiene instrucciones en su constructor, destructor e implementacin Dispose ( ) que escriben mensajes en la consola. El listado 13.4 tambin inclu ye una instruccin using en su mtodo Main ( ) que crea un objeto de tipo MyClass. Si se ejecuta el listado 13.4 se escribe el siguiente mensaje en la consola:
constructor implementation dest ructor of IDispo sa bl e.D i s p o s e ( )

Obs er ve que la i mplementacin Dispose ( ) de la mterfaz IDisposable es invocada a ut om t i ca me n te sin que el mtodo Main ( ) intervenga. Ten ga en cuenta que slo debe implement ar la interfaz IDisposable para las clases que tienen recursos que deben ser liberados explicitamente. como c o nexiones de bases de datos o indicadores de ventana. Si la clase slo contiene referencias a objetos gestionados por el CLR. entonces no es necesario implementar IDisposable. Implementar IDisposable significa que el C L R necesita realizar ms trabajo p ar a eliminar los objetos y este t rabajo adicional puede ralentizar el p roces o de recoleccin de elementos no utilizados. Implemente IDi sposable cuando sea necesario pero no lo haga a menos que sea necesario.

Resumen
Piense en una interfaz como en una promesa de que una clase implementar los mtodos, propiedades, indizadores y eventos definidos en la interfaz. Las interfaces p r o p o r c i o n a n d e f i n i c i o n e s de m i e m b r o s , p e r o no p r o p o r c i o n a n n i n g u n a implementacin. Se necesita una clase que implemente una interfaz p ar a p r o p o r cionar una i mplementacin de cada uno de los miembros de la interfaz. Una clase puede implementar varias interfaces. aunque slo puede derivarse de una de las clases base. Las interfaces pueden derivarse de otras interfaces. del mismo modo que las clases pueden derivarse de las clases base. Las pal abr as clave de C# is vas pueden usarse par a t raba jar con objetos que implementen interfaces. La p al ab r a clave i s se usa en una expresin booleana que devuelve True si un objeto implementa una interfaz y False en caso con trario. La pal abr a clave as convierte una variable de objeto en una variable de un tipo de interfaz. Las expresiones que usan la pal abr a clave as devuelven nuil si el objeto no implementa la interfaz designada. En este captulo se ve un ejemplo sobre cmo implementar una interfaz defini da por N E T Framework. N E T Framework implementa muchas interfaces y es

325

aconsejable revisar la documentacin y estudiarlas todas. Las interfaces de N E T F ramework comienzan con la l et ra /. Revselas todas. Puede usar las interfaces de N E T F ramework p ar a implementar cualquier cosa, desde dar formato per sonal i zado a la consola p ar a mecani zar la hast a la s emnt ica de eliminacin de la reco leccin de elementos no utilizados.

326

14 Enumeraciones

Algunas de las variables definidas en el cdigo pueden usarse par a contener un valor tomado de un conjunto de valores posibles. Por ejemplo, puede necesitar seguir el rastro del estado de un archivo. Podra definir una variable que pudiera describir si un archivo est abierto, cerrado o si no se puedo encontrar. Un modo de lograrlo sera escoger algunas constantes par a definir las distintas opciones y un entero p a r a que contenga el valor actual, como en el siguiente cdigo:
const int FileOpen - 1; const int FileClosed = 2; const int FiieNotFound = 3; int Fi leStatus; - FileClosed;

FileStatus

Este cdigo es cdigo C# vlido y se compi lar perfectamente. Sin embargo, un p rog ra ma do r puede asi gnar a la variable un valor que no est disponible en el conjunto de constantes definidas. El tipo de datos de F i l e S t a t u s es un n m e ro entero y el compi lador de C# ac ept a perfectamente cualquier cdigo que a s ig ne a la variable cualqui er valor entero vlido, aunque el objetivo es restringir el conjunto de valores vlidos al conjunto definido por las constantes. En teora, asignar a F i l e S t a t u s un valor no definido por las constantes no debera estar

329

permitido porque lo que se pretenda en un principio era restringir el conjunto de valores posibles al conjunto definido p a r a esa variable. La situacin de desarrollo ideal en casos como ste es que debera ser posible definir una variable y as oc ia r el valor a un conjunto de posibles valores v lidos. Adems, el compi lador de C# debera ser c ap az de evitar que los progr amadore s asignen a la variable un valor no definido del conjunto de valores posibles. Como resultado, C # admite un cons tructor llamado enumeraci n que se ocupa de este caso concreto. Las enum era cio nes son un gru p o de constantes definidas con un nombre c o mn. El nombre de la enumeracin puede usarse como un tipo de variable una vez que se h ay a definido la enumeracin. Cua nd o se us a una variable definida como un tipo de enumeracin, el compi lador de C# se a se g ur a de que los valores a si g nados a las variables del tipo de la enumeraci n concuerden con uno de los val o res del conjunto de constantes definidas en la definicin de la enumeracin. Las enumeraciones son ideales par a las situaciones en las que una variable debe asociarse a un conjunto de valores especfico. S upongamos , por ejemplo, que est escribiendo una clase de C# que controla una puer ta electrnica y decide escribir una propiedad par a la clase llamada DoorState. que abre o cierra la puerta:
public int DoorState

{ set {
InternalDoorState = valu;

} } Tamb in puede definir algunas constantes que se pueden u sar p ar a hacer el cdigo ms legible:
public public const const int DoorStateOpen = 1; int DoorStateClosed 2;

La propi edad y las constantes permiten que el cdigo que t rabaj a con los objetos de la clase p ued a escri bir cdigo legible como el siguiente:
DoorStateOb]ect = new DoorClass ( ); D o o r O b j e c t .DoorState D o o r O b ] e c t .DoorState = = DoorClass.DoorStateOpen; DoorClass.DoorStateClosed;

El cdigo anterior se compila y ejecuta sin problemas. Sin embargo, la propie dad DoorState se define como un int y no hay n ada que impida a los i nvocadores u s ar valores que no tienen sentido y as ignar los a la propiedad

DoorState:
Do or O b j e c t .DoorState = 12 3 45;

330

Este cdigo t ambi n es vlido porque el literal 12 3 4 5 est dentro de los lmi tes vlidos de un entero de C# y la propi edad DoorState est definida como poseedora de un tipo int. Aun qu e este cdigo es vlido desde el punt o de vista de la c ompi laci n de C#. no tiene sentido en el nivel de clase porque el estado de la puerta en realidad slo debera ser abierta o cerrada. Podra crear algn cdigo par a la verificacin de errores en la propiedad DoorState p ar a que slo acepte valores vlidos, pero sera incluso mejor hacer que el compi lador de C# i mponga la restriccin por nosotros cuando se crea el cdigo. Las enumeraciones prop or ci on an el mecani smo en tiempo de compilacin que est buscando. Le permiten ag r up ar las constantes relacionadas, como las c ons tantes DoorStateOpen y DoorStateClosed. bajo un nombre de grup o y usar ese nombre de gru po como un tipo de valor. Puede, por ejemplo, a gr u p a r las constantes Door StateOpen v Door Sta teClosed en una enumer aci n lla mada LegalDoorStates y redefnir la propi edad DoorState p ar a que t ra bajen con un tipo de LegalDoorStates. en lugar de con un int. El compilador de C # puede entonces a se gurar que los valores asignados a la propiedad son miembros de la enumeraci n y p roducir un error si el valor no existe en la e nu meracin.

Cmo declarar una enumeracin


Puede declarar una enumeraci n en C# usando la siguiente sintaxis: La palabra clave enum. Un identificador de enumeracin. Un tipo base opcional. Identificadores de valor de enumeraci n s eparados por comas y entre lla ves. La e numeracin LegalDoorStates de la anterior seccin se definira como se indica a continuacin:
enum LegalDoorStates

{
DoorStateOpen, DoorStateClosed

} C ad a uno de los mi embros de las enumeraci ones tiene un valor numrico a s o ciado. Por defecto, el valor numrico del pri mer valor es cero y el valor de cada uno de los otros miembros es una unidad mayor que el valor de la anterior en ume racin. Si se usan estas reglas y la enumeracin definida anteriormente, el valor

331

por defecto de DoorStateOpen es 0 y el valor de DoorStateClosed es 1. Si lo desea, puede invalidar estos valores asignando valores a los miembros cuan do se definen us ando el op er ad or de asignacin:
enum LegalDoorStates

{
DoorStateOpen = 10 0, DoorStateClosed = 150

} Puede asi gnar los miembros a un valor literal o al resultado de una expresin constante:
enum LegalDoorStates

(
DoorStateOpen = (75 + 25), DoorStateClosed = 150

} Si no se asi gna un valor a un miembro concreto de la enumeracin, se aplican las reglas de asignacin de valor por defecto. Observe la siguiente e nu m e r a cin:
enum LegalDoorStates

{
DoorStateOpen = 10 0, DoorStateClosed

} Usando esta enumeraci n y las reglas de asignacin de valor por defecto, el val or de Door StateOpen es 100 y el valor de DoorStateClosed es 101. C# tambin permite el uso de un identificador de enumeraci n p ar a as ignar un valor a otro identificador:
enum LegalDoorStates

{
DoorStateOpen = 100, DoorStateClosed, LastState = DoorStateClosed

} En este ejemplo, el valor de la enumer aci n LastState es igual al valor de la enumeracin DoorStateClosed. que en este caso es igual a 101. Esto demu es tra que dos identificadorcs en una enumer aci n tienen el mi smo valor. Las enumeraciones corresponden a un tipo de valor particular. Este tipo co rrespondiente recibe el nombre de tipo subyacente de la enumeracin. Las enume raciones pueden ser convertidas explcitamente a su tipo subyacente. Por defecto, el tipo s ubyacente de todas las enumeraciones es int. Si quiere usar un tipo suby acente diferente, especifique el tipo s ubyacent e despus de dos puntos que siguen al identificador de la enumeracin:

332

enum LegalDoorStates

: short

{
DoorStateOpen = 100, DoorStateClosed

} Todas las asignaciones explcitas de valor deben usar valores que incluidos dentro de los lmites vlidos del tipo suby acente de la enumeracin. Obs er ve el error en la siguiente enumeracin:
enum Weather : uint

{
Sunny = -1, Cloudy = - 2, Rain = - 3, Snow = -4

} Esta declaracin de enumeraci n es un error porque el tipo subyacent e es u i n t y las asignaciones usan valores negativos que estn fuera de los valores legales de un u i n t . Si se compila la anterior enumeracin, el compi lador de C# emite los siguientes errores:
error C S 0 0 3 1 : 'u i n t ' error CS 0 0 3 1 : 'uint' error C S O 031 : 'uint ' error C S 0 0 3 1 : 'uint ' El valor El valor El valor El valor const ante constante constante constante '- 1 ' no s e puede '- 2 ' no s e puede '-3' no s e puede convertir convertir a a

convert i r a conve rtir a

'- 4 ' no s e puede

Cmo usar una enumeracin


Tra s haber definido la enumeracin, se puede usar el identificador de e nu m e r a ci n c o mo un t ipo de v ar i a b l e . El l i st ad o 14.1 m u e s t r a c mo la cl as e DoorController puede usar una enumeracin.
Listado 14.1. Cmo usar una enumeracin public enum LegalDoorStates

{
DoorStateOpen, DoorStateClosed

)
class DoorController LegalDoorStates Curr en tS ta te ;

{
prvate

333

public

LegalDoorStates

State

{
ge t

{
return CurrentState;

} set {
CurrentState = valu;

} } }
class MamClass static void M a i n ( ) Door;

{
public

{
DoorContro11er Door = new D oo rC o n t r o l l e r ( ); = LegalDoo rS ta te s.DoorStateOpen ;

Door.State

} } La enumeracin LegalDoorStates est definida fuera de una d ec la ra cin de clase Esto est permitido en C# y hace que la enumeracin sea visible p ar a todas las clases del archivo fuente. Una alternativa es definir las e nu mer a ciones dentro de una declaracin de clase usan do p a l a br a s clave de mbito (public. protected. internal o private) par a especificar el modo en que la enumeracin es visible p a r a las otras clases. Tr as definir la enumeracin LegalDoorStates. se puede usar su nombre como un tipo de variable. Se usa como tipo para el campo privado Currentstate de la clase DoorController y tambin como tipo de la propiedad publica State de la mi sma clase. Para referirse a una enumeraci n del cdigo se usan el nombre de la e n u me r a cin v uno de los identificadorcs de la enumeracin. Estos identificadores estn s eparados por un punto, como se muest ra en la siguiente instruccin:
Door.State = Lega lD oo rS ta te s.DoorStateOpen;

El valor de la expresin LegalDoorStates .Door StateOpen es igual al valor del identificador Door StateOpen de la enumeracin LegalDoor States. Este valor se asigna a la propiedad State. La ventaja de este diseo basado en enumeraciones es que el compilador puede identificar los lugares donde el cdigo intenta as ignar a la propiedad State un valor diferente del valor pr o cedente de la enumeracin. Observe el error en la siguiente instruccin:
Door.State = 1234 5;

334

El anterior cdigo es un error porque la propiedad State est definida como si tomase un valor de tipo LegalDoorStates y en su lugar se le asigna un v al or entero. El cdigo del an ter i or ej empl o p ro du c e el s iguiente e r ro r del compi lador de C#:
error CS0029: No se puede 'in t ' a 'LegalDoorStates' convertir implcitamente el tipo

Cmo usar operadores en valores de enumeracin


Debido a que los valores enumer ados tienen un tipo s ubyacent e y un valor, lo logico es que escriba un cdigo que trate con valores subyacentes. Puede usar v arios operadores de C# con valores enumerados: igualdad desigualdad menor que m ay or que menor o igual que m ay or o igual que suma resta AND OR exclusivo O R inclusivo compl ement o bit a bit incremento decremento Por ejemplo, observe el listado 14.2.
Listad o 14.2. Cmo usar operadores con enumeraciones using public System; enum FileAttnbutes

335

AttrNone = 0, AttrReadOnly = 1, AttrHidden = 2, AttrReadyForArchive

= 4

}
c 1 a s s M a i n C 1ass

{
pubJic static void M a m () FileAttr; |

{
FileAttributes

FileAt.tr = F 1 eAttributes .AttrReadOnly FileAttribut.es .AttrHidden; Consol . W n t e L n e (Fi leAttr) ;

} } El cdigo del listado 14.2 define un conjunto de valores enumerados que es pe cifican atributos para un archivo o un disco. Un archivo puede no tener atributos e s p e c i a l e s ( F i l e t t r i b u t e s .AttrNone). a t r i b u t o s de solo l ect ur a (FileAttr ibutes .AttrReadOnly). at ri but os ocultos (FileAttributes .H idden) o atributos listos par a ser archivados ( FileAttr ibutes .

AttrReadyForArchive). El codigo del mtodo Main ( ) especifica una variable local llamada FileAttr. que es de tipo Fi leAttributes.
El cdigo asigna el valor a un archivo oculto de solo lectura mediante una operacin OR sobre los atributos FileAttributes .AttrReadOnly v FileAt tribu tes.Hidden. El valor de la variable local se escribe a conti nuacin en la consola. Si se compila y ejecuta el listado 14.2 se escribe lo siguien te en la consola:

El listado 14.2 p ro du c e el v al or 3 p o r q u e el v a lo r de la e n u m e r a c i n FileAttr ibutes .AttrReadOnly. 1 . se uni al valor de la enumeracin FileAttr ibutes .Hidden. 2 . en una operacin OR. Realizar una operacion bool eana OR con los v alores 1 y 2 produce un resultado de 3 . Tambi n puede convertir un valor enumer ado a un valor con el tipo del tipo s ubyacente de la enumeracin:
enum IntEnum

{
EnumOne = 1 , EnumTwo, EnumTh r e e

}
IntEnum In t E nu mV al e ; int IntVa1u e ;

336

IntEnumValue = EnumTwo; IntValue = (int) IntEnumValue;

// el valor es 2

El c di g o a n t e r i o r c on v i e r t e el v a l o r de u n a v a r i a b l e de e n u m e r a c i n IntEnumValue a su equivalente entero y asigna el entero IntValue a ese valor. Como la variable IntValue es un entero estndar, se le puede asignar cualquier valor vlido par a un entero. No esta limitado al conjunto de valores definidos por la enumeracin, aunque se le asigna un valor que procede de una variable enumerada.

Cmo usar la clase .NET System.Enum


El tipo enum de C# es en realidad un alias de la clase System. Enum defi nida en N E T Framevvork. Podemos us ar cualquiera de los mi embros de la clase NE T System. Enum en las enumer aci ones que definamos.

Cmo recuperar nombres de enumeracin


El listado 14.3 muest ra cmo el cdigo puede t raba jar con enumeraciones como objetos System. Enum. Se trata de una mejora del listado 14.1 que recu pera el estado actual de la puerta y escribe el nombre del estado en la consola.
Listado 14.3. Cmo recuperar una nombre de enumeracin mediante GetName() u s m g System; public enum LegalDoorStates

{
DoorStateOpen, DoorStateClosed

}
class DoorController LegalDoorStates LegalDoorStates Cur re nt St at e; State

{
prvate public

{
ge t

{
return CurrentState;

} set {
CurrentState = valu;

337

class M a m C l a s s

{
public static void Main ( )

{
DoorController Door; string E n u m N a m e ; Door = new D oo rC o n t r o l l e r ();

Door.State = Lega lD oo rS ta te s.DoorStateOpen; EnumName = Lega lD oo rS ta te s.G e t N a m e (typeof (LegalDoorStates), Do or .S ta te ); C o n s o l . W r i t e L i n e (E n u m N a m e );

} } El mtodo Main ( ) del listado 14.3 usa el mtodo GetName ( ) de la clase System. Enum par a obtener una cadena que represente un valor de e n um er a cin El pri mer p ar amet ro es un objeto Type que especifica la enumeracin a la que se consulta. La expresin typeof ( LegalDoor States ) devuelve un objeto N E T T y p e p a r a el t i p o e s p e c i f i c a d o (en e s t e c a s o , la e n u m e r a c i n LegalDoorStates). El segundo p ar m et ro es el valor de la enumeracin a c tual. de la que debe devolverse la representacin de su cadena. La siguiente ins truccin muest ra cmo puede usarse el mtodo GetName ( ) p ar a obtener el nombre de un valor enumerado:
EnumName = LegalDo or St at es .G et Na me (type of(LegalDoorStates) , Door.State) ;

Esta instruccin se interpreta como: "Devuelve una cadena que represente el nombre del valor de la propiedad Door. State. Este valor es una parte de la enumer aci n LegalDoorStates." Si se ejecuta el listado 14.3 se escribe lo siguiente en la consola:
DoorStateOpen

T am bi n se puede u sar el mtodo Format ( ) par a recuper ar el nombre de un valor de enumeracin, segn su valor numrico. La llamada GetName ( ) del listado 14.3 puede reemplazarse por la siguiente llamada a Format ( ) :
EnumName = Lega1DoorStates.F o r m a t (t y p e o f (LegalDoorStates), 0, "g");

El primer p ar met ro de Format ( ) es el mismo que el pri mer p ar m et ro de GetNames (). que es el tipo de enumeracin que se usa en la llamada. El s egun do p ar me tr o de Format ( ) es el valor numri co que debe devolver la llamada. El ultimo par met ro de Format ( ) es la cadena que especifica los contenidos de la cadena que debe devolver la llamada. La cadena de formato puede ser una de las siguientes:

g. que especifica que debe devolverse el valor de enumer aci n con el valor numri co que concuerde con el valor del segundo parmetro.

338

x, que especifica que el val or del segundo p ar me tr o debe devolverse como una cadena que represente el valor en notacin hexadecimal
d. que especifica que el valor del segundo p ar me tr o debe devolverse

como una cadena que represente el valor en notacin hexadecimal


f . que especifica que el valor debe ser trat ado como un conjunto de val o

res enumer ados combi nados y que el mtodo debe devolver una lista de valores delimitada por comas como una cadena El valor de formato f se cre par a ser usado con enumeraciones que repre sentan valores de bit. Observe la siguiente enumeracin:
public enum BitsToSet

{
BitOSet BitlSet Bit2Set Bit 3 S e t B 1 1 4S e t B i1 5 S e t Bit 6Set B 1 1 7 S et = = = = = = = = 1, 2, 4, 8, 16, 32, 6 4, 128

} La enumeracin anterior representa un conjunto de bits que pueden asignarse a un byte. Se pueden asignar varios bits a una v ariable mediante el operador booleano OR. como en el siguiente ejemplo:
BitsToSet Byte; Byte = BitsToSet.BitlSet I BitsToSet.Bit 3 Set | Bi t s T o S e t .B it S et ;

Ll amar al mtodo Format ( ) en la variable Byte con el par amet ro de f or mato f devuelve una cadena que represent a los nombres de los valores e nu m e r a dos cuvos v alores se encuentran en la variable:
BitlSet, B i t 3 S e t , Bit 6Set

Cmo comparar valores de enumeracin


El mtodo CompareTo ( ) de la clase System. Enum puede c om par ar una enumeracin con otra v devolver un entero que describe la relacin entre los dos v alores. Observe el listado 14.4. que comp ar a el v alor de una v ariable enumerada con el valor det erminado de la mi sma enumeracin.
Listado 14.4. Cmo comparar valores de enumeracin con CompareTo() us m g public Sys t em; class MainClass

339

public enum Color

{
Red = 0, Or a n g e , Yellow, Green, Blue , Indigo, Violet

static

void M a i n ( ) MyColor;

{
Color

MyColor = Color.Green; C o n s o l e . W r i t e L m e (" {0} ' Console.WriteLine (" {0} ' C o n s o l e . W r i t e L m e (" {0} '

M y C o l o r .Co m p a r e T o ( C o l o r .R e d ) ); M y C o l o r .Compar eTo(Color.Green) ) ; M y C o l o r .C o mp ar eT o( Co lor.Violet))

El listado 14.4 declara una clase con una enumeracin pblica llamada Co lor. Sus valores varan de 0 a 6. El mtodo Main ( ) declara una variable de tipo Color llamada MyColor y asigna el valor Green a la variable. A conti n uacin invoca a CompareTo ( ) par a c om pa r ar el valor de la variable con otros valores de la enumeracin. El mtodo CompareTo ( ) dev uelve uno de estos tres v alores: -1 si el valor que se pas a como argument o a CompareTo ( ) tiene un valor superior al valor enumerado usado p ar a invocar al mtodo 1 si el valor que se p a sa como a rgument o a CompareTo ( ) tiene un valor inferior al valor e numer ado usado par a invocar al mtodo 0 si los dos valores son iguales En el listado 14.4. se llama tres veces al mtodo CompareTo (). En la prime ra llamada, la variable MyColor se c omp ar a con el valor Red. Como Green. que tiene el valor 3. tiene un valor super ior a Red. que tiene el valor 0 . CompareTo ( ) devuelve 1. En la segunda llamada, la variable MyColor se co mpar a con el valor Green. Como los valores son iguales. CompareTo ( ) dev uelv e 0. En la ultima llamada, la variable MyColor se co mpar a con el valor Violet. C o mo Green. que tiene el valor 3 . tiene un valor inferior a Violet. que tiene un valor 6 . CompareTo () devuelve -1. El ar gume nt o usado en la llamada a CompareTo ( ) debe ser del mismo tipo que la enumeracin usada p ar a llamar al mtodo. Usar cualquier otro tipo, inclu so el tipo subyacente de la enumeracin, produce un error en tiempo de ejecucin

340

Cmo descubrir el tipo subyacente en tiempo de ejecucin


De sc ub ri r el tipo subyacent e de una enumer aci n en tiempo de ejecucin es sencillo con el mt odo GetUnder lyingType (). Este mtodo, al que se llama en el tipo de enumeracin, en lugar de una variable del tipo, t oma un p ar met ro Type que represent a el tipo de la enumer aci n y devuelve otro objeto Type que representa el tipo s ubyacent e de la enumeracin. El mtodo ToString ( ) puede ser llamado en el objeto Type devuelto par a obtener un nombre legible p a r a el tipo, como se mu es tra en el siguiente cdigo:
s t n n g FormatSt r i n g ; Type U n d e r l y i n g T y p e ; UnderlyingType = B i t s T o S e t .GetUnderlyingType (typeof (BitsToSet) ) ; Co n s o l . W r i t e L i n e ( U n d e r l y i n g T y p e .ToString () ) ;

Este cdigo r e c u pe r a el tipo s u b y ac e nt e p a r a una e nu me r a c i n l lamada

BitsToSet y escribe el nombre del tipo en la consola, que produce una cadena
como la siguiente:
System.Int 3 2

Cmo recuperar todos los valores de enumeracin


El mtodo GetValues ( ) devuelve una mat ri z de todos los valores de e n u meracin ordenados en orden ascendente segn su valor numrico, como se puede ver en el siguiente cdigo:
Array ValueArray;

ValueArray = C o l o r .GetValues (typeof (Color) ) ; foreach (Color Colorltem m ValueArray) C o n s o l . W r i t e L i n e ( C o l o r l t e m . T o S t r i n g ());

Este cdigo llama a GetValues ( ) en la enumer aci n Color definida con anterioridad. El mt odo GetValues ( ) devuelve una matriz y se v isita a los elementos de la matriz de uno en uno mediante la p al abr a clave f oreach. El nombre de cada elemento de la matriz se escribe en la consola, como se puede ver a co nt i nu a cin:
Red Orange

341

Ye11ow Gr e en B le Indigo Vi o 1et

Anlisis de cadenas para recuperar valores de enumeracin


La clase Enum contiene un mtodo de anlisis de cadenas llamado Parse (). que acept a un a cadena como ent rada de datos y devuelve el valor de la e nu m e r a cin cuyo nombre concuerda con la cadena pr opor ci onada, como se puede ver en el siguiente ejemplo:
C o l o r .Parse (typeof (Color) , "Blue") ;

Esta llamada devuelve un objeto que representa el valor enumer ado llamado

Blue en una enumeracin llamada Color C omo muchos otros mtodos de enumeraci n, el mtodo Parse ( ) es llamado en el tipo, en lugar de una variable
del tipo. El mt odo Parse ( ) devuelve un objeto, que necesita ser convertido expl ci t ament e en un valor del tipo apropiado. El siguiente ejemplo muest ra cmo el m t o do Parse ( ) pude ser usado como uno de los muchos modos de representar un v alor enumerado:
Color ColorValue; object ParsedObject; ParsedObject - Col o r .Parse (typeof (C o l o r ) , "Blue"); Consol . W n t e L m e (Pars edOb j e ct .Ge t Type () . T o S t n n g ( ) ); ColorValue - (Color)ParsedOb]ect; Consol. W n t e L m e (ColorValue. ToS t r i ng () ) ; Con s o l . W n t e L m e (Color. Format (t ype of (Color) , ColorValue,

"d " ) ! ;

En este codigo. se llama a Parse ( ) en el tipo de enu mer aci n Color y se le otorga una cadena de ent rada Blue. Esta llamada dev uelv e un objeto y el codigo escribe el tipo del objeto en la consola. El objeto se conv ierte entonces explcitamente en una variable del tipo Color y se escribe en la consola el nombre del valor de la enumeraci n y el valor deci mal:
MainClass+Color B Le

4 Este resultado d emues tra que el objeto devuelto por el mtodo Parse ( ) es del tipo Color. La variable convertida, que es una variable de Color, tiene un nombre de cadena Blue v un valor decimal 4 .

342

Resumen
Las enumeraciones se emplean par a a g r u pa r un conjunto de constantes rela cionadas. Al dar a sus enumeraciones un nombre, se puede us ar ese nombre en el cdigo como un tipo de variable una vez que se haya definido la enumeracin. Las enumeraciones, por defecto, se basan en un conjunto de constantes i n t . Se puede invalidar este valor por defecto especificando un tipo s ubyacente p ar a la e n um e racin. Se pueden us ar como tipo suby acente de una enumer aci n muchos de los tipos numricos de C#. Se deben emplear enumeraciones cuando queramos que el compi lador de C# garant ice que las constantes con las que t rab aj amos en el codigo proceden de un conjunto de valores vlidos. Por defecto, el compilador de C # asigna valores numricos a los identificadores de las enumeraciones. El primer identificador tiene el valor de cero y las otras enumeraciones aument an su valor a partir de ah. Si lo deseamos, se puede u sar el operador de asignacin p ar a as ignar un valor a un identificador de enumeracin cuando se define la enumeracin. Un valor en una enumeracin se especifica escribiendo el nombre de la e num e racin. un p u nt o y el n o m b r e de los i d en ti fi cad or es de e nu m e r a c i n . Los identificadores de enumer aci n pueden convertirse implcitamente al tipo suby a cente de la enumeracin. Esta conversin implcita tambin permite el uso de algunos de los operadores de C# p ar a t ra ba j ar con los valores de enumeracin. Todas las enumeracin de C# derivan de una clase base de N E T llamada Sy s t e m .Enum. La clase S y s t e m .Enum contiene al gunos mtodos tiles que pueden a y u da r a obtener las mxi mas prestaciones de las enumeraciones. Este captulo ha exa mi na do la may or a de estos mtodos.

343

m 15 Eventos y delegados

En el flujo general del tpieo segmento de software orientado a objetos, un fragmento de codigo crea un objeto de una clase y llama a mtodos de ese objeto. En este contexto, el mvocador es el codigo activo porque es el codigo el que llama a los mtodos. El objeto es pasiv o, en el sentido de que espera y realiza una accin solo cuando se invoca a uno de sus mtodos. Sin embargo, tambin se puede producir el contexto contrario. Un objeto p u e de realizar una tarea y avi sar al inv ocador cuando ocurre algo durante el proceso A este algo se le llama un evento y la publicacin de ese ev ento del objeto se le conoce como d esen cadenar un evento. El proceso activado por eventos, en el que fragmentos de codigo informan a otras piezas de codigo c uando se producen eventos relevantes, no es una novedad de N E T La capa de mterfaz de usuario de Windows siempre ha usado una forma de ev entos para i nformar a las aplicaciones Window s cuando los usuarios t r a b a jan con el ratn, presionan una tecla en el teclado o mueven una ventana Los controles ActiveX desencadenan eventos par a los contenedores de control de ActiveX cuando el usuario realiza una accin que afecta al control. El lenguaje C# contiene pal abr as clave especiales que hacen que sea fcil desencadenar, publ icar y proces ar eventos en el cdigo de C'#. Se pueden usar estas pal abr as clave para permitir que las clases de C# desencadenen y procesen eventos con el mnimo esfuerzo.

345

Cmo definir delegados


Cua nd o se p rog r am an los eventos que desencadenan las clases de C#. es necesario decidir cmo recibe el evento otros fragment os de cdigo. Otros f r ag mentos de cdigo necesitan escribir un mtodo que reciba y procese los eventos que se publican. Suponga, por ejemplo, que su clase implementa un servidor Web y quiere des encade nar un evento siempre que llega una solicitud de una pgina desde Internet. Otros fragmentos de cdigo quizs quieran realizar al guna accin cua ndo la clase desencadene este evento new request y ese cdigo debera incluir un mtodo que se ejecute cua ndo se desencadene el evento. El mtodo que implementan los usuarios de la clase p ar a recibir y proces ar los eventos es definido por un concepto de C# llamado delegado. Un delegado es una especie de "funcin patrn" que describe el aspect o que tiene el cont rol ador de eventos del usuario. Un delegado tambi n es una clase que tiene una firma y contiene referencias a mtodos. Es como un a funcin puntero, pero puede c ont e ner r eferencias a mtodos estticos y de instancia. Para los mtodos de instancia, el delegado al mac ena una referencia al objeto y al punto de entrada de la funcin. Un delegado define lo que debe devolver el controlador de eventos del usuario y lo que debe ser la lista de parmetros. Para definir un delegado en C#, hay que u s ar la siguiente sintaxis: La pal abra clave de C# delegate. El tipo devuelto por el cont rol ador de eventos. El identifcador de delegado. La lista de par met ros del controlador de eventos, entre parntesis. Si se declaran delegados en la clase que des encade na el evento, se les puede anteponer las pal abras clave public. protected, internal o prvate como se p ueden ver en este ejemplo de un a definicin delegate.
public delegate void E ve nN um b e r H a n d l e r (int Number);

En este ejemplo se crea un delegado pblico llamado EvenNumberHandler que no devuelve nada. Este delegado slo define un par met ro p ar a ser pasado, de t ipo int . El identifcador de delegado, EvenNumberHandler. puede ser cual quier nombre que elija mientras no le d el nombre de una p a l a b ra clave de C#.

Cmo definir eventos


Para ac la rar lo que es en realidad un evento, vamos a empezar con un ejemplo. Est conduciendo en su coche y ap arece en el s alpicadero la luz que indica que queda poco combustible. Lo que en realidad ha ocurri do es que un sensor en el

346

depsito de gasolina ha avisado al ordenador de que el nivel de combustible est bajo. El ordenador entonces desencadena un evento que a su vez enciende la luz del salpi cadero para que sepa que tiene que comprar ms combustible. En pocas palabras, un evento es un medio que tiene el ordenador de avisarle de una condicin. Para definir un evento que desencadene una clase se usa la p al ab ra clave de C# event. En su forma ms simple, las declaraciones de eventos de C# usan la siguiente sintaxis: La p al abr a clave de C# event. El tipo de evento. El identificador de evento. El tipo de evento concuerda con un identificador de delegado, como se muestra en el siguiente ejemplo de servidor Web:
public public delegate class void NewRequestHandler ( s t n n g URL) ;

Webserver NewRequestHandler NewReque st Ev en t;

{
public event

// }

..

Este e j em pl o d e c l a r a un d e l e g a d o l l a m a d o N e w R e q u e s t H a n d l e r . NewRequestHandler define un delegado que sirve como una plantilla par a los mtodos que proces an el evento new request. Todos los mtodos que necesitan p ro ces ar el evento new request deben obedecer las convenciones de llamada del delegado: no deben devolver ningn dato y deben tener una sola cadena como lista de p ar met ros . Las implementaciones de control de eventos pueden tener cualqui er n ombre de mtodo mientras su tipo dev uelto y su lista de par met ros concuerdcn con el pat rn de delegados. La clase Webserver define un evento llamado NewRequestEvent. El tipo de este evento es NewRequestHandler. Esto significa que slo los con troles de evento escritos par a que concuerdcn con las conv enciones de llamada del delegado pueden ser usadas p a r a pr oc es ar el evento NewRequestEvent.

Cmo instalar eventos


Tras escribir el controlador de ev entos, hay que crear una nueva instancia de l e instalarlo en la clase que desencadena el evento. P ar a cr ear una nueva i nstancia de cont rol ador de eventos debe crear una nueva v ariable del tipo dele gado y p a s a r el n ombre del mtodo cont rol ador de eventos como un argumento. Usando el ejemplo del cliente Web. la creacin de una nueva instancia controladora de eventos puede tener este aspecto:

347

public void MyNewRequestHandler ( s t n n g URL)

{ }
NewRequestHandler H a n d 1erInstanee = Handlerlnstance; new NewRequestHandler(MyNewRequestHandler);

Tras crear la nueva instancia controladora de eventos, se usa el operador += par a aadirla a la variable de evento:
NewRequestEvent += Handlerlnstance;

Esta instruccin enlaza la instancia de delegado Handlerlnstance. que admite el m t o d o MyNewRequestMethod. con el e v e n t o N e w R e q u e s t E v e n t . Mediante el oper ad or + = . se pueden enl azar tantas instancias de delegado como quiera par a un evento. Del mi smo modo, puede u sar el oper ador - = p ar a eliminar una instancia de delegado de un evento:
NewRequestEvent -= Handlerlnstance;

Esta instruccin desenlaza la instancia de delegado Hand 1er Ins tance del evento NewRequestEvent.

Cmo desencadenar eventos


Se puede des encadenar un evento desde una clase usando el identificador del evento (como el nombre del evento) como si fuera un mtodo. La accin de invo c ar un ev ento como un mtodo des encadena el evento. Dese ncad en ar el evento new request en el ejemplo del servidor We b puede t ener el siguiente aspecto.
N e w R e q u e s t E v e n t (s tr UR LO f N e w R e q u e s t );

Los pa r m et ros usados par a desencadenar el evento deben coincidir con la l i s t a de p a r m e t r o s del d e l e g a d o del e v e n t o . El d e l e g a d o del e v e n t o NewReques tEvent se defini para acept ar un par met ro de cadena: por tanto, se debe p r op or ci onar una cadena cuando se desencadene el ev ento desde la clase del cliente Web.

Cmo unirlo todo


El listado 15.1 muest ra delegados y eventos en accin. El cdigo implemcnta una clase que cuenta desde 0 hasta 100 y desencadena un ev ento c uando encuen tra un numero impar d urante el proceso de contado.

348

Listad o 15.1. Cmo recuperar eventos de nmero impar using System; public class delegate Counter event EvenNumberHandler O n Ev en Nu mb er ; void EvenNumberHandler ( .int Number) ;

{
public public

Counter( ) = null;

{
OnEvenNumber

}
public void CountTo'100 () CurrentNumber; = 0; CurrentNumber <100;

{
int

for (CurrentNumber Cu rr e n t N u m b e r ++)

{
lf (CurrentNumber 2 0)

{
lf (OnEvenNumber != null)

{
OnEvenNumbe r (Cur r entNumbe r ) ;

} } }
class EvenNumberHand1erC1ass void Ev en Nu m b e r F o u n d (m t EvenN um be r )

{
public

{
Console.WriteLine (EvenNumbe r ) ;

} )
class MainClass void Main ( )

{
public: static

{
Counter MyCounter = new C o u n t e r (); EvenNumberHandlerClass MyEvenNumberHandlerClass = new E v e n N u m b e r H a n d l e r C l a s s (); M y C o u n t e r .OnEvenNumber += new EvenNumbe rHa nd 1e r (MyEvenNumbe r H a n d l e r C l a s s .EvenNumbe r F o u n d ) ; M y C o u n t e r .C o u n t T o l O O ();

349

Para compilar esta aplicacin hay que crear una nueva aplicacin de consola en Visual Studio y copiar en ella el cdigo fuente o simplemente u sar el bloc de notas par a g ua r da r el archivo y a continuacin usar:
ese < filename>

El listado 15.1 implementa tres clases: La clase Counter es la elase que realiza el clculo. Implementa un mto do pbl ico l lamado Co u n t T o l O O ( ) y un evento p b l ic o l lamado O n E v e n N u m b e r . El evento O n E v e n N u m b e r es del tipo delegado

EvenNumbe rHand1er.
La clase EvenNumberHandlerClass contiene un mtodo pblico lla mado EvenNumberFound. Este mtodo acta como el controlador de evento p a r a el evento OnEvenNumber de clase Counter. Imprime en la consola el entero p ropor ci onado como parmetro. La clase MainClass contiene el mtodo Main ( ) de la aplicacin

El mtodo Main ( ) crea un objeto de clase Counter y da nombre al objeto My C o u n t e r . T a m b i n c r ea un n ue v o o bj et o de c las e E v e n N u m b e r HandlerClass y llama al objeto MyEvenNumberHandlerClass. El mtodo Main ( ) llama al mtodo CountTolOO ( ) del objeto MyCounter. pero no antes de instalar una instancia de delegado en la clase Counter. El c d i g o c r e a u n a n u e v a i n s t a n c i a de d e l e g a d o q u e g e s t i o n a el m t o d o EvenNumber Found del objeto MyEventNumberHandlerClass y lo a a de al evento OnEvenNumber del objeto MyCounter us ando el oper ador +=. La i mplementacin del mtodo CountTolOO usa una variable local para cont ar desde 0 a 1 0 0 . Ca da vez que pa sa por el bucle contador, el cdigo com pr ue ba si el nmero es par e xami nando si el nmero tiene resto al dividirse entre dos. Si el nmero es par. el cdigo desencadena el evento OnEvenNumber y p ropor ci ona el nmero p a r como el ar gument o par a hacerlo coincidir con la lista de p ar me tr os del delegado de eventos. C om o el mtodo EvenNumber Found de MyEvenNumberHandlerClass e st ab a instalado como un cont rol ador de eventos y como ese mtodo escribe el p ar m et ro p ro por ci onado en la consola, si se compila y ejecuta el cdigo del listado 15.1. se escriben en la consola los nmeros pares entre 0 y 100.

Cmo estandarizar un diseo de evento


Aunque C# ac ept a perfectament e cualqui er diseo de delegado que se pueda compilar. N E T F ramework prefiere que se adopte un diseo est ndar par a los delegados. El diseo de delegados preferido usa dos argumentos: por ejemplo, el

SystemEventhandler:

350

Una referencia al objeto que desencaden el evento. Un objeto que contienen datos relacionados con el evento. El segundo par met ro, que contiene todos los datos del evento, debe ser un objeto de un clase que derive de una clase . NET llamada System. EventArgs. El listado 15.2 remodela el listado 15.1 usando este diseo preferido.
Listad o 15.2. Cmo recuperar nmeros impares con la convencin de delegados NET using System; Origmator,

public delegate void EvenNumberHandler(object OnEvenNumberEventArgs Eve nN um berEventArgs); class Counter event EvenNumberHandler OnEvenNumber;

{
public public

Counter( ) = nuil;

{
OnEvenNumber

}
public void CountTolOO()

{
int CurrentNumber; = 0; CurrentNumber <= 100;

for (CurrentNumber CurrentNumber++)

{
if (CurrentNumber 2 == 0) != nuil) EventArg um en ts ;

{
if (OnEvenNumber

{
OnEvenNumberEventArgs

EventArguments = new O n E v e n N u m b e r E v e n tA rg s( Cu rr en tN um b er ); OnEvenNumber(this, E ve nt Arguments);

public

class

OnEvenNumberEventArgs EvenNumber;

: EventArgs

{
prvate public int

OnE ve nN um be rE ve nt Ar gs (int

EvenNumber)

351

{
t h i s .EvenNumber = EvenNumber;

}
public int Number

{
get

{
return EvenNumber;

} } I
c lass EvenNumbe rHancllerClass

{
public void E ve n N u m b e r F o u n d (object Originator, OnRvenMurtibe rEventArgs EvenNumbe r Event Args )

{
Cons ole . W n t e L i n e (EvenNumbe rEventArgs .Numbe r ) ;

c 1a s s M a 1 11C 1a s s

<
pu b ! i .c stdtic voicl Main (!

I
f : oi ; n t e r MyCounter = new Counter i ); EvenMumberHand1erClass MyEvenNumbe i Hancll e rClass - new t i l ve r ,Uumbe rHand 1 e rC 1 a s s () ; 14yCount e r .OnEvenNumber + - new E ve nN um be rH an d1er ( MyEvenNumbe rHandle r C 1 a s s .EvenNumber Found > ; M yC o u nter .C o u n t T o 1 0 0 ( ') ;

El listado 15.2 aade una nueva clase llamada OnEvenNumberEventArgs que d e n \ a de la clase N E T EventArgs. Implementa un const ructor que toma un numero entero y lo al macena en una variable privada. Tambi n expone una propiedad de solo lectura llamada Number. que devuelve el valor de la variable privada. La firma del delegado tambin ha cambiado para cumplir con la nueva conven cin. Ahora acepta dos parmetros de entrada: una referencia al objeto que desen cadena el evento v un objeto de tipo OnEvenNumber Event A r g s . Cuando la clase Counter se pre para par a desencadenar el evento, antes crea un nuevo objeto de tipo OnEvenNumberEventArgs y lo inicializa con el numero impar. A continuacin pasa este objeto al evento como segundo parametro. La nuev a implementacion del mtodo EvenNumber Found exami na el se gundo parmetro, un objeto de clase OnEvenNumberEventArgs y escribe el valor de la propiedad Number del objeto en la consola.

352

Cmo usar descriptores de acceso de eventos


En la implementacin general de objetos, hay que tener un c ampo de eventos definido en la clase por cada evento posible que pueda desencadenar la clase. En ejemplos como el listado 15.2. en el que la clase solo desencadena un evento, definir un ca mpo de ev entos p ar a cada evento no es muy costoso. Sin embargo, este sistema es mucho ms compl icado cuando la clase puede des encade nar uno de varios eventos. Tome, por ejemplo, una clase de C# que gestiona un componente de la mterfaz de usuario de Windows. Los componentes normales de la interfaz de usuario de Window s pueden recibir uno de los muchos mensajes posibles del sistema o p e r a tivo y podramos querer disear nuestra clase para que se enven a los usuarios de la clase, mediante un ev ento de C#. los mensajes que el componente del interfaz de usuario recibe del sistema operativo. Definir un ca mpo de evento en una clase para cada posible mensaje de Window s obligara a la clase a a lmac enar una gran cantidad de campos y hara que tuviera un t amao enorme C# admite una forma alternativa por la que los ev entos pueden definirse como propiedades, en lugar de como campos. Las propiedades de eventos funcionan exact ament e igual que las propiedades de clase estndar, que se implementan con cdigo, en lugar de c a m pos de datos. A diferencia de una propiedad estndar, una propiedad de evento usa las palabras clave add y remove par a definir bloques de codigo:
pub.Lic event EvenNumberHandler OnEvenNumber

{
add

{ }
r emove

{ } ) El cdigo del bloque de cdigo add se invoca cuando un usuario aade un nuev o cont rol ador de ev entos al ev ento us ando el op er ad or + = . La ventaja de us ar descriptores de acceso de eventos es que tenemos total libertad en lo que respecta al modo en que almac enamo s los controladores de eventos. En lugar de definir c ampos s eparados par a cada evento, podemos a l m a cenar una sola lista enlazada o una matriz de controladores y podemos implementar el descriptor de acceso de eventos remove par a eliminar un controlador de even tos de la matriz o de la lista. Como en las propiedades estandar. podemos usar la palabra clav e de C# valu para hacer referencia al cont rol ador de evento que se aade o elimina, como se puede v er en la siguiente instruccin:

353

M y C o u n t e r .OnEvenNumber += new E v e n N u m b e r H a n d l e r( My Ev en Nu mb er Ha nd le rC la ss .E v e n N u m b e r F o u n d ) ;

En es t a i n s t r u c c i n , se a a d e al eve nt o O n E v e n N u m b e r un nu ev o EvenNumberHandler objeto. Si implemcnt semos el evento como una p ro piedad. el bloque de cdigo add podra usar la pal abr a clave add para hacer referencia al nuevo objeto EvenNumberHandler:
public event EvenNumberHandler OnEvenNumber

{
add

{
AddToList (valu) ;

}
r emove

{
R em ov e F r o m L i s t ( v a l u ) ;

} } C uand o se usa en descriptores de acceso de eventos, la p al ab ra clave valu es una variable de tipo Delegate.

Cmo usar modificadores de eventos


Se puede anteponer a una declaracin de un evento uno de los siguientes modi ficadores: Static Virtual Override Abstract

Eventos estticos
Los eventos modificados con la pal ab ra clave static se c omport an de forma parecida a los campos estticos, en el sentido de que. aunque cada copia de una clase contiene copias s eparadas de todos los campos, slo puede haber una copia de un mi embro esttico en un moment o dado. Todos los objetos de la clase com parten los eventos estticos. C uan do se les hace referencia, debe ser a travs del nombre de la clase y no mediante el nombre del objeto, como se apreci a a conti nuacin:
public class Counter

354

public static event EvenNumberHandler OnEvenNumber;

// }

. . .

C o u n t e r .OnEvenNumber += new Ev en Nu mb er Ha nd le r( My E v e n N u m b e r H a n d l e r C l a s s .Ev e n N u m b e r F o u n d );

Como puede ver. debe hacer referencia al evento esttico OnEvenNumber especificando el nombre de la clase y el n ombre del objeto.

Eventos virtuales
Los eventos modificados con la p al ab ra clave virtual marc an cualquier descriptor de acceso add o remo ve como virtual. Los descriptores de acceso v irtuales en clases derivadas pueden ser r eemplazados.

Eventos de reemplazo
Los eventos modificados con la p al ab r a clave override marc an cualquier descriptor de acceso add o remo ve como eventos de reempl azo add o remove con el mismo nombre en una clase base.

Eventos abstractos
Los eventos modificados con la p al ab ra clave abstract marcan cualquier descriptor de acceso add o remove como abstracto. Los descriptores de acceso abstractos no proporci onan una implementacion propia: en su lugar, un evento de reemplazo de una clase derivada p ropor ci ona una implementacion.

Resumen
Las clases pueden des encadenar eventos cuando un p rog rama pide a sus clien tes que le avisen de las acciones llevadas a cabo por la clase. Sin eventos, los usuarios llaman a un mtodo p ar a realizar una operacin, pero en realidad no saben lo av a nz ad a que est la operacin. Imagine, por ejemplo, un mtodo que recupera una pgina Web de un serv idor Web. Esa operacin consiste en varios pasos: Conect ar con el servidor Web. Solicitar la pgi na Web. Recuperar la pgi na We b devuelta. Desconect ar del servidor Web.

355

Es posible disear una clase como esta con eventos que se desencadenen cuando comience cada una de estas acciones. Al des encadenar los eventos en los pasos crticos del proceso le da pistas a los usuarios de su clase sobre en qu parte del proceso se encuent ra el cdigo. Los i n vo cado res r e sponden a los eventos re gi st ra n do mt odo s llamados controladores de eventos. Los controladores de eventos se invocan cuando una clase desencadena algn evento. Estos mtodos se corresponden con la lista de par met ros y devuelven un valor de un mtodo patrn especial llamado delegado. Un delegado describe el diseo de un co nt rol ador de eventos, indicando qu par met ro s debe admitir y cmo debe ser su cdigo devuelto. Los controladores de eventos se instalan usando el o per ador +=. Los ex entos se declaran normal ment e como ca mpos pblicos en una clase y los invocadores aaden sus controladores de ev entos a la clase creando un nuevo objeto de la clase delegado y as ignando el objeto al evento us ando el o per ador + = . C# permite especificar varios controladores de eventos p ar a un solo evento y tambin permite usar el oper ador - = p ar a eliminar un cont rol ador de eventos de un evento. C# no obliga a usar un nico patrn de diseo p ar a los delegados, pero NET F ramewo rk recomienda un diseo. Usar el diseo recomendado p ropor ci ona un estndar que. cuando se respeta, puede dar a los delegados una lista de parmetros de mtodo: un objeto que especifica los objetos que desencadenan el evento y un objeto de una clase derivada de la clase System. EventArgs. que contiene los ar gument os par a el evento. C # hace que sea muy sencillo i mplement ar eventos en las clases. En el nivel mas bsico, cada evento se declara como un ca mpo pblico y se pueden gestionar tantos eventos como se desee. Si la clase va a gestionar varios eventos y el numero de ca mpos pblicos dentro de la clase parece tener una cantidad excesiva de cdigo, se pueden escribir descriptores de acceso de eventos que permitan contro lar el modo en que la clase gestiona los controladores de eventos. En lugar de definir c amp os pblicos par a los eventos, los descriptores de acceso de exentos permiten definir los eventos como propi edades con bloques de cdigo add y remove. El bloque de codigo add se invoca cuando se aade un controlador de exentos a un evento y el bl oque de cdigo remove se invoca cuando se elimina un c ont rol ador de eventos de un evento. Estos bloques de cdigo se pueden impicment ar al mac enand o los controladores de eventos en una matriz o en una lista par a ser usados posteriormente. El concepto de C# de ex entos y delegados es un concepto nuevo p ar a la familia de lenguajes C. Los eventos pueden ser desencadenados en C y C ++ u sando otros mecani smos, pero estos lenguajes no definen pal abr as clave par a hacer que fun cionen los ex entos. En C#. los exentos y delegados son elementos completamente definidos por s mismos y tanto el lenguaje como el compi lador tienen compat ibi lidad integrada par a el control de exentos. Ot ra ventaja de us ar exentos en C# es que son completamente compatibles con el CLR. lo que significa que se puede p r e p a r a r un mecani smo de exento en

356

C# y desencadenar eventos que se controlen por otro lenguaje N E T Como el CLR admite eventos en el nivel de tiempo de ejecucin, se puede des encade nar un evento en C# y controlarlo v procesarl o con otro lenguaje, como Visual Basic NE T

357

IQ Control de excepciones

Bus car errores y manejarlos adecuadament e es un principio f undamental par a disear software correctamente. En teora, escribimos el cdigo y cada lnea f un ciona como pretendemos y los recursos que e mpl eamos siempre estn presentes. Sin embargo, ste no siempre es el caso en el mundo real. Otros progr amadore s (por supuesto, no nosotros) pueden cometer errores, las conexiones de red pueden interrumpirse, los servidores de bases de datos pueden dejar de funcionar y los archivos de disco pueden no tener los contenidos que las aplicaciones creen que contienen. En pocas pal abras, el cdigo que se escribe tiene que ser ca paz de detectar errores como stos y responder adecuadamente. Los mecani smos p ar a i nformar de errores son tan diversos como los propios errores. Algunos mtodos pueden estar diseados par a devolver un valor booleano que indican el xito o el fr acaso de un mtodo. Otros mtodos pueden escribir errores en un fichero de registro o una base de datos de algn tipo. La variedad de modelos de presentacin de errores nos indica que el cdigo que escri bamos par a controlar los errores debe ser bastante consistente. Ca da mtodo puede i nformar de un error de un modo distinto, lo que significa que la aplicacin estar repleta de gran cantidad de cdigo necesario p a r a detectar los diferentes tipos de errores de las diferentes l lamadas al mtodo. N E T F ramework propor ci ona un mecani smo estndar, llamado control de excepciones estructurado (SEH). p ar a informar de errores. Este mecanismo de

359

pende de las excepciones par a indicar los fallos. Las excepciones son clases que describen un error. N E T Framework las usa p ar a informar de errores y podemos utilizarlas en nuestro codigo. Puede escribir cdigo que busque excepciones gene radas por cualquier fragmento de cdigo, tanto si procede del C L R como si proce de de nuestro propio cdigo y podemos ocup ar no s de la excepcin generada adecuadament e. Usando SEH. slo necesitamos crear un diseo de control de errores par a nuestro cdigo. Esta metodologa unificada del proceso de errores tambin es crucial para permitir la programaci n N E T multilingiie. Al disear todo nuestro cdigo u s an do SEH. podemos mezclar y co mp ar a r cdigo (por ejemplo C#. C ++ o VB.NET). sin peligro al guno y fcilmente. Como premio por seguir las reglas del SEH. N E T Framework gar ant iza que todos los errores sern expuestos y controlados convenientemente en los diferentes lenguajes. El proceso de deteccin y gestin de excepciones en el cdigo de C# es senci llo. Se deben identificar tres bloques de cdigo cuando se t rabaj a con excepci o nes: El bloque de cdigo que debe usar el proces ami ent o de excepciones Un bloque de cdigo que se ejecuta si se e ncuentra una excepcin mientras se procesa el pri mer bl oque de cdigo Un bloque de cdigo opcional que se ejecuta despus de que se procese la excepcin En C#. la generacin de una excepcin recibe el nombre de iniciacin de una excepcin. El proceso de i nformar de que se ha iniciado una excepcin recibe el nombre de capturar una excepcin. El fragment o de cdigo que se ejecuta des pus de que se haya procesado la excepcin es el bloque f i n a l l y . En este captulo veremos como se usan estos constructores en C#. Tambi n estudiaremos a los mi embros de la jerarqua de las excepciones

NOTA: Un debate largo y recurrente de la comunidad de usuarios de soft ware orientado a objetos es si las excepciones deberan usarse en todos los errores (incluyendo los errores que uno espera que ocurran frecuentemente) o slo para los errores graves (los conocidos como errores de excepcin, que slo ocurren cuando un recurso falla inesperadamente). El punto crucial de este debate es el relativamente importante encabezado necesario para iniciar y atrapar excepciones, encabezado que podemos evitar mediante el uso de otro mtodo de control, como los cdigos de devolucin. La respues ta de .NET Framework a este conflicto es el uso del control de excepciones estructurado para todos los errores porque permite garantizar que todos los recursos se liberan adecuadamente cuando se produce un error. Esto es propio del consenso actual de este reido debate. La investigacin exhaus-

360

tiva (principalmente por parte de la comunidad de usuarios de C++) ha llegado a la conclusin de que evitar la prdida de recursos sin excepciones es prcticamente imposible. Por supuesto, C# evita la prdida de memoria con la recogida de elementos no utilizados, pero todava necesitamos un mecanismo para evitar las prdidas de recursos de los varios tipos de pun teros de operaciones del sistema. Como en todas las instrucciones de diseo, usar excepciones indiscrimi nadamente para todos los errores supone un uso excesivo de recursos. Cuando el error es local para un bloque de cdigo, puede ser ms apropiado usar cdigos de devolucin de error. Con frecuencia vemos este enfoque cuando se implementa una validacin de formularios. ste es un cambio aceptable porque los errores de validacin suelen estar localizados en el formulario que recoge la entrada. En otras palabras, cuando ocurre un error de valida cin, se presenta en pantalla un mensaje y pedimos al usuario que vuelva a introducir correctamente la informacin requerida. Como el error y el cdi go controlador estn en el mismo bloque, controlar la prdida de recursos es sencillo. Otro ejemplo es controlar una condicin de fin de archivo cuan do se est leyendo un archivo. Esta condicin puede ser controlada fcil mente sin usar el encabezado de excepciones requerido. De nuevo, la condicin de error se controla completamente dentro del bloque de cdigo donde ocurre el error. Cuando observe que se realizan llamadas al cdigo fuera del bloque de cdigo donde ocurre el error, debe tender a procesar los errores usando SEH.

Cmo especificar el procesamiento de excepciones


La pal abr a clave de C# try especifica que hay un bloque de codigo que debe b us ca r cualquier excepcin iniciada mientras se est ejecutando el cdigo T r a b a jar con la pal abr a clave try es sencillo. Use la pal ab ra clave try seguida de una llave de apertura, de las instrucciones en las que se deben bu sc a r excepciones mientras se ejecutan y termine con una llave de cierre: try {
// coloque aqu las instrucciones

} Si se inicia una instruccin mientras se esta ejecutando cualquiera de las ins trucciones del bloque try. se puede ca pt ur a r la excepcin en el cdigo y o c u p a r se de ella adecuadamente.

361

Cmo capturar excepciones


Si se usa la pal abr a clave try p ar a especificar que desea ser i nformado sobre las excepciones iniciadas, es necesario escribir cdigo que at rape la excepcin y se ocupe de los errores que enva el cdigo. Par a indicar el cdigo que debe ejecutarse cuando se at rape una excepcin se usa la p al abr a clave de C# catch despus de un bloque try. La pal abr a clave catch funciona de for ma pareci da a la p al ab ra clave try.

Cmo usar la palabra clave try


La for ma ms simple del bl oque de cdigo catch at ra pa todas las excepcio nes iniciadas por el cdigo en el anterior bloque try. El bloque catch tiene la mi sma est ructur a que el bloque try, como se puede ap reci ar en el siguiente ejemplo: try {
// coloque aqu las instrucciones

}
catch

{
// coloque aqui las instrucciones

} Las instrucciones del bloque catch se ejecutan si se inicia una excepcin desde el bl oque try. Si ninguna de las instrucciones del bloque try inicia una excepcin, entonces no se ejecuta nada del cdigo del bloque catch.

Cmo atrapar clases especificas de excepciones


Tambi n se puede escribir un bloque catch que controle una clase especfica de excepcin iniciada por una de las instrucciones del bloque try. Esta forma del bl oque de cdigo catch usa la siguiente sintaxis: La p al abr a clave catch Un parntesis de apert ura La clase de excepcin que desea controlar Un identificador de variable p ar a la excepcin Un parntesis de cierre Una llave de ap ert ura

362

Las instrucciones que deben ejecutarse cuando se inicia una excepcin del tipo especificado desde el anterior bl oque try Una llave de cierre

Observe el siguiente cdigo: try {


// coloque aqu las instrucciones

}
catch(Exception thrownException) las instrucciones

{
// coloque aqui

} El bloque catch de este ejemplo a t r a pa excepciones de tipo Exception que inician el anterior bloque try. Define una variable del tipo Exception llamada ThrownException. La variable ThrownException puede usarse en el cdigo del bl oque catch par a obtener ms informacin sobre la excepcin iniciada. El cdigo del bloque try puede iniciar diferentes clases de excepciones y quere mos controlar cada una de las diferentes clases. C# permite especificar varios blo ques catch. cada uno de los cuales controla una clase de error especfica:
try

{
// coloque aqu las instrucciones

}
catch(Exception ThrownException) 1

[
// Bloque catch

}
catch(Exception ThrownException2)

{
/ / Bloque catch 2

} En este ejemplo, se revisa el cdigo del bloque try en b us ca de excepciones iniciadas. Si el C L R descubre que el cdigo del bloque try inicia alguna ex c ep cin. exami na la clase de la excepcin y ejecuta el bloque catch adecuado. Si la excepcin iniciada es un objeto de clase Exception. se ejecuta el codigo del Bloque catch 1 . Si la excepcin iniciada es un objeto de alguna otra clase, no se ejecuta ninguno de los bloques. Tambi n se puede aadir un bloque catch genrico a la lista de bloques de cdi go catch. como en el siguiente ejemplo:
try

{
// coloque aqu las instrucciones

363

}
catch(Exception ThrownException) 1

{
// Bloque catch

}
catch

{
// Bloque catch 2

) En este caso, se revisa el cdigo del bloque try en b us ca de excepciones. Si la excepcin iniciada es un objeto de clase Exception. se ejecuta el cdigo de Bloque catch 1 . Si la excepcin iniciada es un objeto de al guna otra clase, se ejecuta el cdigo del bloque genrico catch (Bloque catch 2 ) .

Cmo liberar recursos despus de una excepcin


Los bloques catch pueden ir seguidos por bloque de cdigo. Este bloque de cdigo se ejecuta despus de que se procese una excepcin y cuando no ocurre ninguna excepcin. Si se quiere ejecutar este cdigo, se puede escribir un bloque fina 11 y . La palabra clave de C# finally especifica que hay un bloque de codigo que debe ejecutarse despus de que se ejecute un bloque de cdigo try. Un bloque de cdigo final ly tiene el mi smo for mato que los bloques try:
f i n a 11 y

{
// coloque aqu las instrucciones

} El bloque de cdigo f inally es un buen sitio donde liberar recursos a los que se hab a colocado en el mtodo con anterioridad. Suponga, por ejemplo, que estamos escribiendo un mtodo que abre tres archivos. Si encerramos el cdigo de acceso a archivos en un bloque try. podremos a t r a pa r excepciones relacionadas con la apert ura, lectura o escritura de esos archivos. Sin embargo, al final del cdigo, querremos cerrar los tres archivos, aunque se haya iniciado una excep cin. Probabl emente quer amos colocar las instrucciones de cierre de archivos en un bloque f inally y podremos es tructur ar el cdigo como se indica a continua cin: try (
// abrir archivos // leer archivos

}
c atch

{
// atrapar excepciones

364

}
finally

{
// cerrar archivos

} El compi lador de C# permite definir un bloque finally sin ningn bloque catch. Se puede escribir un bloque finally inmedi at ament e despus de un bl oque try.

La clase exception
Todas las excepciones iniciadas por N E T F ramework son clases derivadas de la clase Sys t e m .Except ion. La tabla 16.1 describe algunos mi embros utiles de esta clase.
Tabla 16.1. Miembros de la clase S y ste m .Exception Class

M iem b ro

D escrip cin

HelpLink Message

Un vnculo al archivo de ayuda que proporciona ms informacin sobre la excepcin El texto que se ha proporcionado, normalmente como parte del constructor de la excepcin, para describir la condicin del error El nombre de la aplicacin u objeto que provoc la excepcin Una lista de las llamadas al mtodo en la pila El nombre del mtodo que inici la excepcin

Source StackTrace TargetSite

Introduccin a las excepciones definidas por .NET Framework


N E T F ramework define varias excepciones que pueden iniciarse cuando se encuent ran ciertos errores en el cdigo de C# o en los mtodos que se pueden invocar. Todas estas excepciones son excepciones est ndar de N E T y pueden ser at rapadas usando un bloque catch de C#. Cada una de las excepciones de N E T se define en el espacio de nombre System de NET. Los siguientes apa rt ad os describen algunas de las excepciones mas comunes. Estas excepciones son slo una pequea parte de todas las que hay definidas en la biblioteca de clases base de N E T Framework.

365

OutOfMemoryException
El C L R inicia la excepcin OutOfMemoryException cuando agota su memoria. Si el cdigo intenta crear un objeto us ando el o per ador new y el CLR no d i s p o n e de s u f i ci e nt e m e m o r i a p a r a ello, el C L R ini ci a la e x c ep ci n OutOfMemoryException. mos trada en el listado 16.1.
Listado 16.1. Excepcin O utOfMemoryException using class System; MainClass static void M a i n ( ) [ ] LargeArray;

{
public

{
int t ry

{
LargeArray = new int [2000000000];

}
catch (OutOfMemoryException)

{
C o n s o l . W r i t e L m e ("The CLR s out of memo r y ." ) ;

} ) } El codigo del listado 16.1 intenta asi gnar un espacio a una matriz de dos mil millones de nmeros enteros. Dado que un nmero entero requiere cuatro bytes de memoria, se necesitan ocho mil millones de bytes par a contener una matriz de este tamao. Es bastante probable que su ordenador no disponga de esta cantidad de memori a y de que la asignacin falle. El codigo encierra a la asignacin en un bloque try y define un bloque catch p a r a que controle cualquier excepcin OutOfMemoryException iniciada por el CLR.

NOTA: El cdigo del listado 16.1 no escribe un identificador para la ex cepcin del bloque catch. Esta sintaxis (en la que se especifica la clase de una excepcin pero no se le da nombre) es vlida. Funciona perfectamente cuando se quiere atrapar una clase de excepciones pero no se necesita infor macin del propio objeto especfico de la excepcin.

StackOverflowException
El C L R inicia la excepcin StackOverflowException cuando agota el espacio de la pila. El C L R gestiona una estructura de datos llamada stock, que

366

registra los mtodos que han sido llamados y el orden en el que fueron llamados. El C L R tiene una cantidad limitada de espacio de pila disponible y si se llena, se inicia la excepcin. El listado 16.2 mues tra la excepcin StackOverflow-

Exception.
Listado 16.2. Excepcin S t a c k O v e r f l o w E x c e p t i o n
us m g class S ystem; MamClass s tat ic v o id Main( )

{
public

{
tr y

{
Re cur s ive ( );

}
catch(StackOverflowException)

{
Consol.WriteLine("The CL R is out of stack space.");

} }
pu b l i c st atic v oi d Recursive ( )

{
Recursive ( );

} } El cdigo del listado 16.2 i mplementa un mtodo llamado Recursive (). que se llama a s mi smo antes de regresar. Este mtodo es llamado por el mtodo Main ( ) y con el tiempo, hace que el C L R agote su espacio de pila porque el m t o d o R e c u r s i v e ( ) n u n c a r e g r e s a . El m t o d o M a i n ( ) l l a m a a Recursive ( ) . que a su vez llama a Recursive ( ) , que a su vez llama a Recursive ( ) y as sucesivamente. A la larga, el C L R se queda r sin espacio de pila e iniciar la excepcin StackOverf lowException.

NullReferenceException
En este ejemplo, el compi lador a t ra p a un intento de eliminar la referencia de un objeto nuil. El listado 16.3 m ue s t r a la excepci n N u l l R e f e r e n c e

Exception.
Listado 16.3. Excepcin NullReferenceException
us i n g class System; MyClass int Valu;

(
pu b l i c

367

class

MamClass

{
public static void M a i n ! )

{ try {
M yObject = n e w M y C l a s s ();

MyObject

= null;
= 12 3;

MyObject.Value

// espere a que el usuario reconozca los resultados Console.WriteLine ("Hit Enter to terminate...");
C o n s o l e .R ea d () ;

)
catch (Null Referenceszception)

{
Console.WriteLine("Cannot
/ /e s pe r e a que el C o n s o l e .R e a d () ; usuario

reference
r e co n oz c a

a null
los

object.");

r es u ltados

El codigo del listado 16.3 declara una variable de objeto de tipo MyC las s \ asigna a la variable el valor de nuil. (Si no se usa la instruccin new. sino que slo se declara una variable de objeto de t i p o M y C l a s s . el compi lador emitir el siguiente mensaje de error cuando se compile. "Uso de la variable local no asigna da MyO b j e c t .") A continuacin intentar t raba jar con el campo pblico Valu del objeto, lo que no est permitido porque no se puede hacer referencia a objetos nuil. El C L R a t r a p a este er r or e inicia la excepci n Nul IRe f e r e n c e Ezception.

TypelnitializationException
El C L R inicia la excepcin T y p e l n i t i a l i z a t i o n E x c e p t i o n cuando una clase define un const ructor esttico y el const ructor inicia una excepcin. Si no hay bl oques catch en el constructor par a at ra p ar la excepcin, el C LR inicia una excepcin T yp e ln i ti a l i z a t i o n E x c e p t i o n .

InvalidCastExpression
El C LR inicia la excepcin I n v a l i d C a s t E x p r e s s i o n si falla una con versin explicita. Esto puede ocurrir en contextos de interfaz. El listado 16.4 muest ra una excepcin Invalid Ca st Ex pr es sio n.

368

Listado 16.4. E x c e p c i n u sin g S y s t e m ; class Main Cas s static voicl Ma 1 n ()

inval idCastExcept.i o

i
public

{
t ry

{
M a m C l a s s MyObject = nev/ M a m C l a s s ! ); IFormattable Formattable; Formattable = (IFormat tablej M y O b j e c f ;

// espere a que el usuario reconozca los resultados Consol . W n t e L m e ("Hit Enter to termnate ..." i ; C o n s o l .R e a d ();

}
catch (InvalidCast E x c e p t i o n 1

{
Consol . W r i t e L m e ("MyObject T Fo rmat t able interface ." 1 ; // espere a que C o n s o l .R e a d (); el usuario cloes not implement t.hc

reconozca

los

resuitados

) } } El codigo del listado 16.4 usa un operador de conversin de tipo explcito para obtener una referencia a una interfaz N E T llamada IFormattable. Como la clase M a m C l a s s no mplementa la interfaz IFormattabl e. la operaeion de con ve rs i n expl ci ta falla y el C L R inicia la e xc epci n Inval idCast-

F c ep t io n .

ArrayTypeMismatchException
El C L R inicia la e x c e p c i n ArrayTypeMismatchException c u a n d o el
c d i g o intenta a l m a c e n a r un e l e m e n t o en una mat r i z c u n o t ipo no c o i n c i d e con el t i po del e l eme n t o .

IndexOutOfRangeException
El C LR inicia la excepcin IndexOutOfRangeException cuando el codigo intenta a l ma c en ar un elemento en una mat ri z empl eando un ndice de elemento que esta fuera del rango de la matriz. El listado 16.5 describe la excepcin

IndexOutOfRangeException.

369

Listado 16.5. E x c e p c i n using class System; MamClass static void M a i n ( )

IndexOutOf R angeException

{
public

{
try

{
int [ ] IntegerArray - new int = 123; [5];

In te ge rA rr ay [10]

// espere a que el usuario reconozca los resultados Console.WriteLine ("Hit Enter to te r m i n a t e ..."); C o n s o l e .Read () ;

}
c a t c h (IndexOutOfRangeException)

{
Console.WriteLine("An a 11 empt e d .") ; invalid element index access was

// espere a que el usuario Cons o 1e .R e a d ( );

reconozca

los

resultados

El cdigo del listado 16.5 crea una matriz con cinco elementos y a cont inua cin intenta as ignar un valor al elemento 10 de la matriz. C omo el indicc 10 est fuera del rango de la matriz de nmeros enteros, el C L R inicia la excepcin

IndexOutOfRangeException.

DivideByZeroException
El C L R inicia la excepcin DivideByZeroException cuando el cdigo intenta realizar una operacin que da como resultado una divisin entre cero.

OverflowException
El C L R inicia la excepcin OverflowException c uando una operacin mat emt ica guar dad a por el operador de C# checked da como resultado un desbordamiento. El listado 16.6 mues tra la excepcin OverflowException.
L istad o 16.6. Excepcin OverflowException using class S ys t em; MainClass

370

public

static void M a i n ( )

{
t ry

{
checked

{
int Integerl; i n t Integer2; int Sum; Integerl = 2000000000; Integer2 = 2000000000; Sum = Integerl + Integer2;

}
// espere a que el usuario reconozca los resultados C o n s o l e . W n t e L m e ("Hit Ent e r t o t e r m m a t e ..." ) ; Consol.Read ( );

}
catch(OverflowException)

{
C o n s o l e . W n t e L m e ("A mathematical ove r i 1o w .") ; // espere a que el usuario Consol.Read ( ); operation caused an

reconozca

los

resultados

} } } El cdigo del listado 16.6 suma dos nmeros enteros, cada uno con un valor de dos mil millones. El resultado, cuatro mil millones, se asigna a un tercer numero entero. El probl ema es que el resultado de la s uma es mayor que el v alor mxi mo que se puede asignar a un nmero entero de C# y se inicia una excepcin de des bo r da miento matemtico.

Cmo trabajar con sus propias excepciones


Puede definir sus propias excepciones y usarlas en su codigo del mismo modo que hara con una excepcin definida por N E T Framevvork. Esta consistencia en el diseo le permite escribir bloques catch que funcionen con cualqui er e x c e p cin que pueda iniciar cualquier fragmento de codigo. tanto si el codigo pertenece a N E T Framevvork. como si pertenece a una de sus propias clases o a un en s am blado que se ejecuta en tiempo de ejecucin.

371

Cmo definir sus propias excepciones


N E T Framework declara una clase llamada S y s t e m .Exception. que sir ve como clase base par a todas las excepciones de N E T Framework. Las clases p r e d e f i n i d a s del e n t o r n o c o m n de e j e c u c i n se d e r i v a n de S y s t e m . Sys temExcept ion. que a su vez deriva de S y s t e m .Except ion. La ex cepci n a est a regla son las ex ce pc io ne s D i v i d e B y Z e r o E x c e p t i o n . Not Fi ni teNumber Except ion y Over f lowExcept ion. que derivan de una clase l l am ada System. A r i t h m e t i c E x c e p t i o n . que de r iv a de System. SystemException. Cual qui er clase de excepcin que defina debe derivar de System. A p p l icationException. que t a mb i n deriva de

System.Ezception. La clase System. Except ion contiene cuatro propiedades de slo lectura que el codigo de los bloques catch puede u sar par a obtener ms informacin
sobre la excepcin que se ha iniciado: La propiedad Message contiene una descripcin de la c aus a de la excep cin. La propiedad InnerException contiene la excepcin que ha p r ovo ca do que se inicie la excepcin actual. Esta propiedad puede ser nuil, lo que i n d i c a r i a q u e no h a y n i n g u n a e x c e p c i n i n t e r i o r d i s p o n i b l e . Si InnerExcept ion no es nuil, hace referencia al objeto de excepcin que se ha iniciado y que provoc que se iniciase la excepcin actual. Un bloque catch puede a t r a pa r una excepcin e iniciar otra diferente. En ese caso, la propiedad I nner Except ion puede contener una referencia al objeto de excepcin original a tr a pa do por el bloque catch. La propiedad StackTrace contiene una cadena que muest ra la pila de ll amadas de mtodo que es taba en vas de ejecucin cuando se inici la excepcin. En ltima instancia, este rastro de pila puede contener todo el recorrido hasta la llamada al mtodo Main ( ) de la aplicacin del C LR La propiedad TargetSite contiene el mtodo que ha iniciado la excep cin. Algunas de estas propiedades pueden especificarse en uno de los constructores de la clase S y s t e m .Except ion:
public public E x c e p t i o n (string message); Ezception ( s t n n g message, Exception innerException);

Las excepciones definidas por el usuario pueden llamar al constructor de clase base en su const ructor de modo que se pueden as ignar valores a las propiedades, como mues tra el siguiente codigo:

372

using class

System; MyException : A p p l 1 cat 1 onExcept 1 on is my exception message.

{
public M y E x c e p t i o n () : base ("This

Este cdigo define una clase l lamada MyException. que deriva de la clase ApplicationException. Su constructor usa la palabra clave base para llamar al constructor de la clase base. La propiedad Message de la clase recibe el valor This is my exception message.

Cmo iniciar sus excepciones


Puede iniciar sus propias excepciones mediante la pal abra clave de C# throw. La pal abr a clave throw debe ir seguida por una expresin que evala un objeto de clase System. Exception o una clase derivada de .System. Exception. Observe el codigo del listado 16.7.
L istado 16.7. C m o iniciar s u s p r o p i a s e x c e p c i o n e s using class System; MyException : A p p 1 1 cat ionExcepti on : base("This is my exception message.")

{
public M y E x c e p t i o n ( )

class

MamClass static void M a i n ( )

{
public

{
try

{
MamClass MyObject = new M a m C l a s s ( );

M y O b ]e c t .T h r o w E x c e p t i o n (); // espere a que el usuario reconozca los resultados C o n s o l . W r i t e L m e ("Hit Enter to terminate ..."); C o n s o l .Read () ;

}
catch(MyException Ca ughtException)

{
Consol . W r i t e L m e (CaughtException.Message) ;

373

// espere a que el usuario C o n s o l . R e a d ();

reconozca

los

resultados

} }
public void ThrowException( )

{
throw new M y E x c e p t i o n () ;

} } El cdigo del listado 16-7 declara una clase new llamada MyException. que deriva de la clase base ApplicationException definida por NET Framework. La clase MainClass contiene un mtodo ll amado ThrowException. que inicia un nuevo objeto de tipo MyException. El mtodo es invocado por el mt o do Main ( ) . que encierra la llamada en un bloque tr y. El mtodo Main ( ) tambin contiene un bloque catch. cuya i mplementacin escribe el mensaje de la excepcin en la consola. C omo el mensaje se estableci c uando se construy el objeto de la clase MyException. est disponible y se puede escribir. Si se compila y ejecuta el listado 16.7 se escribe lo siguiente en la consola:
This s my exception message.

Cmo usar excepciones en constructores y propiedades


Algunos constructores de C# contienen cdigo que se puede ejecutar, pero no pueden devolver un valor que indique el xito o fr aca so del cdigo que se est ejecutando. Los constructores de clase y los descriptores de acceso de p ropi eda des set son un ejemplo claro. Iniciar excepciones es un buen modo de informar de errores de bloques de codigo c omo estos. En un captulo anterior e xa mi na mos una clase que implement aba un punto en la pantalla. La clase tenia propiedades que representaban las coordenadas v e v del punto y los descriptores de acceso set para las propiedades garant izaban que el valor era valido antes de que se al mac enar a realmente. El probl ema con el codigo del listado 1 es que no hay un informe de errores en caso de que se proporcione un valor que este fuera de los lmites permitidos. El listado 16.8 es una versin mejorada del listado 1 porque aade control de excepciones para informar de coor denadas que estn fuera de los lmites permitidos.
L istado 16.8. C mo iniciar excepciones desde descriptores de acceso de propiedades using System; :

public cas s Coorclinat.eOut.Of RangeExcept. ion A pp li ca ti onException

374

{
public CoordinateOutOfRangeException () coordinate is out of range.") : base ("The supplied

{ }

public

class mt mt mt

Point XCoordmate; YCoordinate; X

{
private private public

{
get

{
return XCoordinate;

} set {
if ( (value >= 0) & & (value < 6 40)) XCoordinate = value;

else
throw new CoordinateOut Of Ra ng eE xc e pt io n();

} )
public mt Y

{
get

{
return YCoordinate;

}
set

{
if ( (value >= 0) && (value < 48 0) ) YCoordinate = value;

else
throw new CoordinateOutOfRangeExceptlon () ;

) }
public static void M a i n ( ) = new Point ( );

{
Point M y P o m t

try {
M y P o m t . X = 100; MyPoint.Y = 200; Console .WriteLine (" ((0) , M y P o m t . X = 1500 ; MyPoint.Y = 600;

{1})",

M y P o m t .X , M y P o m t .Y) ;

375

C o n s o 1 e . Wr 1 1 e L i n e ( " ( { 0 } ,

{ 1} ) " ,

M yPom t.X,

M y P o m t . i'l

// espere a que el usuario reconozca los resultados Console.WriteLine("Hit Enter to termnate..."); C o n s o ie .P e a d () ;

}
catch Coorci inateOutOfP.angeRxcept ion Caught.Exception!

{
C onso le .Wr if el.i ne (Ca ught Except ion .Me s s a ge ) ; // espere a que C o n s o 1 e .P e a d t ) ; e i usuario reconozca los resultados

}
C a t r :h

{
Consoie.WrifeTiine "An unexpected caught .") ; // espere a que el C o 11 s o !e .P e 1 a d } ; usuario except i on wa s

reconozca

los

resultados

1 } } El cdigo del listado 16.8 comp rue ba el valor de los descriptores de acceso de la propiedad set para gar ant izar que el valor proporci onado est dentro de los lmites validos. En caso contrario, se inicia una excepcin. La asignacin del primer punto tiene xito ya que los dos valores estn dentro de los lmites validos. Sin embargo, el segundo punto no tiene xito, ya que la c o o rd en ad ax est fuera de los lmites vlidos. Este valor fuera de los limites validos hace que se inicie un ob| et o de clase Coorci inateOutOf RangeEi-icept ion. Si se compila y ejecuta el listado 16.8 se escribe lo siguiente en la consola:
( 1 0 0, 20 o ) The supplied coordnate rs out o range.

Resum en
N E T Framevvork usa las excepciones p ar a i nformar de diferentes errores a las aplicaciones NET. El lenguaje C# admite perfectamente el tratamiento de las excepciones y permite al usuario definir sus propias excepciones, ademas de t ra baj ar con las excepciones definidas por N E T Framevvork. El codigo de C# puede iniciar y a t r a pa r excepciones. Tambi n puede at ra p ar excepciones iniciadas por N E T Framevvork La ventaja de usar excepciones reside en que no es necesario co mp ro ba r cada llamada de mtodo en busca de un error. Se puede encerrar un grupo de llamadas de mtodo en un bl oque try y se puede escribir cdigo como si cada llamada de

376

mtodo del bloque tuviera xito. Esto hace que el codigo del bloque t r y sea mucho mas limpio porque no necesita ninguna comp rob aci n de errores entre lneas. Cual qui er excepcin iniciada desde el codigo del bloque t r y es g es ti ona da en un bloque c a t c h .

377

Cmo trabajar con atributos


u vi 17

Los captulos anteriores estaban dedicados a las pal abr as clave que definen el comport ami ent o de una clase y sus miembros. Por ejemplo, las p al abr as clave public. prvate, protected e internal definen la accesibilidad de la declaracin para otras clases del cdigo. Estos modificadores estn implementados por pal abr as clave predefinidas cuyo significado est integrado en el lenguaje C# y no puede ser cambiado. C# tambin permite mej orar las declaraciones de clase y de mi embro de clase mediante i nformacin que es i nterpretada por otras clases de C# en tiempo real. Esta informacin se especifica usando un constructor llamado atributo. Los atribu tos permiten incluir directivas en las clases y en sus miembros. El comp or ta mi en to del at ri bu to se define por el cdigo que escri bimos o por el codigo que proporci ona N E T Framework. Los atributos permiten ampliar el lenguaje C# mediante la escri tura de clases de at ri but o que mejoran el c omport ami ent o de o t ra s cl as es c u a n d o se e j e c u t a el cdi go , a u n q u e e s c r i b a m o s la cl as e de implementacin de atributo antes de que los otros usuarios apliquen el atributo a sus propias clases. Al compi lar aplicaciones, la informacin del atributo que se aade es enviada a los met adatos del ensamblado, lo que permite que otras aplicaciones o he r ra mientas vean que se est usando el atributo. Mediante el des ens ambla dor IL ( I L D A S M ) o las clases del espacio de nombres S y s t e m .Reflection se pue-

379

de c omp ro ba r fcilmente que atributos se han aadido a las secciones de codigo y se puede determinar si son tiles. En C#. se pueden usar dos tipos de atributo: los que estn integrados en el lenguaje y los atributos personalizados, que podemos crear. En la primera parte de este captulo, aprenderemos a usar atributos y exa mi naremos algunos de los atributos integrados que nos ofrece C#. En la segunda parte, aprenderemos a escribir atributos personalizados y el modo en que las aplicaciones pueden sacar partido de estos atributos.

Atributos
C# permite que los atributos se antepongan a los siguientes constructores de CU: Clases. Miembros de clase, incluyendo constantes, campos, mtodos, propiedades, eventos, indizadores. sobrecargas de operador, constructores y dest ructo res. Estructuras Interfaces. Mi em br os de interfaces. i ncluyendo mtodos, p ropi edades , eventos e indizadores. Enumeraciones y mi embros de enumeraciones. Delegados. Para especificar un atributo en el cdigo se escribe su nombre entre corchetes. La especificacin de at ri but o debe apa rec er antes de la declaracin en la que se debe aplicar el atributo. Los atributos mas simples pueden tener este aspecto:
[MyAt t n bu t e ]

Un buen ejemplo de un atributo simple es el modelo de s ubprocesos que se usa par a crear una aplicacin de consola en C#. Observe en el siguiente fragmento de cdigo el a tri but o [ STAThread J aplicado a la funcin Main ( ) . Este atributo indica al c ompi lador que la funcin Mai n ( ) debe introducir un ap art ament o de un nico s ubproc es o (STA) C O M antes de que se ejecute algn codigo basado en C OM
// 's urrond r y > // K 1 punto de entrada principal // < /summary> STAThreadj static v o id Main f s t n n g [] a r g s ) de la aplicacin.

380

//
// TODO: Aada el codigo para iniciar la aplicacin aqu

// ) Tambi n se puede ant eponer a un at ri but o un modi fi cador que defina el ele mento de C# al que se aplica el atributo. El modificador de atributo se escribe antes del nombre del atributo y va seguido de dos puntos. Esto recibe el nombre de enl azar un atributo. La tabla 17.1 enumera los tipos de declaraciones y los ele mentos a los que hace referencia par a los atributos especficos. Los elementos a los que las clases de atributo hacen referencia estn predefinidos: por ejemplo, si una clase N E T contiene una clase de at ri but o que slo hace referencia a e nu m e raciones. el atributo slo puede ser usado par a enumeraciones y no puede a pl i ca r se a otros constructores del cdigo C#. como clases y estructuras. Ms adelante aprender a especificar los destinos de los atributos para sus clases de atributo personalizadas.
Tabla 17.1. Listado de destinos de atributos

D ecla racin

D estin o

Assembly Module Class Struct Interface Enum Delegate Method Parameter Field Property - Indexer Property - Get Accessor Property - Set Accessor Event - Field Event - Property Event - Add Event - Remove

Assembly Module Type Type Type Type Type (por defecto) o Return Value Method (por defecto) o Return Value Param Field Property Method (por defecto) o Return Value Method (por defecto), Param or Return Value Event (por defecto), Field o Method Event (por defecto), Property Method (por defecto) o Param Method (por defecto) o Param

381

Por ejemplo, par a enl azar explcitamente un atributo a un mtodo, se debe escribir algo parecido a esto:
[me t h o d :MyAt tribute] int M y M e t h o d ( )

{ } Los modificadores de atributo son tiles en las situaciones en las que su enlace puede ser ambi guo, como m ues tra el siguiente ejemplo:
[MyAttribute ] int MyMethod ()

{ ( En realidad, este ej empl o no es muy ac la rat ori o. Se apl i ca el atributo

MyAt tribu te al mtodo o a su tipo d evuelto9 Si se especifica explcitamente el


enlace, como se muest ra en el anterior ejemplo, se indica al compilador de C# que el at ri but o se apl ica a todo el mtodo. En el ejemplo en el que el atributo [ STAThr ead ] se aplica a la funcin Main ( ) cuando se crea una aplicacin de consola, se puede hacer la siguiente modificacin p ar a hacer ms evidente el enlace:
/// <'summary> /// El punto de entrada principal /// ' '/s umma r y > [method: STAThread] static v o id Main Istring[ ] a rg s )

de

la aplicacin.

{ //
// TODO: Aada el codigo para iniciar la aplicacin aqu

// } Algunos atributos estn construidos para acept ar parmetros. Los parmetros de at ri but o siguen al nombre del atributo y estn entre parntesis. Los parntesis estn a su vez entre corchetes. Un atributo con un par met ro puede tener este aspecto:
[MyAttribute Parameter) ]

Ahora que tiene un conocimiento bsico de la sintaxis de los atributos, pode mos ex ami na r las clases de atributo integradas que ofrece .NET. Observe que las clases de atributos funcionan en todos los lenguajes, de modo que. aunque escriba atributos p ar a los tipos de C#. la informacin de atributo puede ser usada por Visual Basic NET. JScript N E T y todos los lenguajes orientados al entorno comn de ejecucin (CLR). El objetivo del uso de at ri but os es aument ar la funcionalidad del lenguaje.

382

Cmo trabajar con atributos de .NET Framework


N E T F ramework p ropor ci ona cientos de atributos predefinidos integrados. No son fciles de encontrar, ya que el S DK no propor ci ona una lista con cada at ri but o en orden alfabtico. Dependiendo de las clases que estemos usando, los atributos pueden derivar de la clase S y s t e m .Attribute y estos atributos pueden ser objetos especficos. Por ejemplo, cuando se t rabaj a con la funcin de N E T Fr amewor k que permite que el cdigo N E T interacte con el cdigo her e dado C O M (lo que se conoce como mt eroperabi lidad C OM ). se pueden emplear s ob re los m o d i f i c a d o r e s m s de 20 cl as es de a t r i b u t o s , des de el a t r i b u t o ComAliasName hast a el atributo TypeLibType . El siguiente cdigo muest ra el atributo DllImportAttribute y le da una idea de c mo l lamar a mtodos externos en las DLL de Wi n32 desde C#.
amespace S y st em .R un ti me .InteropServices

{
[AttributeUsage (AttributeTargets.Method) ] public class DllImportAttribute: S y s t e m .Attribute

{
public public public public publ c public public public DllImportAttribute (string dllName) { . . .} C a l l m g C o n v e n t i o n Cal 1 m g C o n v e n t ion ; CharSet CharSet; string EntryPoint; bool E x a c t S p e l l m g ; bool PreserveSig; bool Se tL astError; string Valu { get {...} }

} } Sin atributos, no sera posible informar al compi lador de C# del modo en el que pretendemos usar un mtodo especfico en una DLL externa y si el lenguaje C# incln ese esta funcionalidad en el lenguaje base, no sera lo suficientemente generica como p ar a poder ejecutarse en otras plataformas. Con la posibilidad de llamar a componentes Wi n32 a travs de todas las plataformas, se obtiene control sobre qu propiedades usar, en su caso, cuando se llama a mtodos externos. Como N E T Framework cuenta con tal cantidad de clases de atributos, es imposible describir ca da una de ellas en un solo captulo. Adems, como las clases de atributo son especficas de las clases en las que se definen, slo son tiles en el contexto de esas clases. A medida que codifique aplicaciones y se vaya familiarizando con los espacios de nombres de N E T Framework par a los que esta codificando, las clases de atributo asociadas a los espacios de nombre se harn ms transparentes. Algunas clases de atributo r eservadas pueden funcionar por s mismas y afectar directamente al lenguaje C#. Las clases Syst e m .Obsolete-

383

A t t r ibutc. S y s t e m . S e r i a l i z a b l e A t t r i b u t e y System. Condi 1 1 o na iAt tribute son clascs de atributo que pueden usarse indepen
dientemente y que afectan directamente al resultado del cdigo.

NO TA: En NET Framework, las clases de atributo tienen alias, por lo que, cuando se usan clases de atributo, es normal ver el nombre de la clase de atributo sin la palabra "Attribute" a continuacin. El sufijo est im plci to, de m odo que la form a corta no produce un error. Por ejem plo, ObsoleteAttribute puede usarse com o Obsolete, ya que los atri butos estn entre llaves, lo que hace evidente que son atributos y no algn otro tipo de m odificador.

Obser vemos algunas de las muchas clases de atributo disponibles en NET Framework. De esta forma, se a cos tumb ra ra al modo de t rabaj ar de estas clases y al modo de aplicar estos atributos en el codigo de CU.

System. Diagnostics. ConditionalAttribute


El atributo C o n d i t i o n a l es el alias de System. Diag n o s t i c s . Cono i t io na iAttribute. que solo puede aplicarse a declaraciones de metodo de clase. Especifica que el mtodo solo debe ser incluido como una parte de la clase si el compi lador de CU define el smbolo que ap arec e como p ar met ro del atributo. El listado 17.1 muest ra el funcionamiento del atributo Conditional.
L istad o 17.1. C mo trabajar con el atributo Conditional using using System; System.rnaqnostics;

p u b 1 1 c c 1 a s s TestClass

{
p ubi i c vo ic i Method i (i

{
Consol e . W r i t e L m e !"Hello from Method!!") ;

}
[C ondit io nal (" PE BU G " ) ] p u b 1 1 c v o id M e t h o d 2 ()

I
Conso l p .W c i t e L i n e ("Hello from M e t h o d 2 !");

I
p u b11c void M e t h o d 3 ()

(
Console .Wri t e L m e !"Hello from Me t h o d 3 !" ) ;

384

class

MainClass static void M a i n ( ) MyTestClass = new TestClass ( );

{
public

{
TestClass

M y T e s t C l a s s .Method 1 ( ); M y T e s t C l a s s . M e t h o d 2 (); M y T e s t C l a s s . M e t h o d 3 ();

} }

NOTA: Recuerde hacer referencia al espacio de nombre System. Diagnostics en el cdigo de modo que no tenga que usar el espacio de nombre completo al usar la clase de atributo Conditional y el compilador de C# pueda encontrar la implementacin de la clase.
El listado 17.1 declara dos clases: TestClass y MainClass. La clase TestClass contiene tres mtodos: Methodl ().Method2 () y Method3 (). Las clases Methodl ( ) y Method3 ( ) se implementan sin at ri but os, pero Method2 ( ) usa el atributo Condtonal con un p ar met ro llamado DE BUG. Esto significa que el mtodo Method2 ( ) es una parte de la clase solo cuando el compi lador de C# construye la clase con el smbolo DE BUG definido. Si el compi lador de C# construye la clase sin haber definido el smbolo DE BUG. el mtodo no se incluye como una parte de la clase y se pasa por alto cualquier llamada al mtodo. La clase MainClass i mplementa el mtodo Main ( ) de la aplicacin, que crea un objeto de tipo Tes tClass y llama a los tres mtodos de la clase. El resultado del listado 17.1 ca mb ia dependiendo del modo en que es compilado el cdigo. En primer lugar, intente compilar el listado 17.1 con el smbolo DEBUG definido. Puede u sar el ar gume nt o de lnea de c omando del compi lador de C# /D par a definir smbolos par a el compilador:
ese /D:DEBUG Listingl7-l.cs

C uand o el cdigo del listado 17.1 se compi la mientras el smbolo DEBUG est definido, el mtodo Method2 ( ) de la clase TestClass se incluye en la c o n s t ruccin y al ejecutar la aplicacin se escribe lo siguiente en la consola:
Helio Helio Helio from Methodl! from M e t h o d 2 ! from M e t h o d 3 !

Ahora intente compi lar el listado 17.1 sin el smbolo DEBUG definido:
ese Listingl7-I.cs

385

Cua nd o se compila el cdigo del listado 17.1 mientras el smbolo DEBUG no esta definido, el mtodo Method2 ( ) de la clase TestClass no se i n cl u \e en la construccin y se p as a por alto la llamada al mtodo Method2 ( ) realizada en el mtodo Main (). Si se crea el cdigo del listado 17.1 sin definir el smbolo DEBUG se g enera cdigo que escribe lo siguiente en la consola al ser ejecutado:
Helio Helio from M e t h o d l ! from M e t h o d 3 !

Como puede ver. el atributo Conditional es eficaz y til. Antes de empe zar a usar esta clase, preste atencin a las siguientes reglas: El mtodo marc ad o con el atributo Conditional debe ser un mtodo de una clase. El mtodo marc ad o con el atributo Conditional no debe ser un mtodo

override.
El mtodo marcado con el atributo Conditional debe tener un tipo devue lt o void. Aunque el mtodo m ar cad o con el at ri but o Conditional no debe estar m ar c ad o con el modi fi cador override. puede estar m ar cado con el mo dificador virtual. Los reemplazos de estos mtodos son implcitamente condicionales y no deben estar mar cados explcitamente con un atributo

Conditional.
El mtodo m ar cado con el at ri but o Conditional no debe ser una implementacin de un mtodo de interfaz; en caso contrario, se producir un error en tiempo de compilacin.

System.SerializableAttribute class
El atributo Serializable es el alias de la clase System.Seriali zableAttribute. que puede ser aplicado a clases. Indica a N E T Framework que los mi embros de la clase pueden ser s e a li z ad os a y desde un medio de al macenamiento, como un disco duro. El uso de este atributo hace que no resulte necesario agr egar la funcin de estado en las clases p ar a que su almacenamiento en el disco y su posterior recuperacin. C uando se serializan tipos, todos los datos de la clase ma rc a da como Serializable se guar dan en el estado en el que se encuentran cuando el dato es persistente. Si hay tipos dentro de la clase que no quiere que sean persistentes, puede marcarlos con el a tr i b u t o NonSerialized. que es el alias de la clase System. NonSerializableAttribute. En el siguiente fragmento de cdigo, los datos de la cadena password marcados como NonSerialized no son persistentes p ar a el archivo o flujo para el que se escriben los datos de clase:

386

public

class

Users{

public public public

string username; string emailaddress; string phonenumber;

// Aada un campo que no vaya a ser persistente [NonSerialized( ) ] public public FillData() { string password;

username = "admin"; password = "password"; emailaddress = "billg@microsoft.com"; phonenumber = "555-1212";

Para mo st rar un ejemplo de serializacin completo, el listado 17.2 vuelve a la clase Point 2D con la que ya hemos trabajado. La clase est m a rc a da con el atributo Serializable, lo que significa que puede ser g ua r d a d a y leda desde un flujo de datos.
L istado 17.2. Cmo trabajar con el atributo Serializable using using using System; System.10; System.Runt im e .Serialization.Forma11 ers.Binary;

[Se r i a l i z a b l e ] class Point2D

{
public public int X; int Y;

}
class MyMainClass static void M a i n ( ) = new Point 2D () ;

{
public

{
Point2D My2DPoint

My2DPoint.X = 100; My2 D P o i n t .Y = 200 ; Stream WriteStream = F i l e .C r e a t e ("Point2D .b i n "); BinaryFormatter BinaryWrite = new B in ar yF o r m a t t e r (); B i n a r y W n t e .Serialize (WriteStream, M y 2 D P o m t ) ; W r i t e S t r e a m . C l o s e (); Point2D ANewPoint = new P o m t 2 D ( ) ;

387

C o n s o l e . Wr it eL in e("New Point Before Deserialization: ({0}, {1} ) " , A N e w P o m t .X , ANewPoint .Y) ; Stream ReadStream = F i l e . O pe nR ea d("Point2D.bin"); BinaryFormatter B m a r y R e a d = new BinaryFormatter () ; ANewPoint = (Point2D )Bi na r y R e a d .D e s e r i a l i z e (Readstream); R e a d S t r e a m . C l o s e (); C o n s o l e . W ri te Li ne ("New Point After Deserialization: ({0}, {!})", A N e w P o i n t .X , A N e w P o i n t .Y) ;

El cdigo del listado 17.2 crea un nuevo objeto Point2D y le otorga las coordenadas (100, 200) . A continuacin serializa la clase en un archivo llamado Point2D.bin. El cdigo crea entonces un nuevo punt o y deserializa los contenidos del archi vo Point 2 D .bin en el nuevo objeto Point2D. El proceso de deserializacin lee el archivo Point2D.bin y asigna los valores que se encontraban en el archivo binario a los valores del objeto. Si se ejecuta el cdigo del listado 17.2 se escribe lo siguiente en la consola.
New P o m t New P o m t Before Deserialization: (0, 0) After Deserial iz at io n: (100, 200)

C uand o se crea el nuevo objeto Point2D. sus mi embros se inicializan con sus valores por defecto de 0. El proccso de deserializacin. que asigna los valores de acuerdo con los datos al mac enados en el archivo Point2D.bin. cambia los valores. El listado 17.2 emplea dos clases de . NET F ramework en su proceso de sealizacin La clase Stream se encuentra en el espacio de nombre System.10 y gestiona el acceso a los flujos de datos, incluyendo los archivos de disco. La c l a se B i n a r y F o r m a t t e r se e n c u e n t r a en el e s p a c i o de n o m b r e System .Runtime .Ser ial i zat ion .Formatters .Binary y gestiona la serializacin de datos a una representacin binaria. N E T Framework incluye otros formateadores que pueden usarse par a representar datos serializados en otros formatos. Por ejemplo, la clase SoapFormatter da a los datos sealizados un formato adecuado par a una llamada X M L SOAP.

NOTA: La cia&e BinaryForfaatter es una patente de .NET Framework. Si tene pefis&do que su destino sean otros sistemas que pueden no ser compatibles con el formato binario, considere usar la clase Soap Formatter para que persistan los datos de un formato XML que es com patible con otros sistemas.

System.ObsoleteAttribute class
El atributo Obsolete puede ser aplicado a cualquier tipo de C# excepto a ensamblados, mdulos, p ar met ros y valores devueltos. El atributo Obsolete

388

permite definir fragment os de cdigo que se van a re empl aza r o que ya no son vlidos. Las propiedades Message e IsError de la clase Obsolete otorgan el control del modo en el que el c ompi lador controla los tipos m ar c ad os con el atributo Obsolete. Al asignar a la propiedad IsError el valor True. el compi lador produce un error y el mensaje de error es la propi edad de cadena asignada a la propiedad Message. El valor por defecto de la propiedad IsError es Fa 1 se. lo que hace que se pro du zca un aviso cuando se compi la el cdigo. En el siguiente cdigo, el mtodo HelloWorld est marc ad o como Obsolete.
using System; public class RunThis

{
public static void M a i n ( )

{
// Esto genera un aviso de tiempo de compilacin. Consol.WriteLine (HelloWo r1d ( ) ); C o n s o l . R e a d L i n e ();

}
// Marca HelloWord como Obsolete [Obsolete("Next versin uses Helio public static string HelloWorld()

Unive rs e" )]

{
return ("HelloWorld") ;

} } La figura 17.1 muest ra la lista de tareas de los avisos producidos al compilar el cdigo anterior.
lis ta de tareas - 1 tarea(s): Error al generar (filtro) y Descripcin

m m

RunThis,HelloWorld()' esta obsoleto: 'N ext version uses Hello Universe

Z \ Lista de tareas

(-

Figura 17.1. Aviso producido al emplear el atributo obsolete

Si quiere asegurarse de que se produce un error y no solo un mensaje de aviso, puede modi fi car el cdigo marc ado asi gnando a la propiedad IsError el valor true y la clase no se compilar. Si modifica el atributo Obsolete del cdigo anterior con la siguiente lnea, se produce un error:
[Obsolete("Next versin uses Helio Universe", true)]

Como puede ver. el uso del at ri but o Obsolete permite man tene r el cdigo existente mientras nos a se guramos de que los prog ramad ore s no estn usando tipos desfasados.

389

Cmo escribir sus propias clases de atributo


N E T F ramework parte con un buen nmero de clases de atributo que pueden usarse p a r a diferentes propsitos. Sin embargo, podria necesitar un atributo que cumpl iera una funcin no incluida en N E T Framework. Por ejemplo, podra desear disponer de un a tri but o de revisin de cdigo que etiquetara una clase con la fecha de la ltima vez que el cdigo de esa clase fue revisado por sus compae ros. En ese caso, necesitar definir sus propios atributos y hacer que funcionen como cualquier atributo incluido en N E T Framework. Por suerte. NE T Framework admite perfectamente la construccin de nuevas clases de atributos. En esta sec cin apr ender emos cmo el cdigo N E T desarrolla y usa las nuevas clases de atributos. Puede escribir sus propias clases de atributos y usarlas en su cdigo del mismo modo que usara un atributo procedente de N E T Framework. Las clases de atri buto personales funcionan como clases normales; tienen propi edades y mtodos que permiten al usuario del atributo asignar y recuperar datos. Los atributos se implementan con clases de atributo. Las clases de atributo d er i v a n de u n a c las e del e s p a c i o de n o m b r e S y s t e m de N E T l lamada Attribute. Por norma, las clases de atributo llevan antepuesta la palabra

Attribute:
public class CodeAuthorAttribute : Attribute

{ } Esta clase define un a tri but o llamado CodeAuthorAttribute. Este nom bre de atributo puede usarse como un atributo una vez que se ha definido la clase. Si el nombre de atributo t ermina con el sufijo Attribute, el nombre de atribu to puede ser usado entre corchetes o sin el sufijo:
[CodeAuthorAttribute] [C o d e A u t h o r ]

Estos dos atributos hacen referencia a la clase CodeAuthorAttribute. Tr as definir una clase de atributo, se us a como cualquier otra clase de atributo .NET.

Cmo restringir el uso de atributos


Las clases de atributo pueden, a su vez, us ar atributos. El ejemplo ms comn es un atributo llamado AttributeUsage. El atributo AttributeUsage contiene un p ar m et ro que especifica dnde puede usarse un atributo. Algunos atributos pueden no tener sentido en todos los constructores de C # vlidos. Por ejemplo, el atributo Obsolete tratado con anterioridad slo tiene sentido en mtodos. No es lgico m ar c a r u na sola variable como obsoleta, de modo que el

390

atributo Obsolete solamente debe aplicarse a mtodos y no a otros co ns t ru c to res de C#. La clase de atributo AttributeUsage contiene una enumer aci n pblica llamada AttributeTargets. cuyos miembros ap arecen en la tabla 17.1. Estos miembros AttributeTargets pueden apa rec er juntos en una e x presin OR y ser usados como par met ros del atributo AtrributeUsage para especificar que la clase de atributo define un atributo que slo puede usarse en determinados contextos, como mu es tr a el siguiente ejemplo:
[ A t t n b u t e U s a g e (AttributeTargets .Class | A t t r i b u t e T a r g e t s .S t r u c t ) ] public class CodeAuthorAtt r bute : A t t n b u t e

{ } Este constructor declara una clase llamada CodeAuthorAttribute y es pecifica que el atributo slo puede ser usado con clases y estructuras. El compilador de C# le fuerza a usar el atributo par a asegurarse de que se emplea de ac uerdo con los valores de la e numer aci n de AttributeTargets especificados en el atributo AttributeUsage. Si usa un atributo en una e x presin que no est permitida en la definicin del atributo, el compi lador emitir un error. Por ejemplo, suponga que escribe un atributo llamado ame y slo usa la enumer aci n A t t r i b u t e T a r g e t s .Class c omo p a r m e t r o del a tri but o

AttributeUsage:
[At tributeUsage (AttributeTargets.Class) ] public class NameAt t r but e : A t t n b u t e

{ } Si a continuacin intenta aplicar el atributo ame a algo que no sea una clase, el compi lador emitir un mensaje de error parecido al siguiente:
error CS0592: El atributo "ame" no es valido en este declaracin. Solo es vlido en declaraciones "class". tipo de

Cmo permitir mltiples valores de atributo


Tambi n se puede usar el atributo AttributeUsage par a especificar si una clase permite que varias instancias de un atributo sean usadas en un f r agmen to de cdigo C# en particular. Esto se especifica mediante un p armet ro de at ri bu to llamado AllowMultiple. Si el valor de AllowMultiple es True. se pueden usar varias instancias del atributo en un elemento particular de C#. Si AllowMult iple recibe el valor False. slo se puede u sar una instancia en cualquier elemento par ti cular de C# (aunque sigue estando permitido aplicar el atributo a ms de un constructor de C#):

391

[ AttrbuteUsage ( A t t r ib ut eT ar ge ts .elass , AllowMultple public class NameAttr ibute : A t t n b u t e

true) ]

{
public NameAttnbute (stnng ame)

( } } El uso de varios atributos permite asignar varios valores a un constructor de C# usando un solo atributo. El siguiente constructor marca el atributo ame como un atributo de varios usos y permite a los progr amadores usar el atributo ms de una vez en un solo elemento de C#:
[Mame("Jef Ferguson")] [ame("Jeff Ferguson's As si s t a n t " )] public class MyClass

{ } Los atributos de varios usos tambin pueden apa rec er en un solo conjunto de corchetes, s eparados por una coma:
[ame ("Je f f Ferguson") , ame ("Jeff public- class MyClass Ferguson's As sistant") ]

{ } Si no especifica un valor par a el par met ro A l l o w M u l t p l e . no se permite el uso v ariado.

Cmo asignar parmetros de atributo


Sus clases de atributo pueden acept ar parmetros, que aparecen entre parnte sis despus del nombre de atributo. En el ejemplo anterior, el atributo ame recibe una cadena que da nombre al creador de cdigo como parmetro. Algunos atributos necesitan parmetros para asociar los datos al atributo, como la cadena de nombre en el at ri but o ame mos trado anteriormente. Los valores de los par met ros se pasan al constructor de la clase de atributo y la clase de at ri bu to debe i mple me nt ar un co n st ru c to r que pueda recibir los parmetros:
[At t ributeUsage (Attnbut eT ar ge ts .C la ss | A t t n b u t e T a r g e t s .Struct) ] public class CodeAuthorAttr ibute : A t t n b u t e

{
public: CodeAuthorAttr ibute ( s t n n g ame)

{ } }

392

Este atributo necesita que se suministre un p ar met ro de cadena cada vez que es usado:
[CodeAuthor ("Jeff Ferguson") ]

Debe s uministrar los p ar met ros especificados en el const ructor de la clase cuando se usa el atributo. En caso contrario, obt endr un error del compilador:
error CS1S01: Ninguna sobrecarga para el mtodo 'CodeAuthorAttrbute ' adquiere '0' argumentos

Los par met ros proporci onados al constructor de la clase de atributo reciben el nombre de p a r me t ro s p o s i c i o n a l e s . Los par met ros posicionales asocian los datos de par met ro con sus nombres de par met ro basandose en la posicion de los datos en la lista de parmet ros. Por ejemplo, el elemento de datos del segundo par amet ro est asociado a la variable del segundo par met ro especificada en la lista de parmetros de la declaracin de la funcin. Tambin se pueden p ropor ci o n a r p a r m e t r o s co n n o m b r e , q ue son a l m a c e n a d o s p o r las p r o p i e d a d e s implementadas en la clase de atributo. Los p ar met ros con nombre se especifican con el nombre de la propiedad, un signo igual y el valor de la propiedad. Los par met ros con nombre se asocian a datos de par met ros con el nombre del p ar met ro basado en el nombre del p ar met ro que aparece antes del valor. Dado que la asociacin entre un nombre de variable y su valor se especifica mediante el nombre del parmetro y no mediante la posicion del valor en la lista de parmetros, los p ar met ro s con nombre pueden apa rec er en cualquier orden. S up on ga que aade un p ar am et ro con nombre llamado Date al atributo CodeAuthorAt tribute. Esto significa que la clase puede admitir una p r o piedad llamada Date cuyo valor puede asi gnarse en la definicin del atributo:
fAttrbuteUsage (Att ributeTargets.Class | At tributeTargets.Struct) ] public class CodeAuthorAttri bute : At.tri.bute

{
public Co de Au th or At tr ib ut e(str ing ame)

{ }
public strmg Date

{ set { } } } Tras definir la propiedad, un p ar amet ro con nombre puede establecer su p r o piedad cuando el atributo a pa rez ca en el cdigo:
[CodeAuthor("Jeff Ferguson", Date = "Apr 01 2001")]

393

A diferencia de los par met ros posicionales. los par met ros con nombre son opcionales y pueden omitirse de una especificacin de atributo.

Ejemplo explicativo de las clases de atributo


En este a pa rt ado crear un nuevo atributo llamado ClassAuthor y lo usar en cdigo C#. Esto le dar una idea sobre cmo el cdigo N E T define y usa nuevos atributos. El listado 17.3 agrega una nueva clase al cdigo del listado 17.2. Esta nueva clase recibe el nombre de ClassAuthorAttribute y deri va de la clase N E T Attribute.
Listado 17.3. Cmo definir nuevas clases de atributo us ing using using Sys tem; System.Diagnostics ; System.Reflection;

[At tributeUsage ( A t t ributeTargets.Class) ] public class C l a s s A u t h o r A t t n b u t e : Attribute

{
private public; string AuthorName; Clas sAuthor At t r ibute (st ring = AuthorName; AuthorName)

{
t h i s .AuthorName

}
public string Author

{
get

{
return AuthorName;

} } }
[ClassAuthor("Jeff Ferguson")] public class TestClass

{
public void Method! () f r om Method 1 !" ) ;

{
Console . W r i t e L m e ("Hello

[C on di ti onal("DEBUG")] public void Method2()

{
Console . W r i t e L m e ("Hello from Met hod 2 !" ) ;

}
public void M e t h o d 3 ( )

394

{
C o n s o l e . Wr it eL in e("Hello from Method3!");

} }
public class MainClass static void M a i n ( ) = new T e s t C l a s s ();

{
public

{
TestClass MyTestClass

MyTestClass.Methodl ( ); MyTestClass.Method2 ( ); M y T e s t C l a s s . M e t h o d 3 () ; object [ ] ClassAttributes ; Memberlnfo Type Informat 1 o n ; Type Informa1 1 on = typeof (TestClass) ; ClassAttributes = Type Informat 1 o n .GetCustomAttrlbutes (typeof (C 1 assAuthorAttribute) ,

false) ;
ii (ClassAttributes.GetLength(0) !=
0)

{
C 1 as sAutho rAt tribute Clas sAt t r i b u t e ;

C 1assAttribute = (Cl as sA ut ho r A t t r i b u t e ) (ClassAttributes [U] ) ; C o n s o l e .WriteLine ("Class Author: {0}", C 1 a s sA tt ri b u t e . A u t h o r ) ;

1 El codigo de 1 listado 17.3 comienza con una nueva clase de atributo llamada

CodeAuthorAttribute. La clase sirve como una clase de atributo para un


atributo que slo puede aplicarse a otras clases. La clase recibe un par amet ro de cadena, que se al macena en una v ariable priv ada y al que se accede publicamente mediante una propi edad de solo lectura llamada Author. La intencin del p ar amet ro es m ar c ar una clase como poseedora de un nombre de prog ramad or especfico adjunto, de modo que los dems progr amadores sepan con quien deben c ont act ar si tienen al guna duda sobre la implementacion de la clase. La clase TestClass usa el atributo CodeAuthor y proporciona el parametro

Jeff

Ferguson.

L1 rasgo mas interesante del listado 17.3 es el me;t o d o M a i n ( ) . que obtiene un objeto de atributo de la clase y escribe el nombre del autor. Esto lo hace mediante un concepto llamado reflexin, que implementa las clases de un espacio de n o m bres NET llamado System. Reflection. Mediante la reflexin, el cdigo puede, en tiempo de ejecucin, est udi ar la i mplementacin de una clase y descu-

395

brir cmo est construida. La reflexin permite que el cdigo examine otros frag mentos de cdigo p ar a derivar informacin, como los mtodos y propiedades que admite y la clase base de la que deriva. La reflexin es una funcin muy potente y es completamente c ompatible con . NET Framework. El cdigo del listado 17.3 usa la reflexin p ar a obtener una lista de atributos asociados a una clase particular. El cdigo de atributo comienza recuperando un obj et o Type para la clase Tes tciass . Para conseguir el objeto Type se usa el oper ador de C # typeof (). Este oper ador t oma como ar gument o el nombre de la clase cuyo tipo de informacin se va a recuperar. El objeto Type devuelto, que est definido en el espacio de nombre de N E T F ramework System, funciona como una t abl a de contenidos, describiendo todo lo que se debe saber sobre la clase requerida. Despus de r ecuper ar el objeto Type p ar a la clase, el mtodo Main ( ) llama a un mtodo llamado GetCustomAttributes ( ) p ar a conseguir una lista de los atributos que permite la clase descrita por el objeto Type. Este mtodo de vuelve una matriz de objetos y ac ept a como p ar m et ro el tipo del atributo que debe recuperarse. En el listado 17.3, el mtodo GetCustomAttributes ( ) es invocado con informacin de tipo p ar a la clase CodeAuthorAttribute como parmetro. Esto obliga al mtodo GetCustomAttr ibutes ( ) a devol v e r s l o i n f o r m a c i n s o b r e los a t r i b u t o s de c l a s e q u e s e a n del t ipo CodeAuthorAttribute. Si la clase hubiera usado algn otro atributo, la l lamada no podria devolverlos. El cdigo del listado 17.3 finaliza tomando el pri mer atributo CodeAuthorAttribute de la matriz y solicitndole el valor de su propiedad Author. El valor de la cadena se escribe en la consola. Si se ejecuta el cdigo del listado 17.3 se escribe lo siguiente en la consola (si compi la el cdigo sin definir el smbolo DEBUG):
Helio from Methodl! Helio from M e t h o d 3 ! Class Author: Jeff Ferguson

Resumen
N E T F ramework permite u sar atributos en los lenguajes que se ejecutan con el CLR. El concepto de atributo abre la puer ta a la expansin de la funcionalidad de los lenguajes N E T con clases que pueden agr egar comport ami ent os al cdigo. El lenguaje C# permite el uso de atributos creados por otras personas en su cdigo C# y tambin la creacin de atributos propios, que pueden ser usados por otros progr amadores de NET. El concepto de atributo no es exclusivo de C #; ms bien, est disponible para cualquier lenguaje que se ejecute con el CLR. Los atributos le conceden la posibi lidad de extender el entorno del lenguaje y apo rt a nuevas herrami ent as p a r a que los pr og ramad or es trabajen con cdigo NET. El proceso de serializacin es un

396

buen ejemplo de esto. La s ea li z ac in no est integrada en la especificacin del lenguaje C#. pero su funcionalidad est disponible por medio de una clase de atributo escrita por Microsoft. La clase de atributo extiende el lenguaje en tiempo de ejecucin p ar a que admi ta una caracter st ica que no fue diseada en ese len guaje. Al igual que los dems constructores de . NET Framework. los atributos son objetos. Se definen por clases que derivan de la clase S y s t e m .Attribute de N E T Framework. Puede us ar C# p ar a desarrollar nuevas clases de atributo con slo derivar una nueva elase de la clase base S y s t e m .Attribute. Los atri butos que desarrolle en CU y los atributos ya definidos por N E T Framework pueden ser usados por cualqui er lenguaje compatible con el CLR. Los atributos se usan especificando entre corchetes el nombre de clase del atributo, inmediatamente antes del const ructor de CU al que se aplica el atributo. Los atributos pueden ac ep tar datos en forma de parmet ros, que pueden asociar datos de estado al atributo. Estos datos pueden ser recuperados por cdigo de reflexin que puede consul tar el cdigo y bu s ca r atributos.

397

fclfl Cmo utilizar versiones en sus clases


Casi todo el cdigo escrito p a r a las modernas aplicaciones evoluciona con el tiempo. Los proyectos de soft ware comienzan con un conjunto de requisitos y se disean las clases p ar a que cumpl an esos requisitos. Este primer cdigo base sirve como cdigo fuente de la versin 1.0 de la aplicacin. Sin embargo, casi todas las aplicaciones van ms all de la versin 1.0. Las actualizaciones de la aplicacin proceden de un grupo de requisitos mejorado y la versin 1.0 del codigo base debe ser revisada p ar a implementar los requisitos actualizados. El lenguaje C# admite const ructores que hacen las clases lo suficientemente estables como p ar a evolucionar mientras cambi an los requisitos de la aplicacin. En este captulo, aprenderemos a usar las pal abr as clave new y override en mtodos de clase de C# par a as egurarnos de que las clases pueden continuar usndose a medida que cambi an los requisitos de la aplicacin.

El problema de las versiones


Antes de aprender a usar las pal abr as clave new y override para hacer las clases de su cdigo de C# compatibles con el cdigo base que tiene que mant ener se al da con los requisitos de cambio, observe como sera la vida sin estas pala-

399

bras clave. Si recuerda el captulo 8. las clases que creamos y usamos pueden ser consideradas clases base. Estas clases tienen la funcionalidad bsica que necesi tan las aplicaciones. Al declarar una instancia de una clase, est derivando de esa clase para usar su funcionalidad. Las bibliotecas de clases base de N E T Framework estn bas adas en este m o delo; todo lo que hacemos mientras p ro gr amamos aplicaciones N E T est basado en una clase base. Todo el entorno deriva de la clase base System .Ob j ect. de m o d o que i ncl us o c u a n d o d e r i va un a s imp le v a r i a b l e e st d e r i v a n d o una funcionalidad de la clase base System. Object. El listado 18.1 muestra las caractersticas de las clases base y derivadas.
Listado 18.1. Una clase base y una clase derivada using public S ys tem; class BaseClass int Valu;

{
protected public

BaseClass( ) - 12 3;

{
Valu

public

class

DerivedClass PnntValue ( )

: BaseClass

{
public void

{
Consol.WriteLine("Valu = " + Valu);

} }
class MamClass static void M a i n ( ) D e r i v e d C l a s s ();

{
public

{
DerivedClass DerivedC1assObject = new D e n v e d C l a s s O b j e c t .P n n t V a l u e ( );

} } El cdigo del listado 18.1 es relativamente sencillo. Contiene una clase base l lamada BaseClass que i ncl ine una variable entera protegida. Ot ra clase, lla mada Der ivedCl ass. deriva de la clase BaseClass e iniplementa un mt o do llamado P n n t V a l u e ( ) . El mtodo Main ( ) crea un objeto de tipo DerivedClass y llama a su mtodo PrintValue ( ) . Si se ejecuta el codigo del listado 18.1 se escribe lo siguiente en la consola:
Valu = 12

400

Ahora suponga que los requisitos cambian y otro p rog ra ma do r decide de sa r ro llar la clase BaseClass mientras cont inuamos t rabaj ando en nuevas mejoras par a la clase De r ivede 1 as s . Qu ocurrir si el otro p ro gr amado r agrega un mtodo a la clase BaseClass llamado PrintValue ( ) y propor ci ona un implementacin ligeramente diferente? El cdigo seria como el listado 18.2.
L istad o 18.2. Adicin de PrintValue() a la clase BaseClass using System; public c 1 a s s BaseClass in t Valu;

{
prote cted public

BaseClass( ) - 123;

Valu

}
public virtual void PrintValue( ) " + Valu) ;

I
Consol . W r i t e L m e ("Valu:

( }
public class DerivedClass PrintValue( ) = " + Valu) ; : BaseClass

(
public void

{
Consol.WriteLine ("Valu

} }
class MamClass static void M a m ( ) DerivedClassObject = new DerivedClass () ;

{
public

{
DerivedClass

DerivedClassObject.PrintValue ( );

} } Ahora tenemos un problema. La clase DerivedClass deriva de la clase BaseClass y a mbas implementan un mtodo llamado PrintValue (). La clase BaseClass ha sido actualizada a una nueva versin, mientras que la clase DerivedClass ha p er maneci do con su i mplementacin original. En el listado 18.2. la relacin entre el mtodo PrintValue ( ) de la clase base y el mtodo PrintValue ( ) de la clase derivada no est clara. El compi lador debe saber que mtodo reemplaza a la versin de la clase base. Y el compi lador no sabe que

401

i mple me nt aci n debe ej ec ut ar cu a nd o el mt odo Main ( ) l lama al mtodo

P r i n t V a l u e ().
Como resultado, el compi lador de C# remarca esta a mbi gedad con un aviso:
w a r m n g CS0I14: 'De r i vedCl as s .Pr int Va le ( ) ' oculta el miembro heredado 'BaseClass.PrintValue ( ) ' . Para hacer que el mtodo actual reemplace esa implementacin, agregue la palabra clave override. De lo contrario, agregue la palabra clave new.

Este es un buen aviso, porque la filosofa del lenguaje C# fomenta la claridad y el compi lador de C # siempre avisa sobre los constructores de cdigo que no estn claros.

Cmo solucionar el problema de las versiones


C# tiene dos modos de s olucionar la a mbi gedad del listado 18.2: Usar el modificador new p a r a especificar los dos mtodos que. en reali dad. son diferentes. Usar el modi fi cador overr ide par a especificar que el mtodo de la clase derivada debe reempl azar al mtodo de la clase base. Exami nemos estos dos mtodos.

Mediante el modificador new


Si las dos implementaciones de mtodo del listado 18.2 deben ser tratadas como mtodos separados que simplemente tienen el mi smo nombre, el mtodo de la clase derivada debe llev ar ant epuest o el modi fi cador new. Al usar el modifica dor new, p u e d e o c u l t a r e x p l c i t a m e n t e los m i e m b r o s h e r e d a d o s de la i mplementacin de la clase base. Simplemente debe dec la rar un mi embro en su clase derivada con el mismo nombre y ant eponer a la declaracin el modificador new y se usar la funcionalidad de la clase derivada, como muest ra el listado 18.3.
Listado 18.3. C mo resolver la ambig edad mediante la palabra reservada new using public System; class BaseClass int Valu;

{
protected public

BaseClass( )

402

{
Value = 12 3;

}
public void PnntValue ( )

{
Console .W r i t e L m e ("Value : " + Value) ;

} }
pu b l i c class DerivedClass : BaseClass

{
new public void PnntValue ( ) = " + Value);

{
Console . W r i t e L m e ("Value

) }
class MainClass static void M a i n ( ) DerivedClassObject - new DerivedClass ( );

{
public

(
DerivedClass

Derived Class Ob ject ,P n n t V a l u e ( );

NOTA: El operador new y el modificador new son implementaciones di ferentes de la palabra clave new. El operador new se usa para crear ob jetos, mientras que el modificador new se usa para ocultar un miembro heredado de un miembro de clase base.
El codigo del listado 18.3 usa la pal abra clave new en la i mplement aci n del mt odo Pr intValue () de la clase Der ivedCia.ss. Esto indica al compilador de C# que debe t rat ar este mtodo como distinto del mtodo de la clase base, aunque los dos mtodos tengan el mismo nombre. El uso de la p al ab ra clave resuelv e la a mbi gedad y permite que el c ompi lador de C# compile el eodigo sin emitir advertencias. En este caso, el mtodo Main () llama al mtodo de la clase derivada y el listado 18.3 escribe lo siguiente en la consola:
Valu = 12 3

Todav a puede ejecutar el mtodo de la clase base porque la pal abra clave new ha as egu rad o b si cament e que los dos mtodos P r i n t V a l u e ( ) de cada una de las clases puede ser llamado por separado. Puede llamar al mtodo de la clase base conv irtiendo explcitamente el objeto de la clase deriv ada en un objeto de tipo de la clase base:

403

BaseClass

BaseClassObject

(BaseClass)DerivedClassObject;

B a s e C l a s s O b j e c t .PrintValue ( );

C omo puede ver. el uso del modi fi cador new solamente permite reemplazar la funcionalidad en una clase base. Si necesita usar la funcionalidad de la clase original, use el nombre de la clase completo y su ruta de acceso con el miembro de la clase p a r a estar seguro de que est us ando la funcionalidad correcta.

Mediante el modificador override


La otra opcin par a resolver la a mbi gedad con los nombres de mtodo dupli cados es u sar el modificador override par a especificar que la implementacin de la clase derivada reemplaza a la implementacin de la clase derivada. El modi ficador override "reemplaza" la funcionalidad del mi embro de la clase base al que sustituye. Para reempl azar a un mi embro de una clase, la firma del mi embro que reem plaza debe ser la mi sma que el miembro de la clase base. Por ejemplo, si el mi embro que realiza el reemplazo tiene un constructor, los tipos en el constructor deben coincidir con los del mi embro de la clase base. En el listado 18.4 puede ver el f unc iona mie nto del mo di fi cado r override.
Listado 18.4. Cmo resolver la ambigedad mediante el modificador override us m g public Sys t em; class BaseClass int Valu;

{
protected public

BaseClass( ) = 12 3;

{
Valu

}
public virtual void PrintValue( ) " + Valu);

{
Consol . W n t e L m e ("Valu:

} }
public class DerivedClass void : BaseClass

{
override public PrintValue( ) = " + Valu);

{
C o n s o l e . W n t e L m e ("Valu

404

class

HamClass static void M a i n ( ) DerivedClassOb]ect = new DerivedClass () ;

{
public

{
DerivedClass

Der ivedC 1 assOb j ect .P n n t V a l u e () ;

} } En el listado 18.4. la pal abr a clave override indica al compi lador de C# que la i mplement aci n de PrintValue ( ) en la clase derivada reemplaza a la implementacin del mismo mtodo en la clase base. La implementacin de la clase base est oculta bsi cament e a los invocadores. A diferencia del listado 18.3. el cdigo del listado 18.4 slo contiene una implement aci n de PrintValue (). La implementacin de la clase base de PrintValue ( ) no es accesible al cdigo del mt odo Main () incluso si el cdigo convierte explcitamente el obje to de la clase derivada en un objeto de clase base y llama al mtodo en el objeto de la clase base. Debido a que la p al ab ra clave override se usa en el listado 18.4. todas las l lamadas al mtodo realizadas mediante un objeto convertido expl citamente son dirigidas a la i mplementacin reempl aza da de la clase derivada. Observe el cdigo us ado en la llamada a la implementacin de la clase base de PrintValue ( ) cuando se usa el oper ador new p a r a resolver la ambigedad:
BaseClass BaseClassObject = (BaseClass)D e n v e d C l a s s O b ] e c t ;

BaseClassObject.PrintValue ( );

Este cdigo no es suficiente p ar a hacer que se llame a la implementacin de la clase base cuando se use la pal ab ra clave override. Esto es debido a que el objeto fue creado como un objeto de la clase DerivedClass. Puede llamar al mtodo de la clase base pero, debido a que la implementacin de la clase base ha sido reempl aza da con el cdigo de la clase derivada, se seguir i nvocando a la implementacin de la clase derivada. Debe us ar la p al ab ra clave de C# base p a r a llamar a la implementacin de la clase base, como en el siguiente ejemplo:
base.PrintValue ( );

Esta instruccin llama a la implementacin de PrintValue ( ) que se e n cuentra en la clase base de la clase actual. Al colocar esta instruccin en la clase DerivedClass, por ejemplo, se llama a la implementacin de PrintValue ( ) que se encuent ra en la clase BaseClass. Puede considerar el uso de la p al abr a clave b a s e i g u al al u s o de la s i n t a x i s c o m p l e t a y con r u t a de a c c e s o namespace .ob j e c t .method. a mbas simplemente hacen referencia a la ins t ancia de clase base correcta que se est usando.

405

Resumen
Los ejemplos de este captulo situaban j unt as todas las clases del listado en un nico archivo fuente p a r a hacerlos ms sencillos. Sin embargo, la programaci n en el mundo real puede ser ms complicada. Si varios progr amadores estn t r aba j a nd o en un nico provecto, el provecto podra estar formado por ms de un archivo fuente. El p rog ramado r que t rabaja en la clase base podra colocarla en un archivo fuente de CU y el pr og r am ad or que t rabaj a en la clase derivada puede colocarla en otro archivo fuente de C#. El asunto podra ser aun ms complicado si la clase base se compila en un ensambl ado y se implcmenta la clase derivada en un provecto que hace referencia al ensamblado. Lo importante en este caso es que las clases base y las clases deriv adas pueden proceder de varias fuentes diferentes y que coordinar la progr amaci n de las clases cobra una gran importancia. Es de vital importancia comprender que. con el tiempo, las clases base y las clases deriv adas aadirn funcionalidades a medi da que el provecto progrese. C omo progr amador, debera tener esto en cuenta: disee sus clases de modo que pueden ser usadas en varias versiones de un provecto y puedan ev olucionar a medida que evolucionen los requisitos del p ro vecto. A priori. la otra solucin par a los problemas que presentan las versiones es i n cl us o mas sencillo: no use el m i sm o n o m b r e p a r a m t o do s que tengan i m pl e me n t a c i o n e s d ifer ent es a menos que est r e e m p l a z a n d o re al men te la funcionalidad de la clase base. Aunque, en teora, ste puede parecer el mejor medio para solventar el problema, en la practica no siempre es posible. Las pal a bras clave de CU now y o ve r ri d e le ayudan a evitar este problema de pr og ra macin y le permiten reutilizar nombres de mtodos en caso de que sea necesario para su provecto. El principal uso de la pal abra clave o ve rr i de es avisar de la creacin de nuevas i mplementaciones de mtodos virtuales en clases base, pero tambin tiene un papel en las versiones de CU.

406

19 Cmo trabajar con cdigo no seguro


Al usar la pal abra clave n e w para crear una nueva instancia de un tipo de referencia, est pidiendo al C LR que reserv e suficiente memoria para la v ariable. El C LR asigna suficiente espacio en la memoria para la variable y asocia la memoria a la variable. En condiciones normales, el codigo desconocera la local i zacion actual de esa memoria, por lo que respecta a la direccin de memoria. Despus de que la operacion n e w tenga xito, el codigo puede usar la memoria asignada sin saber ni importarle en que parte del sistema est realmente situada la memoria. En C y C ++. los progr amadores tienen acceso directo a la memoria. Cuando un fragmento de cdigo de C o de C ++ solicita acceso a un bloque de memoria, se le otorga la direccin especfica de la direccin asi gnada y el cdigo lee y escribe directamente en esa posicin de memoria. La ventaja de este enfoque es que el acceso directo a la memori a es ext remadament e rpido y contribuye a la eficien cia del codigo. Sin embargo, hay algunos inconvenientes que superan a las vent a jas. El probl ema de este acceso directo a la memoria es que es fcil usarlo incorrectamente v esto hace que el cdigo falle. Un mal funcionamiento del codigo de C o C++ puede fcilmente escribir en la memoria de otra variable. Estos probl emas de acceso a memori a producen numerosos fallos y errores de software difciles de localizar. La arquitectura del C L R elimina todos estos problemas rea lizando toda la gestin de memoria por nosotros. Esto significa que su codigo de

409

C# puede t ra ba j ar con variables sin que necesitemos conocer los detalles de cmo y dnde se al macenan las variables en memoria. Como el C L R protege al cdigo de C# de estos detalles de la memoria, el cdigo de C# est libre de errores relacionados con el acceso directo a la memoria. No obstante, alguna vez tendr que t ra ba j ar con una direccin de memoria especifica del cdigo C#. El cdigo puede necesitar un poco ms de rendimiento o quizas el cdigo de C# quiera t raba jar con cdigo heredado que necesite que le proporci one la direccin de un fragment o de memori a especfico. El lenguaje C# admite un modo especial, llamado modo no s e g u r o . que permite t rabaj ar directa mente con memori a desde el interior del cdigo C#. Este const ructor de C# especial recibe el nombre de modo no seguro porque el cdigo ya no dispone de la proteccin que ofrece la gestin de memori a del CLR. En el modo no seguro, el cdigo de C# puede acceder directamente a la memoria y puede tener los mismos fallos relacionados con la memori a que los cdigos de C y C ++ si no es ext remadament e cui dadoso con su for ma de gestionar la memoria. En este captulo, est udi aremos el modo no seguro del lenguaje C# y como puede ser us ado par a permitirle acceder directamente a las direcciones de memo ria usando constructores de estilo puntero de C y C++.

Conceptos bsicos de los punteros


En C# se accede a la memori a usando un tipo de dato especial llamado p u n tero. Un puntero es una variable cuyo valor a pun ta a una direccin especfica de la memoria. En C#. un puntero se declara con un asterisco situado entre el tipo del puntero y su identificador. como se mu es tr a en la siguiente declaracin:
int * My ln te gerPointer;

Esta instruccin declara un puntero entero llamado M y l n t e g e r P o i n t e r . El tipo del puntero indica el tipo de la variable a la que el p untero puede apuntar. Por ejemplo, un puntero entero slo puede a pu nt ar a memori a us ada por una variable entera. Los punteros deben ser asignados a una direccin de memoria y C# hace que sea fcil escribir una expresin que evale la direccin de memoria de una variable. Si se antepone el operador de concatenacin, el smbolo de unin, a una expresin uara, devuelve una direccin de memoria, como mues tra en el siguiente ejemplo:
int int Mylnteger = 123; * MylntegerPointer = SMylnteger;

El cdigo anterior hace dos cosas: Declara una variable entera llamada M y l n t e g e r y le asigna el valor 123.

410

Declara una variable entera llamada MylntegerPointer y la apunta en la direccin de la variable Mylnteger. La figura 19.1 mues tra cmo se interpreta esta asignacin en memoria.

Mylnteger

123

MylntegerPointer

Figura 19.1. Un puntero apuntando a una variable

Los punteros en realidad tienen dos valores: El val or de la direccin de memori a del puntero El valor de la variable a la que a pu nt a el puntero C # permite escribir expresiones que evalen cualqui era de los dos valores. Si se antepone un asterisco al identifcador del puntero se obtiene el valor de la variable a la que ap un t a el puntero, como demu es tra el siguiente cdigo:
int int Mylnteger = 123; * MylntegerPointer - SMylnteger;

Consol .W r i t e L m e (MylntegerPointer) ;

Este cdigo escribe en la consola 12 3 .

Tipos de puntero
Los punteros pueden tener uno de los siguientes tipos:

sbyte byt e short ushort int

uint

411

lo n g

ulong char float double


dec: ima 1

boo 1
un tipo de enumeracin

void. usado par a especificar un puntero par a un tipo desconocido


No se puede declarar un puntero p ar a un tipo de referencia, como un objeto. La memori a par a los objetos est gestionada por el C L R y la memoria puede ser b or r ada cada vez que el recolector de elementos no utilizados necesite liberar la memori a del objeto. Si el compi lador de CU le permite mant ener un puntero sobre un objeto, su cdigo corre el riego de ap un tar a un objeto cuya memoria puede ser liberada en otro punto por el recolector de elementos no utilizados del CLR. Imagine que el compi lador de CU permitiese escribir cdigo como el siguiente:
MyClass MyClass MyObject = new MyClass ( ); * MyOb] e c t P o m t e r ; = SMyObject;

MyObj ectPo.i nter

La memoria usada por MyObj ect es gestionada aut omt icamente por el CLR v su memori a es liberada cuando todas las referencias al objeto se liberan y se ejecuta el recolector de elementos no utilizados del CLR. El probl ema es que el codigo no seguro ahora contiene un puntero al objeto y el resultado es que tiene un puntero que apunt a hacia un objeto cuya memoria se ha liberado. El C L R no tiene ningn modo de saber que hay un puntero par a el objeto y el resultado es que. despus de que el recolector de elementos no utilizados haya liberado la memoria, tiene un puntero apun tand o hacia la nada. C# solventa este problema no permi tiendo que existan variables a tipos de referencia con memoria que es gestionada por el C LR

Cmo compilar cdigo no seguro


Por defecto, el compi lador de CU slo compila cdigo seguro de CU. Para obligar al compi lador a compi lar cdigo de CU no seguro debe us ar el argumento del c om pi l ado r /unsafe:
ese /unsafe filel.es

412

El cdigo no seguro permite escribir cdigo que acceda di rectamente a la m e moria. sin hacer caso de los objetos que gestionan la memoria en las aplicaciones. Como a las direcciones de memori a se accede directamente, el codigo no seguro puede funcionar mejor en algunos tipos de aplicaciones. Esta instruccin compila el archiv o fuente f i l e .es y permite compi lar el codigo no seguro de C#.

NOTA: En C#, el cdigo no seguro permite declarar y usar punteros del mismo modo que en C++.

Cmo especificar punteros en modo no seguro


El compi lador de C# no permite por defecto usar punteros en el cdigo C#. Si intenta t rabaj ar con punteros en su cdigo, el compilador de C# emitir el siguien te mensaje de error:
error CS214: Los punteros contexto no seguro solo se pueden utilizar en un

Los punteros slo son vlidos en C# en cdigo no seguro y hay que definir explcitamente el cdigo no seguro al compilador. Para hacerlo se emplea la p a l a bra clave de C # unsafe. La pal abr a clave unsafe debe aplicarse a un bloque de codigo que use punteros. P ar a especificar que un bl oque de codigo se ejecute en el modo no seguro de C# se aplica la pal abr a clave unsafe a la declaracin del cuerpo de codigo. como se muest ra en el listado 19.1.
Listad o 19.1. Mtodos no seguros using public System; class MyClass unsafe static void Maini)

{
public

{
int Mylnteger = 123; int * MylntegerPointer = iMylnteger;

C o n s o l . W n t e L i n e (*MyIntegerPonter) ;

} } El mtodo Main ( ) del listado 19.1 usa el modi fi cador unsaf e en su d ec la racin. Esto indica al compi lador de C# que todo el cdigo del mtodo debe ser considerado no seguro. Despus de us ar esta pal ab ra clave, el cdigo del mtodo puede us ar constructores de puntero no seguros.

413

La palabra clave unsafe se aplica slo al mtodo en el que aparece. Si la clase del listado 19.1 va a contener otro mtodo, esc otro mtodo no podr usar constructores de puntero no seguros a menos que. tambin, sea declarado con la p al abr a clave unsafe. Las siguientes reglas se aplican al modificador unsafe. Clases, est ructuras y delegados pueden incluir el modi fi cador unsafe. que indica que todo el cuerpo del tipo se considera no seguro. Campos , mtodos, propiedades, eventos, indizadores, operadores, cons tructores. destructores y constructores estticos pueden definirse con el modi fi cador unsafe, que indica que la declaracin del miembro especifi co no es segura. Un bloque de cdigo puede ser m a r c ad o con el modi fi cador unsafe. que ndica que todo el cdigo debe ser consi derado no seguro.

Cmo acceder a los valores de los miembros mediante punteros


El modo no seguro de C# permite usar el operador - > p ar a acceder a los miembros de las estructuras a las que hace referencia el puntero. El operador, que se escribe como un guin seguido por el smbolo m ayo r que. le permite acceder directamente a los miembros, como se mu es tra en el listado 19.2.
Listado 19.2. Cmo acceder a los miembros de una estructura con un puntero usmg public System; struct Point2D

{
public public int X; int Y;

}
public class MyClass unsafe static void M a i n ( )

(
public

{
Pomt2D Pomt2D MyPoint; * PointerToMyPoint ;

MyPoint = new P o m t 2 D ( ) ; PointerToMyPoint = S M y P o m t ; P o i n t e r T o M y P o m t - > X - 10 0; P o i n t e r T o M y P o m t - > Y - 200 ; Consol . W r i t e L m e ("({ 0 } , {1})", PomterToMyPomt->Y) ;

PointerToMyPoint->X ,

} }

414

El listado 19.2 contiene la declaracin de una est ructur a llamada Point2D. La e st ruc tur a tiene dos miembros pblicos. El listado tambin incluye un mtodo no seguro Main ( ) que crea una nueva variable del tipo de la est ructura y crea un puntero p ar a la nueva estructura. A continuacin, el mtodo usa el oper ador de acceso a miembros del puntero par a asignar valores a la estructura, que se escribe en la consola. Esto es diferente del acceso a mi embro s del modo seguro, por defecto, de C#. que u sa el oper ad or .. Si se usa un o per ador incorrecto en un modo incorrecto, el compi lador de C# emite un error. Si usa el oper ador . con un puntero no seguro, el c ompi lador de C# emite el siguiente mensaje de error:
error CS0023: El operador del tipo 'Point2D*' no se puede aplicar a operandos

Si se usa el oper ador - > en un contexto seguro, el compi lador de C# tambin emite un mensaje de error:
error CS0193: El operador * o -> se debe aplicar a un puntero

Cmo usar punteros para fijar variables a una direccin especfica


C uando el C L R gestiona la memoria de una variable, el codigo t rabaj a con una variable y los detalles sobre la memori a de la variable son controlados por el CLR. Durant e el proceso de recoleccin de elementos no utilizados del CLR. el tiempo de ejecucin puede ca mb ia r la memori a de lugar varias veces par a af ia n zar la pila de memori a disponible en tiempo de ejecucin. Esto significa que durante el curso de una aplicacin, la direccin de memori a p ar a una variable puede cambiar. El C L R puede t omar los datos de la variable y moverlos a una direccin diferente. En condiciones normales, el cdigo de C# no tiene en cuenta esta tcnica de recolocacin. C mo el cdigo t rab aj a con un identificador de variable, n o rm al mente acceder a la memori a de la variable mediante el identificador de la v a r i a ble y puede confiar en que el C L R trabaje con el fragment o de memori a correcto mientras t rabaj a con la variable. Sin embargo, la situacin no es tan sencilla cuando se t rabaj a con punteros. Los punteros a punt an a una direccin de memori a especfica. Si asigna un pun te ro a una direccin de memori a us ada por una variable y el C L R despus mueve la direccin de memoria de esa variable, su puntero estar apunt ando a una memoria que ya no est siendo us ada por la variable. El modo no seguro de C# permite especificar una variable como excluida de la recolocacin de memori a del CLR. Esto permite mant ener una variable en una direccin especfica de memoria, lo que le permite us ar un puntero con la variable

415

sin p re ocupar se de que el C'LR p ueda mov er la direccin de memori a de la v aria ble de la direccin a la que a punt a su puntero. Para especificar que la direccin de memoria de una variable debe ser fija se usa la pal abr a clave de C# f ized. La pal abra clave f ized va seguida de una expresin entre parntesis que contiene una declaracin de puntero con una asignacin a una variable. La expresin fija da va seguida de un bloque de cdigo y la variable fijada permanece en la misma direccin de memori a a lo largo del bloque de cdigo fijado, como se muest ra en el listado 19.3.
Listado 19.3. Cmo fijar en memoria los datos gestionados u sin g S y s t e m ; p u b 1 ic r ;1a s s M y C 1 a s s

p u b 1ic unsafe static void M a i n ( )

I
mt int Ai r ay Index ; [ ] IntegerArray;

IntegerArray - new m t [5] ; f ized !m t * I n t e g e r P o m t e r = IntegerArray)

I
for (Arraylndex. - 0; Arraylndex < 5; Ar r ay Index + + ) IiiteqerPointer [Airaylndex] = Arraylndex;

)
for (Arraylndex - 0; Arraylndex < 5; Arraylndex + +J Conso 1e .Wr 1 1 c L m e (IntegerArray [Arraylndex] ) ;

La palabra clav e f ized del listado 19.3 declara un puntero entero que apunta a una matriz entera. Va seguida por un bloque de codigo que escribe valores en la matriz usando un puntero. Dentro de este bloque de cdigo, est g ar ant izado que la direccin de la matriz IntegerArray es fija y que el C L R no mover su posicin. Esto permite al cdigo usar un puntero con la matriz sin preocuparse de si el C L R va a mover la posicion de la memoria fsica de la matriz. Despus de que el bloque de codigo fijado termine, ya no puede usarse el puntero y el CLR vuelve a tener en cuenta a la variable IntegerArray cuando reubica la memo ria.

Sintaxis del elemento de matriz puntero


El listado 19.3 tambin muest ra la sintaxis del elemento de matriz puntero. La siguiente lnea de codigo t rata un puntero de modo no seguro como si fuera una matriz de bytes:
I n t e g e r P o m t e r [Arraylndex] = Arraylndex;

416

Esta linca de cdigo t rata al puntero como si fuese una matriz. La sintaxis del elemento de matriz puntero permite al cdigo de C# no seguro ver la memoria a la que a punt a el puntero como una matriz de variables en la que se puede escribir y leer de ella.

Cmo comparar punteros


El modo no seguro de C# permite c o m pa r ar punteros usando los siguientes operadores: Igualdad (==) Desigualdad (!=) Menor que (<) Mayo r que (>) Menor o igual que (<^) May or o igual que ( > - ) Al igual que los tipos de valores, estos operadores devuelven los valores bool eanos True y False cuando se usan con tipos de puntero.

Clculo con punteros


Se pueden c ombi nar punteros con valores enteros en expresiones matemt icas par a c ambi ar la posicin a la que a pun ta el puntero. El operador + s uma un valor al puntero y el oper ador - resta un valor del puntero. La instruccin f ixed del listado 19.3 tambin puede escribirse como se indica a continuacin:
fixed ( m t * IntegerPointer = IntegerArray) < 5; ArrayIndex ++ ) = Arraylndex;

{
for ( ArrayIndex = 0; Arraylndex *( IntegerPointer + Arraylndex)

} En este bloque de cdigo, el puntero es despl azado por un valor y la s uma se usa par a a pun ta r a una direccin de memoria. La siguiente instruccin realiza aritmtica de puntero:
* (IntegerPointer + Arraylndex) = Arraylndex;

Esta instruccin debe interpretarse como: " Toma el valor de IntegerPo inter e i n c r e m n t a l o en el n m e r o de p o s i c i o n e s e s p e c i f i c a d a s por Arraylndex. Col oca el valor de Arraylndex en esa posicin". La aritmtica de punt ero aument a la posicin de un puntero en un nmero especificado de bytes, dependiendo del t ama o del tipo al que se est apuntando.

417

El listado 19.3 declara una matriz entera y un puntero entero. Cuando se usa aritmtica de puntero en el puntero entero, el valor usado par a modificar el punte ro especifica el nmero de t a maos de variable que deben moverse, no el numero de bytes. La siguiente expresin usa aritmtica de puntero para despl azar la loca lizacin de un puntero en tres bytes:
IntegerPointer + 3

El valor literal 3 de esta expresin especifica que se debe incrementar el puntero en el espacio que o cupan tres nmeros enteros, no en tres bytes. Dado que el puntero a punt a a un nmero entero, el 3 se interpreta como "espacio nece sario par a tres nmeros enteros" y no "espacio p ar a tres bytes". Dado que un numero entero ocup a cuatro bytes de memoria, la direccin del puntero se a u menta en doce bytes (tres nmeros enteros multiplicado por cuatro bytes por cada numero entero), no en tres.

Cmo usar el operador sizeof


Se puede usar el operador s i z e o f en modo no seguro par a calcular el nu mero de bvtes necesarios par a contener un tipo de datos especfico. El operador va seguido por un nombre de tipo no admi ni strado entre parntesis y la expresin da como resultado un numero entero que especifica el nmero de bytes necesa rio para contener una variable del tipo especificado. La tabl a 19.1 enumera los tipos administrados admitidos y los valores que devuelve una operacin s i z e o f .
Tabla 19.1. Tipos sizeof() admitidos

Expresin
sizeof(sbyte) sizeof(byte) sizeof(short) sizeof(ushort) sizeof(int) sizeof(uint) sizeof(long) sizeof(ulong) sizeof(char) sizeof(float) sizeof(double) sizeof(bool)

Resultado
1 1 2 2 4 4 8 8 2 4 8 1

418

Cmo asignar espacio de la pila para la memoria


C# proporciona un sencillo mecani smo de asignacin de memoria en cdigo no seguro. Puede solicitar memori a en modo no seguro usando la p al ab r a clave de C# stackalloc. como se mues tra en el listado 19.4.
L istado 19.4. Cmo asignar espacio de la pila para la memoria using public System; class MyClass unsafe static void M a i n ( ) = stackalloc int [5];

{
public

{
int int * CharacterBuffer Index;

for (Index = 0; Index < 5; Index++) CharacterBuffer[Index] = Index; for(Index = 0; Index < 5; Index++) Consol.WriteLine (CharacterBuffer[Index] ) ;

} } Tras la palabra clave stackalloc se escribe un tipo de dato. Devuelve un puntero al bloque de memori a al que se le asigna el espacio y se puede usar la memori a exact ament e igual que la memori a gest ionada por el CLR. No hay una operacin explcita par a liberar la memoria asignada por la p a l a bra clave stackalloc. La memoria se libera aut omt icame nte c uando finaliza el mtodo que asign esa memoria.

Resumen
El modo no seguro de C# permite a su codigo t raba jar directamente con la memoria. Su uso puede mej orar el rendimiento porque el cdigo accede di rec ta mente a la memoria, sin tener que moverse con cuidado por el CLR. Sin embargo, el modo no seguro puede ser peligroso y puede hacer que el codigo falle si no t rabaj a adecuadament e con la memoria. En general, evite el uso del modo no seguro de C#. Si necesita un poco ms de rendimiento p ar a su cdigo o si est t raba jando con cdigo heredado de C o C ++ que necesita que especifique una posicin de memoria, siga con el modo seguro que se ofrece por defecto y deje que el C L R gestione los detalles de la asignacin de memoria.

419

La p eque a reduccin en el rendimiento que se produc e es c omp en sa da con creces por no tener que realizar la pesada tarea de gest ionar la memori a de su cdigo y por conseguir la posibilidad de escribir cdigo libre de errores relaciona dos con la gestin de memoria.

420

Constructores avanzados de C#
En este captulo exa mi na remos algunas facetas interesantes del lenguaje C#. Ta mb i n veremos algunos ejemplos de cdigo y apr end er emo s por qu el codigo funciona como lo hace. La c omprensin de p robl emas de p r og ramaci n como los presentados en este captulo le a yu da rn a enfrentarse a sus propias dudas sobre pr ogr amaci n en C#. En primer lugar, observe la funcin de conversin implcita de C# y como se aplica a objetos de clases derivadas a las que se accede como objetos de la clase base de la clase derivada. Recuerde que puede escribir mtodos de operadores implcitos que definan c mo se gestionan las conversiones implcitas de un tipo u otro; pero, como ver, las cosas se vuelven un poco ms compl icadas cuando se t rabaj a con tipos de tiempo de ejecucin y de tiempo de compilacin. A continuacin, nos adentr aremos en la inicializacin de estructuras. Las es tructuras. al igual que las clases, pueden contener campos y propiedades. Sin embargo, la inicializacin de est ructur as con campos se realiza de forma ligera mente diferente a la inicializacin de est ructuras con propiedades. En este c a p tu lo, descubri r por que y cmo resolver este problema. En la t ercera parte de este captulo, investigaremos el paso de un objeto de una clase derivada a una llamada de mtodo en el que se espera un objeto de una clase base. Dado que los objetos de las clases derivadas son inherentemente objetos de la clase base, p a sa r un objeto de clase derivada a un elemento que espera una

423

clase base puede parecer bastante sencillo. En este apart ado estudiaremos por qu esta tcnica no es tan simple como podra parecer. Finalmente, nos adentr aremos en el uso a va nzad o de los indizadores de clase. En la inmensa mayora de los casos, los indizadores que escriba servirn para hacer que una clase se comport e como una matriz de elementos. Por lo general, las matrices aceptan valores enteros como p ar a especificar el elemento del ndice. En este a pa rt ad o estudiaremos la tcnica de usar tipos de datos distintos de ente ros par a los ndices de matriz.

Operadores implcitos y conversiones no vlidas


Recuerde que las clases pueden contener un cdigo de conversin de op er ad o res implcitos. Los operadores implcitos se usan p ar a convertir un tipo en otro sin ningn cdigo especial. En el lenguaje C# se crean muchas conversiones im plcitas. Por ejemplo, un entero puede ser convertido implcitamente en un entero lonq sin ningn codigo especial:
Mylnt - 12 3; lonq MyLonglnt = Mylnt;

C# no define conversiones implcitas p ar a todas las combinaciones existentes de tipos de datos Sin embargo, puede escribir cdigo de conversin de oper ado res implcitos que indique al entorno c omn de ejecucin (CLR ) cmo debe com port arse cuando un usuario de la clase intente hacer una conversin implcita entre la clase y otro tipo. En este apa rt ado estudiaremos una faceta del operador de conversin implcita que t rat a con la conversin entre dos clases diferentes. El listado 20.1 contiene dos clases: TestClass y MainClass. La clase MainClass contiene el mtodo Main ( ) de la aplicacin. La clase TestClass contiene una variable privada de tipo MainClass. Ta mb i n define un mtodo de o p e r a d o r i mpl ci to que c onv ie r te los ob jet os T e s t C l a s s en objetos MainClass. La i mplementacin de o per ado r implcito devuelve una referencia al objeto privado MainClass del objeto TestClass.
Listado 20.1. E xcepciones a las conversiones invlidas con operadores implcitos public class TestClass MyMai nC la ss Ob je ct ;

{
prvate public MainClass TestClass( ) = new MainClass ( );

{
MyMainClassOb]ect

424

public

static

implicit

operator M a m C l a s s ( T e s t C l a s s

Source)

{
return Source. M y M a m C 1 assOb] ect;

} }
public class MainClass static void M a i n ( )

(
public

{
ob]ect MyOb]ect; M a m C l a s s MyMainClassOb]ect ; MyObject - new T e s t C l a s s (); M y M a m C l a s s O b j ect = (MainCl ass )MyObj ect ;

} } El cdigo del m t o d o M a i n () crca un nuevo objeto Tes te 1ass y convierte explcitamente el objeto en otro objeto de tipo MainClass. Como en TestClass se define un o per ador implcito, esta conversin debe tener xito. Sin embargo, si ejecuta el listado 20.1. recibir el siguiente mensaje en la consola:
Excepcin no controlada: System.InvalidCastException: conversin especificada no es valida, at M a i n C l a s s . M a i n () La

Por qu el C L R considera que la conversin es invalida, incluso cuando se define un oper ado r implcito.) El p rob lema aqu es que la conversin funciona entre tipos de tiempo de compilacin, no entre tipos de tiempo de ejecucin. El mtodo Main ( ) crea un nuevo objeto de tipo TestClass y asigna el nuevo objeto a la variable de tipo object. A continuacin, esta variable se conv ierte en un tipo de clase MainClass. C omo el objeto fue cr eado como un objeto de tipo TestClass. puede esperar que la conversin explcita convierta un objeto de tipo TestClass en un objeto de tipo MainClass. Sin embargo. C# no realiza conversiones explcitas basadas en el tipo usado en el momento de crear el objeto. En su lugar, realiza conv ersiones basadas en el tipo de variable que contiene el nuevo objeto. En el listado 20 1. el nuevo objeto se asigna a una variable de tipo object. Por tanto, el compi lador de C# genera cdigo que conv ierte un objeto de tipo ob j ect a tipoMa inClass. C omo no se ha definido una conversin de ob ject a M a i n C l ass. no se produce la c onve r sin explcita.

Inicializacin de estructuras
Como sabe, las est ructur as pueden contener constructores de lenguaje que tambin se encuent ran en las clases, incluyendo mtodos, ca mpos y propiedades Para a si gnar valores a los mtodos y c ampos de una est ructura se usa una simple

425

instruccin de asignacin. Sin embargo, es importante recordar que la diferencia entre una propiedad y un campo es que si se asigna un valor a una propiedad, se ejecuta el cdigo compilado en la estructura. Esto significa que se debe tener especial cuidado cuando se asignan valores a propiedades de est ructur as recin creadas. Este capitulo estudia este tema.

Cmo inicializar estructuras


El listado 20.2 contiene dos estructuras. La pri mera recibe el nombre de StructWi thPublicMembers y contiene dos mi embros pblicos enteros lla mados X e Y. La segunda estructura se llama StructWithProperties v contiene propiedades publicas llamadas X e Y. que gestionan dos nmeros enteros privados. El m t o d o Ma in ( ) del listado 20.2 crea dos variables, una que tiene el tipo de estructura StructWithPublicMembers y otra que tiene el tipo de es tructu ra StructWithProperties. El cdigo asigna valores a los miembros X e Y de cada estructura.
Listado 20.2. Cmo acceder a las estructuras con propiedades y mtodos pblicos public struct StructWithPublicMembers

{
public public int X; int Y;

}
public struct int int int X StructWithProperties PrivateX; PrvateY;

{
prvate prvate public

{
ge t

{
return PrvateX;

} set {
PrivateX = valu;

} }
public int Y

{
ge t

{
return PrivateY;

426

set

{
PrivateY = valu;

} } }

public

class MainClass static void M a i n ( )

{
public

{
S t r u c t Wi th Pu b1icMembers MembersStruct; StructWithProperties P r o p e r t i e s S t r u c t ; M e m b e r s S t r u c t .X = MembersStruct .Y = Properti es St ru ct .X PropertiesStruct .Y 100; 200 ; = 100; = 200 ;

} } El listado 20.2 no se compila. El compi lador de C# emite el siguiente error:


error CS0165: Uso de 'PropertiesStruct' la variable local no asignada

Lo mas interesante de este error es que hace referencia a la segunda variable de est ructur a definida en el mtodo Main ( ) . Sin embargo, el compi lador de C # compila el cdigo que funciona con la pri mera variable de estructura. En otras palabras, se puede acceder a los miembros pblicos del listado 20.2. pero no a las propiedades publicas del listado 20.2. Cual es la diferencia.'

Cmo resolver los problemas con la inicializacin


La respuesta corta es que el cdigo debe us ar el operador new para crear una nueva instancia de estructura. El listado 20.2 se compila si se crean nuevas refe rencias de estructura:
StructWithProperties PropertiesStruct S t r u c t W i t h P r o p e r t i e s (); = new

Est a r e s p u e s t a tiene que ver con el hecho de que las p r o p i e d a d e s son implementadas por el c ompi lador de C# como funciones publicas cuando genera el codigo del lenguaje intermedio de Microsoft (MS1L) par a la aplicacin. Puede c om pr ob a r esto revisando el MSIL generado por el compi lador de C# N E T Framevvork tiene una h e r ra mi en t a l lamada 1LDASM. que son las siglas de desensamblador de IL. Se puede usar esta herramienta para exami nar el Lenguaje

427

intermedio (IL) y los met adatos de cualqui er r esultado binario c ompatible con el C L R de un compilador NET. Modifique el listado 20.2 p ar a que incluya la nueva operacin y complelo en un ejecutable llamado Listing2 0-2 .exe. Tra s generar el ejecutable, puede obs er var su contenido con I L DAS M. Use la siguiente lnea de comando para iniciar el des ens ambla dor IL con el ejecutable del listado 20.2:
ldasm Listing20-2.exe

La f i g u r a 20.1 m u e s t r a la v e n t a n a I L D A S M a b i e r t a con el ej ec ut abl e

Listing20-2 .exe. El ejecutable contiene el manifiesto, que i n c l i n e la infor


macin de identificacin p ar a el ejecutable y tambin contiene met adatos que describen el cdigo del ejecutable.
f Listing20-2.exe - IL DASM
File View Help

^lnjxj

Listing20-2.exe
M A N I F E S T MainC lass J class p u b lic au to ansi beforefieldm it c to r M ain vo id v o id ;'

Struct W ith Properties class v a lu e p u b lic se q u e n tia l ansi se a le d beforefieldm it e x te n d s im scoriib: System P n va te X P rivate Y p riv a te int 32 p riv a te int 32

Value Type

3t get _X int 3 2 C IB g e t _Y int 22


s e t_ X set 'r' X v o id ;in t3 2 ' v o id ;in t3 2 ;

XI
A A

in s ta n c e int 32;

y in s ta n c e int 32 f
class v a lu e p u b lic s e q u e n tia l ansi sealed beforefieldm it e xte n d s [m sco riib System v a lu e Type X p u b lic int 3 2

Struct W ith P ublic M em bers ^

y p u b lic int 3 2 assembly "Listing20-2"

Jj

Figura 20.1. ILDASM abierto con el ejecutable del listado 20.2

I L D AS M muest ra las clases y est ructuras del ejecutable en forma de rbol. La parte del rbol StructWithPublicMembers muest ra dos variables publi cas de tipo int32 llamadas X e Y. Estas variables reflejan las dos propiedades progr amadas en la est ructura. La parte del rbol StructWithProperties muest ra las dos variables privadas; tambin mues tra cuatro mtodos que no se escribieron en la estructura: int32get_X() i n t3 2 g e t _ Y ( )

428

void set_X(int32) void set_Y(int32)

Estos mtodos realmente implementan el acceso a la propi edad de la e s t r u c t u ra. El mtodo get X ( ) contiene el cdigo del descri ptor de acceso get de la propiedad X y el mtodo get Y ( ) contiene el cdigo del des cri ptor de acceso get de la propi edad Y . Del mi smo modo, el mtodo set X () contiene el cdigo del descriptor de acceso set de la p ropiedad X y el mtodo set Y ( ) contiene el cdigo del descri ptor de acceso set de la propiedad Y Esto significa que cuando el cdigo accede a una propiedad, en realidad est llamando a un mtodo que implementa la f uncionalidad de la propiedad. El probl ema con el listado 20.2 es que la variable PropertiesStruct no esta inicializada con un oper ador new antes de ser usada. Esto significa que la variable no est asociada a una instancia de es tructur a y los mtodos no pueden ser llamados en instancias que no existen. Las instrucciones de la propi edad del mtodo Main ( ) obligan a que se llame a los mtodos de propiedades subyacentes, pero la l l amada no e ncuent ra ninguna instancia. El c ompi lador de C# detecta este probl ema y emite el mensaje de error mostrado tras el listado 20.2. La inicializacin del mi embro pblico tiene xito porque las clases y las es truct uras pueden inicializarse directamente, sin usar un constructor, siempre y cuando se haya dado explcitamente un v alor a todas las v ariables de la instancia.

Clases derivadas
Cuando t rat amos las clases de C# v imos como las clases pueden deriv arse de otras clases. Las clases derivadas heredan la funcionalidad de su clase pri mari a o base. La relacin entre una clase derivada y una clase base recibe el nombre de una relacin "es un" en trminos orientados a objetos. Por ejemplo, todas las clase de C# deriv an en ltima instancia del tipo Sys t e m .Ob j ect de NET. de modo que se puede decir que la clase "es un" Sys tem .Ob j ec t . Como todas las clases deriv adas heredan funcionalidad de su clase base, po de mos pres uponer que los objetos de una clase derivada pueden ser usados en c u al quier lugar donde se pueda usar un objeto de la clase base de la clase. Sin embargo, la seguridad de tipo integrada en C# tiene preferencia y el cdigo de este a part ado explica este tema.

Cmo pasar clases derivadas


El listado 20.3 contiene una clase l lamada TestClass que contiene un m todo llamado Test ( ) . El mtodo Test ( ) acept a una referencia a un objeto como parmetro.

429

El listado 20.3 tambin contiene una clase llamada MainClass. que crea un objeto de la clase TestClass y una cadena. La cadena se usa como parmetro par a la llamada al mtodo Test ( ) del objeto TestClass.
Listado 20.3. C m o p a s a r c a d e n a s d o n d e se e s p e r a n o b j e t o s public class TestClass

{
public void Test(ref ob]ect O bjectReference)

{ } }
public class MainClass static void M a i n ( )

{
public

{
TestClass TestObject = new TestClass (); string TestString = "Helio from C# !" ; TestObject.Test (ref TestString) ;

} } El listado 20.3 no se compila. El compi lador de C# emite los siguientes erro res:
Lis 1 1 n g 2 U- 3.c s (1t , S ) : error C S 15 0 2 : La me jor coincidencia de mtodo sobrecargado para T e s t C l a s s .T e s t (ref object)' tiene algunos argumentos no validos Listing20-3.cs (le, 25) : error CS1503: Argumento convertir de 'ref string' a 'ref object' '1' : no se puede

A pri mera vista, no parece logico. Como cada tipo de dato de N E T es un objeto, cualquier tipo de dato debera conv ertirse en ultima instancia en una v a riable de tipo ob] ect . Esto debera incluir a los objetos string. Por que no se puede convertir implcitamente el objeto string en una variable de tipo

object'.'

Cmo resolver problemas que surgen cuando se pasan clases derivadas


El p robl ema de compilacin surge de las estrictas reglas de seguridad de tipos integradas en el lenguaje C#. El mtodo Test ( ) del listado 20.3 toma el valor de tipo object como p ar amet ro y el compi lador emite un error si se le proporciona algo distinto de un objeto. Otro problema con la estrategia del listado 20.3 proce de del mo di fi cador de p ar am et ro ref us ado en el mtodo Test (). El modifica-

430

dor ref permite que la implementacin del mtodo cambie el valor de la variable v el cambi o es visible p ar a el invocador. Esto le da permiso al mtodo Test ( ) par a sobrescribir la variable Ob j ectRef erence con cualquier valor que p u e da v ol ver a c o n ve r ti rs e e xp l ci t a m e n t e en un objeto. O b s e r v e la si gui ent e i mplement aci n a lt er nat iva del mtodo Test ():
public void Test (ref ob]ect O bj ec tReference)

{
Tstelass TestObject;

TestObject = new TestClass ( ); Ob]ectReference = (object)Tes tO bj ec t;

} En esta implementacin. se crea un objeto de clase T e s t C l a s s . La variable de referencia Obj e c t R e f e r e n c e se asigna al nuevo objeto y el invocador ve esta asignacin. El probl ema es que el listado 20.3 pasa una cadena al mtodo T e s t ( ) . Con esta nueva i mplementacin del mtodo T e s t ( ) situado en el listado 20.3. el i nvocador podra p a s a r una cadena y re cu per ar a un objeto T e s t C l a s s . El invocador podra no esperar que la variable ca mbi ara a un tipo diferente del s umi nist rado y podran surgir numerosos probl emas si el inv ocador siguiera t raba jando con el cdigo presuponiendo que la v ariable sigue siendo una cadena. C # evita este p robl ema exigiendo que solo se usen tipos de par met ros correctos cuando se inv oquen mtodos.

Cmo usar no enteros como elementos de matriz


El lenguaje C# especifica que slo se pueden us ar enteros como elementos de matriz. Sin embargo, a veces se encontr ar en situaciones en las que los enteros no son el modo ms conveniente p ar a e xpr es ar un ndice de mat ri z en el codigo. Por ejemplo, imagine un tablero de ajedrez en el que una letra desde A hasta H hace referencia a una de las ocho columnas del tablero y un nmero de 1 a K hace referencia a una de las ocho filas del tablero. Si necesita representar un tablero de ajedrez en el cdigo de C#. podra escoger usar una matriz rect angul ar de dos dimensiones:
in t [,] Chessboard; = new int [8,8];

Chessboard

Tras inicializar la matriz del tablero de ajedrez, querr hacer referencia a una casilla usando la tradicional sintaxis par a las casillas del tablero de ajedrez Q ui zs quiera hacer referencia a la casilla B7. por ejemplo, de esta manera.
C h e s s b o a r d [ 'B ' , 7] ;

431

Sin embargo, no puede hacer esto porque C# no permite el uso de caracteres, como la B del ejemplo, como referencias de elementos de matriz. El listado 20.4 usa un indizador p a r a solucionar este problema:
Listado 20.4. Cmo representar un tablero de ajedrez con un indizador using public System; class Chessboard [,] Board;

{
private public in t

Chessboard( )

(
Board = new i n t [8,8];

}
public int this [char Column, int Rowlndex]

{
get

{
int Columnlndex;

switch(Column)

{
case ' A': case 'a ' : Columnlndex break;

= 0;

case case

' B' : 'b' :


= 1;

Columnlndex

break;
case case 'C ' : 'c ' :

Columnlndex break; case 'D ' :

= 2;

case

'd' :
= 3;

Columnlndex brea k ; case 'E ' : case 'e ' : Columnlndex break;

= 4;

case

' F' :
= 5;

case 'f ' : Columnlndex break; case 'G' : case 'g ' : Columnlndex

= c;

432

break; c a s e ' H' :


case 'h': Column Index = 7; break; default: throw new Exception("Illegal

column

specif ie r. ") ;

}
C o n s o l e . W r i t e L m e (" (returning cell [ {0 ) , { 1} ] " , Columnlndex, Rowlndex) ; return Board[Columnlndex, Rowlndex];

public

class

MamClass void M a i n ( )

{
public static

{
int CellContents; Chessboard MyChessboard CellContents = new C h e s s b o a r d (); [ 'B' , 7] ;

= MyChessboard

} } El cdigo del listado 20.4 declara una clase llamada Chessboard para re presentar un tablero de ajedrez. La clase i nc lu\ e una matriz de enteros privada de dos di mensiones l lamada Board. que puede usarse p ar a representar que piezas de ajedrez estn en qu casillas del tablero. (Par a mant ener el listado del codigo. la matriz no se usa realmente.) La clase tambin implementa un indizador con un descri ptor de acceso get. El indizador acepta dos parmetros: un carcter y un entero. El indizador da por hec ho que el c a r c t e r e s p e c i f i c a d o en el p r i m e r p a r a m e t r o r e p r e s e n t a un identificador de col umna y traduce el carcter como una col umna de la matriz priv ada. El especificado!' de col umna A lo t raduce como col umna 0 en la matriz privada Board. El especi fi cador de col umna B lo t raduce como col umna 1 en la matriz privada Board v as sucesivamente. El indizador escribe un mensaje en la consola que especifica los elementos de indizador t raduci dos y luego devuelve el valor de los elementos de la matriz a los que hacen referencia los par met ros del indizador. El mtodo Ma n ( ) del listado 20.4 crea un nuev o objeto de tipo Chessboard y usa el indizador par a hacer referencia a la casilla B7:
CellContents = MyChessboard [ 'B', 7];

Cua nd o el cdigo del listado 20.4 se ejecuta, el codigo del mtodo Main ( ) llama al indizador. que escribe lo siguiente en la consola:
(retur n m g cell [1,7]

433

El indizador tradujo el primer parmetro. B. en la referencia de columna b as a da en enteros que el compi lador de C# necesita p ar a acceder a un elemento de la matriz privada. Este esquema permite disear clases que usan una sintaxis natu ral para la aplicacin (en este caso, indizadores de elementos de matriz basados en caracteres) mientras an cumplen los requisitos de C# de usar indizadores de elementos de matriz basados en enteros.

Resumen
El mejor modo de resolver un difcil probl ema de prog ramaci n de C# es intentar diferentes mtodos de codificacin con el compilador. No tenga miedo de experimentar. El compi lador de C# le avi sar si hace algo equivocado. Tambi n podria considerar el uso la herramienta I LD AS M para colarse en sus ensamblados y v er cmo el compilador de C# crea codigo ejecutable a partir de su cdigo fuente. La comprensin del cdigo que genera el compi lador de C# puede ayudarle a entender por que el cdigo funciona de la manera que lo hace. En este capitulo, aprendi que el cdigo descriptor de acceso de propiedades se convierte en mtodos especiales por el compilador de C#. Esto puede ser difcil de descubrir sin observ ar el codigo generado por I LD ASM . La herramienta I LD AS M funciona con cualquier ensamblado generado por un compilador de N E T que genere MSIL Examine con I L D AS M algunos ensambl ados y aplicaciones de NET. Abralos con la herramienta y vea cmo estn construidos. El anlisis de otros ens ambl a dos v su contenido puede darle una mejor comprensin de cmo funciona el cdi go N E T y puede ayudarle a ser un mejor p rog ramado r NET.

434

Parte IV

Cmo desarrollar soluciones .NET usando C#

435

Cmo construir aplicaciones WindowsForms


m
La mayor parte del material escrito sobre N E T Framework se centra en la a yu da que reciben los pr og ramado re s que escriben aplicaciones par a Internet. El motor A S P . N E T y los modelos de desarrollo del "software como un servicio" son. sin lugar a dudas, unas potentes herramientas para el desarrollo de aplicaciones de Internet. Sin embargo. N E T Framework no t rata slo con Internet. Microsoft se dio cuenta de que. aunque muchos pro gr amado re s estn escri biendo aplicaciones par a Internet, otros muchos se dedican a desarrol lar ap li ca ciones de escritorio al estilo Wi n32. N E T Framewo rk no ha olvidado a estos programadores. Incluye un conjunto de clases de N E T que facilita el desarrollo de aplicaciones Windows de escritorio que usan un lenguaje compatible con NET Este conj unt o de clases y el modelo de p r o g r a m a c i n que admi te se llama Wi ndowsForms. En este c a p t u l o e s t u d i a r e m o s la e s t r u c t u r a b s i c a de u n a a p l i c a c i n Wi ndows Forms . Ver cmo crear una forma bsica y cmo aadir controles a los formularios. Exami nar emos las clases de N E T Framewo rk que puede usar una aplicacin W i nd ow sF o rm s y tambi n estudiaremos al gunos de los at ri but os de ensambl ado que se pueden usar par a a gr egar la informacin de versin y derecho de a utora a sus aplicaciones.

437

Arquitectura de WindowsForms
Para pr ogr a ma r una aplicacin Wi ndows Forms es necesario comprender cmo se usan las clases base de Wi ndows Forms con las aplicaciones N E T Este captu lo exa mi na la arquit ect ura de la biblioteca de clases de Wi ndows Forms . Todas las clases que se usan p ar a construir aplicaciones de Wi ndo ws Fo rms se incluyen en un espacio de n ombre de N E T F ra me wo rk llamado System. Windows .Forms. Este espacio de nombre contiene todas las clases necesarias par a construir elaboradas aplicaciones de escritorio p ar a Windows. Estas clases permiten t rab aj ar con formularios, botones, controles de edicin, casillas de veri ficacin. listas y muchos otros elementos de interfaz de usuario. Todas estas c l as e s e s t n a su d i s p o s i c i n listas p a r a ser u s a d a s en sus a p l i ca c io ne s Wi ndowsForms. Las aplicaciones W i n do ws F or m s usan dos clases fundamentales de NET Framework: La clase Form. que gestiona los formularios de la aplicacin \ los controles del formulario, y la clase Application, que gestiona el modo en que la aplicacin controla los mensajes Wi ndows enviados y recibidos de los formula rios de la aplicacin. Estas dos clases se i n cl i n en en el espacio de nombre System. Windows .Forms de N E T Framework y componen la estructura basica de una aplicacin Wi ndo ws Fo rms .

La clase Form
El espacio de nombre S y s t e m .Windows .Forms i ncl i ne una clase base llamada Form. La clase Form representa una forma o ventana de su aplicacin Al crear una aplicacin de W i n d ow sF o rm s en C#. se disea una clase de ventana y se usa la clase Form como clase base par a la clase de ventana. Esta clase de v en tan a hereda todo el c o mp or t a mi e nt o b s ico de una vent ana y agr ega la funcionalidad necesaria par a la aplicacin. Todos los comport ami ent os bsicos de ventana estn integrados en la clase base Form y esos comport ami ent os se heredan a ut omt icame nte si se deriva una clase de ventana de la clase Form.

La clase Application
La s clases Form definen el aspect o y c omport ami ent o de las ventanas de una aplicacin paro no se ejecutan por s mismas. W in do ws F or ms debe ejecutarse d en tro del c on t ex t o de u na ap li ca ci n . El e s p a ci o de n o m br es System. Windows .Form.s incluye una clase llamada Application, que contiene mtodos que ayudan a gest ionar las aplicaciones Wi ndo ws Fo rms . La clase Application contiene mtodos que permiten iniciar, gestionar v detener las aplicaciones WindowsForms. W i n do ws F o r ms responde a eventos iniciados por el usuario, como mover el ratn o pul sar una tecla del teclado.

438

Desde los comienzos de Wi ndows, la ar quit ect ura de las aplicaciones de escri to rio de Wi nd ows ha sido diseada sobre el concepto de bucle de mensajes. En una aplicacin Wi ndows estandar. la parte mas importante del codigo se incluye en un bucle y recibe mensajes del sistema operativ o Wi ndows. Cu and o el usuario mueve el ratn, pul sa una tecla o realiza alguna otra operacin sobre la que puede a ctuar una ventana, el sistema operativo toma nota de la accin y enva un mensaje a la v ent ana correspondi ent e informndole de la accin. Es el codigo de la v ent ana el que debe utilizar convenientemente el mensaje. En la ar quit ect ura WindovvsForms. los conceptos bsicos siguen siendo los mismos. Las aplicaciones WindovvsForms tienen un fragment o de codigo que espera la llegada de mensajes de interaccin del usuar io desde el sistema o pe r at i vo y luego los envan a la ventana apropiada. En la arquit ect ura WindovvsForms. la clase Application es el cdigo principal que gestiona este control de m e n sajes y la clase Forms es la clase que controla los mensajes que env a la clase

Appl i ca t ion. La clase Application est sellada. No se pueden derivar clases de ella.
Sus mtodos son estticos, lo que significa que pueden ser llamados sin que haya un objeto de la clase Application disponible.

Cmo crear la primera aplicacin WindowsForms


El listado 21.1 mues tra una sencilla aplicacin WindovvsForms. Representa una sencilla aplicacin W ind ows For ms que abre un slo formulario y sigue ejecu tndose hasta que el usuar io cierra el formulario.
Listado 21.1. La aplicacin Helio, W in d o w s F o rm s using public Syst em .W in dow s.F o r m s ; class SimpieHe11oWorId : Form

{
public static void M a i n ( ) S impleHe11oWor1d () ) ;

{
A p p l i c a 1 1 o n .Run (new

}
public Sim p1eHe 11oWorId ( ) = "Helio, W i n d o w s F o r m s !";

{
Text

} 1 El cdigo del listado 21.1 declara una clase llamada SimpleHelloWorld. Se deriva de la clase Form de N E T Framework. que califica la clase como una

439

clase Windows Form. La clase contiene un mtodo Main ( ) . que crea un nuevo objeto de la clase SimpleHelloWorId y usa ese objeto como parmetro del mtodo en la clase Application llamado Run ( ) . El constructor de la clase S impleHe 1 ] oWor id establece el valor de la propiedad heredada Text a He 1l o , Windows Forms ! Esta cadena se muestra como el titulo del for mu lario. La figura 21.1 muest ra el aspecto del formulario cuando se ejecuta el codigo del listado 21.1.

Figura 21.1. El listado 2 1 1 muestra un sencillo formulario

Cmo compilar una aplicacin WindowsForms


Al igual que las aplicaciones de consola diseadas usando C#. las aplicaciones W i nd ow sF o rm s deben ser compi ladas con el c ompi lador de C# antes de poder ejecutar su cdigo. Las aplicaciones Wi ndowsForms compiladas con el compilador de C# pueden comport arse de f orma ligeramente diferente al ser iniciadas, depen diendo del modo en el que se compil el cdigo. La siguiente lnea de comando es la mas simple que se puede usar p ar a compi lar el cdigo del listado 2 l . I :
c s c L is t in g 2 1- 1 .c s

Como todas las aplicaciones de C#. este cdigo genera un ejecutable llamado Li st inq2 1-1 .e;:e. Si ejecuta este archivo desde una consola, aparecera la ventana de la aplicacin. Sin embargo, ocurre algo interesante cuando se hace doble clic sobre el icono del ejecutable en el expl orador de Wi ndows. Si se inicia el ejecutable desde el Expl orador de Wi ndows aparecen dos v entanas: una v enta na de consola, que esta vacia y la ventana WindowsForms de la aplicacin. Este comport ami ent o es diferente de la mayor a de las aplicaciones Windows. La mayor a de las aplicaciones Wi ndows no presentan una ventana de consola vaca

440

cuando se inicia la aplicacin. (,Por que el ejecutable del listado 21.1 muestra una vent ana de consola y. lo ms importante, como podemos el i mi na rl a } Por defecto, el compilador de C# genera aplicaciones de consola. Estas apl ica c i o n e s n e c e s i t a n u n a v e n t a n a de c o n s o l a p a r a q u e los m t o d o s , c o m o Consol .WriteLine ( ) . dispongan de una consola en la que escribir sus mensajes. El tiempo de ejecucin de N E T consulta el ejecutable cuando es inicia do y si el ejecutable est compilado como una aplicacin de consola, el cargador del tiempo de ejecucin crea una nueva vent ana de consola par a la aplicacin. Si se compi la el listado 21.1 mediante el compi lador de C# por defecto, se generara una aplicacin N E T para consola. Esto explica la ventana de consola vacia que aparece cuando se ejecuta el ejecutable compilado. WindovvsForms t ra ba j a con ventanas, no con consolas y las aplicaciones WindovvsForms no necesitan la ventana de consola. El compi lador de CU admite un a r gu me nt o de linea de co man do ll amado target que se usa p ar a especificar el tipo de la aplicacin que se quiere compilar. Puede usar este ar gument o para indicarle al compi lador de CU que quiere compi lar una aplicacin Wi nd ows que no necesita una consola. La siguiente lnea de comando:
ese /target :win e x e L i s t m g 2 1 - l . c s

ordena al compi lador de CU que compile el archivo L i s t i n g 2 ] - 1 . e s y use sus contenidos para crear un ejecutable Wi ndows que no necesita una c on sola. Si usa esta lnea de c omando p ar a compilar el cdigo del listado 21.1 e inicia el ejecutable desde el expl orador de Wi ndows, ap arec er el formul ari o de la aplicacin, sin que apa rez ca tambin una ventana de consola vaca. N O T A : El compilador de C# acepta /t como abreviatura de /target. La anterior lnea de comandos puede acortarse a ese /trwinexe

L i s t i n g 2 1 - 1 .es.

Ensamblados: cmo aadir informacin de versin a las aplicaciones WindowsForms


Por defecto, las aplicaciones W i n d o w s F o r m s no contienen i nformaci n de su v ersin. Sin embargo, se pueden usar atributos integrados en N E T Framevvork para aadir informacin de la versin a las aplicaciones. Estos atributos empi e zan a ac tua r en el nivel de ens ambl ado y se aaden al cdigo que produce el compilador de CU. Todos estos atributos son opcionales, pero su uso aade infor macin de versin y de derechos de autora a los binarios NET. Al aadir esta informacin se permite a los usuarios finales usar el Ex pl orado r de Windows, hacer clic con el botn derecho en la aplicacin, seleccionar Propiedades en el men contextual e inspeccionar los valores del atributo incrustado. Los usuarios

441

finales pueden ex ami na r la informacin de la versin y de derechos de a utora de las aplicaciones N E T WindowsForms ex act ament e del mi smo modo que pue den exa mi na r dicha informacin en las aplicaciones Wi n32 estndar. Las clases que implementan estos atributos estn en un espacio de nombre NE T llamado Sys tem .Ref lect ion. C uando se usan estos atributos. ha\ que hacer referencia a este espacio de nombre con la p al abr a clave using o a nt eponer el nombre del espacio de nombre a los nombres de los ensamblados. Parte de la informacin especificada en estos atributos se escribe en el mani fiesto del ens ambl ado y otros fragment os de informacin se al mac enan como recurso de informacin de versin incrust ado en el ejecutable del ensamblado Puede obser var el manifiesto del e nsambl ado mediante la herramienta ILDASM v puede ver el recurso de i nformacin de versin del ejecutable haciendo clic con el boton derecho del ratn en el archiv o en el Expl orador de Wi ndows y seleccionan do Propiedades>Versin.

TRUCO: Puede agregar estos atributos a cualquier proyecto de cdigo .NET. La informacin de la versin siempre est disponible en el producto compilado del cdigo.
En este ap art ado estudiaremos los siguientes atributos:

AssemblyTit le. que asigna un ttulo al ensamblado. AssemblyDescr ipt ion. que asigna una descripcin al ensamblado. AssemblyConfiguration. que describe las opciones usadas para
construir el ensamblado.

AssembiyCompany. que asigna un nombre de compaa al ensamblado. AssemblyProduct. que asigna informacin del producto al ensamblado. AssemblyCopyright. que asigna informacin de derechos de autora
al ensamblado.

AssemblyTrademark. que asigna informacin de marca al ensamblado. AssemblyCulture. que asigna informacin local al ensamblado. AssemblyVersion. que asigna un nmero de versin al ensamblado.

AssemblyTitle
El atributo AssemblyTitle permite asi gnar un ttulo al ensamblado. El atributo t oma un par met ro de cadena en su const ructor que especifica el ttulo, como mues tra el siguiente ejemplo:
[assembly: AssemblyTitle ( " L i s t m g 21-2")]

442

El titulo del ensamblado no se escribe en su manifiesto, pero esta disponible en el c a mp o Descripton del bloque de informacin de versin del archivo c o m pilado.

Assem bly Descri ption


El atributo AssemblyDescription permite pro po rci onar una d es cri p cin del ensamblado. El at ri but o toma un par met ro de cadena en su constructor que especifica la descripcin, como mues tra el siguiente ejemplo:
[assembly: A s s e m b l y D e s c n p t i o n ("This executable c o m p i l m g the code in Listn g 21-2.")] was produced by

La descripcin del e ns ambl ado se escribe en el manifiesto del ensambl ado; tambin est disponible en el ca mp o Comment del bloque de i nformacin de versin del archivo compilado.

AssemblyConfiguration
El atributo AssemblyConfiguration permite especificar informacin de configuracin de compilacin del ensamblado. Por ejemplo, la i nformacin de configuracin de e ns ambl ado puede especi fi car si el ens ambl ado se compilo con configuracin par a su distribucin o depuracin. El atributo toma un parmet ro de cadena en su cons tructor que especifica la informacin de configuracin:
[a s s e m b l y : A s s e m b l y C o n f i g u r a t i o n ("retail" ) ]

La descripcin del e ns ambl ado se escribe en el manifiesto del ensamblado, pero no esta disponible en el bloque de informacin de versin del archivo compilado.

AssemblyCompany
El atributo AssemblyCompany permite especificar un nombre de compa a para asociarlo al ensamblado. El atributo toma un par amet ro de cadena en su const ructor que especifica el nombre de la compaa:
[assembly: AssemblyCompany("John Wiley, Inc.")]

El nombre de la co mpa a del en sa mbl ado se escribe en el manifiesto del e n sambl ado; tambin est disponible en el c a mp o Company ame del bl oque de informacin de versin del archivo compilado.

AssemblyProduct
El atributo AssemblyProduct permite especificar un nombre de producto p ar a asociarlo al ensamblado. El atributo toma un par met ro de cadena en su

443

cons tructor que especifica el nombre del producto compaa, como muest ra el siguiente ejemplo:
[assembly: AssemblyProduct("C# Bible")]

El nombre del producto del ens ambl ad o se escribe en el manifiesto del e n sa m blado; tambin est disponible en el ca mpo Product ame del bloque de informacin de versin del archivo compilado.

AssemblyCopyright
El atributo AssemblyCopyright permite especificar informacin de dere chos de aut or a par a el ensamblado. El atributo toma un par met ro de cadena en su cons tructor que especifica la informacin de derechos de autora, corno mues tra el siguiente ejemplo:
[assembly: A ss e m b l y C o p y r i g h t (" (c) 2002 John Wiley, Inc.")]

El nombre del prod uc to del ens ambl ado se escribe en el manifiesto del ens am blado; tambin est disponible en el c a mp o Copyright del bl oque de informa cin de versin del archivo compilado.

Assem blyTrademark
El atributo AssemblyTrademark permite especificar informacin de m a r ca registrada p ar a el ensamblado. El atributo t oma un p ar met ro de cadena en su const ructor que especifica la i nformacin de m ar c a registrada, como muest ra el siguiente ejemplo:
[assembly: AssemblyTrademark("Windows Microsoft Corporation.")] s a trademark of

El nombre del producto del e ns ambl ado se escribe en el manifiesto del ens am blado; tambin est disponible en el ca mp o Legal del bl oque de informacin de versin del archivo compilado.

AssemblyCulture
El atributo As semblyCul ture permite especificar informacin de referen cia cultural par a el ensamblado. La informacin de referencia cultural especifica la informacin de lenguaje v pais que el ensamblado usa para hacer su trabajo. El atributo t oma un parmetro de cadena en su cons tructor que especifica la i nformacin de referencia cultural, como mue st ra el siguiente ejemplo:
[assembly: As se mb ly Cu lture("us-en")]

444

Las cadenas de referencia cultural son definidas mediante un estndar de Internet llamado RFC 1766. El est ndar se titula Tags for the Identification of Languages y est disponible en Internet en www.ietf.org/rfc/ rf cl7 66 .txt. El nombre del pro du cto del e ns ambl ado se escribe en el m a n i fiesto del ensamblado; t ambin est disponible en el campo Legal Trademarks del bloque de informacin de versin del archi vo compilado.

NOTA: La informacin de referencia cultural slo se puede aadir a bi bliotecas y mdulos. No puede aadirse a ejecutables, porque los ejecutables no pueden ser localizados. Si se intenta aadir el atributo AssemblyCulture al cdigo base que se compila en el ejecutable final, el compilador de C# emite el siguiente mensaje de error:
error CS0647: Error al emitir el atributo 'S y s t e m .Ref 1e c t i o n .A s s e m b ly Cu lt ur eA tt ri bu te ' 'Los archivos ejecutables no se pueden adaptar y no deben tener referencia c u 1 tu r a 1'

La descripcin del ens amb la do se escribe en el manifiesto del ensamblado, pero no est disponible en el bloque de informacin de versin del archivo c ompi lado.

AssemblyVersion
El atributo AssemblyVersion permite asi gnar un nmero de versin al ensamblado. Los nmeros de versin de N E T constan de cuatro partes: Un n mero de versin principal Un nmero de v ersin secundari a Un n mero de rev isin Un nmero de compilacin C ad a una de estas partes est s eparada por un punto. El atributo toma un p ar met ro de cadena en su const ructor que especifica el nmero de versin, como m ues tra el siguiente ejemplo:
[assembly: A s s e m b l y V e r s i o n ("1.O .O .O " )]

Siempre se debe especificar un nmero de versin. Si se especifican los n me ros de versin principal y secundaria, puede dejar que el compilador de CU genere automt icamente los otros nmeros al compilar el cdigo. Esto puede ser til si se quiere que c ada compilacin del cdigo tenga un nmero de versin nico. Si usa el carcter asterisco p a ra un nmero de compilacin, el compi lador de CU asigna

445

uno automt icamente. El nmero de compilacin generado es igual al nmero de das desde el 1 de enero del 2000. como mues tr a el siguiente ejemplo:
[assembly: AssemblyVersin ("1.0.0.*") ]

Este ejemplo asigna al ensamblado una versin principal igual a 1. una versin secundaria igual a 0. un nmero de revisin igual a 0 y un nmero de compilacin asignado aut omt icame nte por el compi lador de C#. Si usa el carcter asterisco p ar a un nmero de revisin, el compilador de C# asigna aut omt i came nt e un nmero de revisin y un nmero de compilacin. El nmero de revisin generado es igual al nmero de das desde el 1 de enero del 2000. como mues tra el siguiente ejemplo:
[a s s e m b l y : AssemblyVersin ("1.0.*") ]

Este ejemplo asigna al ensambl ado una versin principal igual a 1. una versin secundari a igual a 0. un numero de revisin igual a 0 y un nmero de revisin asignado au to mt icame nte por el compi lador de C#. El nombre del p roducto del ens amb la do se escribe en el manifiesto del ensam blado: tambie'n est disponible en los campos Assembly Versin. Product Versin y File Versin del bloque de informacin de versin del archivo compilado. El listado 2 1.2 aade atributos de versin de ensamblado al cdigo del listado 21.1.
Listado 21.2. Sencilla aplicacin de formulario W in d o w s con inform acin de versin using us ing System.Reflection; Syst em .W in do ws .Fo rms ;

[assembly: As s emb 1yT 1 1 1 e (" Iu s t m g 21-2")] [assembly: A s s e m b l y D e s c n p t i o n ( " T h i s executable was produced compiling the code in Listing 21-2.")] As s emblyConfiguration("Retail") ] [asse m b 1y A s s e m b 1y C o m p a n y ("John Wiley, Inc.")] [assembly AssemblyProduct ("C# Bible") ] [asse m b 1y AssemblyCopyr lght (" (c j) 2002 John Wiley, Inc." [asse mb 1y [asse m b 1y As s em b1yVe r s l o n ("1.0.*") ] public class Simp 1eH e 11oWo r1d void M a i n ( ) SimpieHe11o W o r I d ( ) ); : Form

by

{
public static

{
Appi icat i o n .Run(new

public

S impieHe11oWo r1d () - "Hello, Windows F o r m s !" ;

{
Text

446

El objeto Application con ms detalle


El objeto Application contiene propiedades, mtodos y eventos que p u e den usarse en el cdigo WindowsForms . En este ap art ado estudiaremos los miembros de clase ms usados.

Eventos Application
La clase Application admite cuatro eventos que pueden usarse en las aplicaciones WindowsForms: El evento App licationExit se desencadena cuando la aplicacin esta a punto de cerrarse. A este evento se le pueden asi gnar los delegados de tipo EventHandler . El delegado EventHandler esta definido en el espacio de nombre System de NET. El delegado toma dos parmetros: un objeto que hace referencia al objeto que enva el evento y un objeto EventArgs que especifica los ar gu me nt os del evento. No devuelve ni n gn valor. El evento Id le se desencadena cuando la aplicacin termina de env iar mensajes desde el sistema operativo y est a punt o de ent rar en estado de inactividad. La aplicacin a ba ndona el estado de inactividad cuando consi dera que hay ms mensajes que procesar. A este evento se le pueden a si g nar delegados de tipo EventHandler. El delegado EventHandler est definido en el espacio de nombre N E T System. El delegado toma dos parmetros: un objeto que hace referencia al objeto que enva el evento y un objeto EventArgs que especifica los a rgume nt os del evento. No devuelve ningn valor. El evento ThreadExcept.ion se desencadena cuando se inicia una e x cepcin de s ubproces o no captur ada. A este evento se le pueden asignar delegados de tipo ThreadEzecptionEventHandler. El delegado ThreadExecptionEventHandler se define en el espaci o de n o m bre .NET S y s t e m .Threading. El delegado toma dos parmetros: un objeto que hace referencia al objeto que enva el evento y un objeto ThreadingExcept onEventArgs que especifica los argument os del evento. No devuelve ningn valor. El evento ThreadExit se desencadena cuando un subproceso est a punto de cerrarse. C uando el proceso principal de una aplicacin esta a punto de cerrarse, antes se desencadena este evento, seguido de un evento ApplicationExit. A este evento se le pueden a si gnar delegados de tipo EventHandler. El delegado EventHandler esta definido en el espacio de nombre System de NET. El delegado toma dos parmetros: un objeto que hace referencia al objeto que enva el evento y un objeto

447

EventArgs que especifica los a rgume nt os del evento. No devuelve nin


gn valor.

Cmo trabajar con eventos en el cdigo


El cdigo del listado 21.3 se suma al cdigo de formulario del listado 21.2 mediante el control de ev entos desde el objeto Appl i cat ion.
Listado 21.3. Cmo controlar los eventos de la aplicacin u sing using using us inq Sy s t e m ; System.Threading; System.Reflection; S ystera.Windows.F o rm s;

[assembly: A.ssemblyTitle ("Listing 21-3")] [assembly: As se mb l y D e s c r i p t i o n ("This executable was produced compiling the code in Listing 21-3.")] [assembly: A s s e m b l y C o m p a n y ("John Wiley, Inc.")] [assembly: AssemblyProduct ("C# Bible")] a s s e m b l y : A s s e m b 1y C o py right (" (c ) 2002 John Wiley, Inc.")] [a s s e m b 1y : As s e m b 1yVersion ("1.0.*") ] public class He 11oWorIdForm : Form

by

{
pub lie Hell oW or 1dForm - "Hello, W m d o w s F o r m s !" ;

{
Text

} }
public class void A p p 1icationEventHandlerCl ass OnApplicationExit (object sender, EventArgs e)

{
public:

{ try {
Console.WriteLine("The application is shutting down.");

}
catch(MotSupportedException)

{ } }
public void Onldle (object sender, EventArgs is e)

{
Console.WriteLine("The application idle.");

}
public void OnThreadException(object Thr eacJExcept i onEventArgs e ) sender,

448

C o n s o l . W i i t e L m e i"an threacl was caught !" ) ;

exception

thrown

from

an

applicaticn

}
public void OnThreadExit(object sender, EventArys e) s

1
Consol.WriteLine f"The s h u t t m g down ." ) ; application' s m a m thread

} }
public class MamClass

{
public static void M a i n ( )

{
He 11 oWor ldForm FormOb] ect - new Hel.loWorldFormf ; ApplicatonEventHandlerClass AppEvents = new A p p 1 icatonEventHandlerClass () ; Application.ApplicdtionEy.it +- new Even tHandler (AppEvents.OnApplicationEx it ) ; Application.Idle new EventHandler (AppEvents.O n l d l e ) ; Application.ThreadException +- new Thre ad Ex ce p1 1 onEventHandle r (AppEvent s .OnThreadException) ; A p p l i c a t i o n .ThreadExit new EventHandler (AppEvents.OnThreadExit ) ; A p p l i c a t i o n . R u n ( F o r m b j e c t );

} i La nueva clase del listado 21.3 recibe el no mbr e de A p p l i c a t i o n EventHandierClass v contiene mtodos que controlan los eventos d es e nc a denados desde el objeto Appl i catin. El mtodo Main ( ) crea un objeto de la clase ApplicationEvent.HandlerCla.ss y agrega su codigo a la lista de controladores de exentos de la clase Application. Los controladores de evento de la clase Appl icat i onEvent Hand IerClass escriben en la c on sola. Esto es perfectamente v alido, incluso en una aplicacin W indows Forms. Si compila el cdigo del listado 21.3 usando el destino ejecutable de consola (ese / target :exe List ing2 1-3 .es), los mensajes del c ont rol ador de eventos se escriben en la ventana de la consola que se us para iniciar la aplicacin. Si compila el cdigo del listado 21.3 us ando el destino de ejecutable de Wi ndows (esc /target : winexe Li sting2 l-3.es). ni nguna consola esta a s oc i a da al proceso y no se muestran mensajes en la consola.

Propiedades Application
La clase Application es compatible con varias propiedades que pueden usarse en las aplicaciones de C#. Los siguientes apart ados describen cmo usar cada una de estas propiedades.

449

AllowQuit
La propi edad booleana AllowQuit especifica si el cdigo puede o no termi nar la aplicacin mediante programacin. La propiedad devuelve True si el cdi go puede ordenar a la aplicacin que termine y False en caso contrario. Esta propiedad es de slo lectura y no se le puede as ignar un valor. Por lo general, los usuarios pueden t erminar las aplicaciones cerrando el formulario principal de la aplicacin. Algunas aplicaciones se incluyen en contenedores, como clientes Web. v no pueden cerrarse mediante programaci n. Slo se cierran c uando su contene dor se cierra. Si la propiedad AllowQuit devuelve true. se puede llamar a un mtodo de Application llamado Exit ( ) p ar a terminar la aplicacin me diante progr amaci n. Los mtodos del objeto Application se estudiaran en el a pa rt ado titulado "Mtodos Application."

CommonAppDataRegistry
La propiedad CommonAppDataRegistry devuelve una referencia a un objeto de la clase RegistryKey. El objeto RegistryKey hace referencia a una clave en el registro que la aplicacin puede usar par a al macenar datos de registro que deberan estar disponibles p ar a todos los usuarios de la aplicacin. Esta propiedad es de slo lectura y no se le puede as ignar un valor. La clase RegistryKey es parte de N E T F ramework y est disponible en un espaci o de nombre llamado M i c r o s o f t .W i n32 . Representa una clave espec fica del registro y contiene mtodos que permiten crear subclavcs. leer valores y realizar otras tareas relacionadas con las claves del registro.

CommonAppDataPath
La propiedad de cadena CommonAppDataPath hace referencia a una ruta en el sistema de archivos que la aplicacin puede u s ar p ar a al macenar datos bas ados en archivos que deberan estar disponibles par a todos los usuarios de la aplicacin. Esta propiedad es de slo lectura y no se le puede asi gnar un valor. La ruta de datos de la aplicacin se almacena dentro de la ruta de carpeta de d ocument os de W in do ws p a r a todos los usuar ios, que suele enc ontr ars e en

C:\Documents and Settings\All Users\Datos

de programa.

La ruta real de la aplicacin a punt a a una carpeta dentro de esta ruta de documen tos "a/l users" que tiene la f o r m a C o m p a n y N a m e \ ProductName\ ProductVersion. Los nombres de carpet a CompanyName. ProductName v ProductVersion se basan en los valores de las propiedades de la aplicacin del mi smo nombre. Si no se a si g na n val ores a est as prop ieda des , la clase Application propor ci ona unos valores por defecto vlidos. Por ejemplo, el codi go del listado 21.1 tiene u na rut a de dat os c o m un es de la aplicacin

C:\Documents and Settings\All Users\Datos de programa\SimpleHelloWorld\SimpleHelloWorld\VO .0 . Si el cdigo del listado 21.1 va a a s i g n a r val ores a las p r o p i ed a de s CompanyName.

450

ProductName o ProductVersion de la clase Application, los n o m bres de carpetas en la ruta de datos comunes de la aplicacin puede c ambi ar para reflejar los valores de esas propiedades. La ruta de la carpet a de la versin del producto slo usa los nmeros de versin principal y secundario especificados en la aplicacin, independientemente del nmero de valores que asigne en el at ri but o de la aplicacin [AssemblyVersion] . Si la aplicacin usa un atributo [AssemblyVersion] con un valor, por ejemplo, 1. 2 .3 .4 . la parte de nmero de versin de la ruta de datos comunes de la aplicacin ser 1 .2 . La letra V siempre se ant epone al nmero de v ersin principal de la aplicacin en la parte de la v ersin de numero de la ruta de datos.

CompanyName
La propiedad de cadena CompanyName devuelve el nombre de la c ompa a asociado a la aplicacin. Esta propiedad es de slo lectura y no se le puede asignar un valor. Por defecto, este valor se asigna al nombre de la clase que contiene el m t o d o M a i n ( ) de la aplicacin. Si la aplicacin especifica un n o m bre de co mpa a con el at ri but o [ AssemblyCompany]. el valor de ese a t r i b u to se usa como el valor de la propiedad CompanyName de la aplicacin.

CurrentCulture
La propiedad CurrentCulture permite t ra ba j ar con la informacin de referencia cultural de la aplicacin. Esta propiedad se puede leer y escribir. La propiedad tiene una clase de tipo Culturelnf o. que es una clase definida por N E T F ra me wo rk y que se e nc uen tr a en el es paci o de nombres System. Globalization. La clase Culturelnfo contiene mtodos y propiedades que permiten al cdigo t ra ba j ar con datos especficos del entorno cultural en el que se ejecuta la aplicacin. Los objetos Culturelnfo ofrecen informacin como el formato preferido par a mo st rar la fecha y la hora, la configuracin de la hora y el formato numeral.

CurrentlnputLanguage
La propiedad CurrentlnputLanguage permite t rab aj ar con el idioma actual de la aplicacin. La propiedad tiene una clase de tipo InputLanguage. que es una clase definida por N E T F ramework y que se encuentra en el espacio de nombres System. Windows .Forms. La clase InputLanguage contiene mtodos y propiedades que permiten al codigo t ra ba j ar con el conocimiento que tenga la aplicacin de las teclas del teclado y cmo se relacionan con los caracteres que pueden introducirse en la aplicacin. Las diferentes versiones especficas de cada lenguaje de Wi ndows establecen equivalencias entre las teclas del teclado y los caracteres especficos de los diferentes lenguajes y la clase CurrentlnputLanguage especifica el aspecto de esta asignacin.

451

ExecutablePath
La propiedad de cadena ExecutablePath devuelve la ruta del ejecutable de la aplicacin. Esta propiedad es de slo lectura y no se le puede asi gnar un valor.

LocalUserAppDataPath
La propiedad de cadena LocalUserAppDataPath hace referencia a una ruta en el sistema de archivos que la aplicacin puede usar par a al macenar datos basados en archivos que deberan estar disponibles par a el usuario conectado en ese momento al equipo. Esta propiedad es de solo lectura y no se le puede asi gnar un valor. Es usada por los usuarios locales con perfiles de sistema operativo del equipo local. Los usuarios con perfiles mviles usados a travs de un sistema de redes tienen una propiedad distinta, llamada UserAppDataPath. par a especificar dnde deben al macenar se los datos de la aplicacin. Al igual que la propiedad CommonAppDataPath. la ruta de datos de u s u a rio local seala a una carpet a incluida dentro de la carpet a de documentos de u s u a r i o c o n e c t a d a con u n a e s t r u c t u r a de c a r p e t a s q ue t i e n e la f o r m a CompanyName\ ProductName\ ProductVers i on. Los nombres de carpeta CompanyName. ProductName y ProductVersion se basan en los valores de la aplicacin del mi smo nombre. Si no se asigna un valor a estas propiedades, la clase Application propor ci ona unos valores vlidos por de fecto. Si el c di g o a s i g n a un v a l o r a las p r o p i e d a d e s C o m p a n y N a m e . ProductName o ProductVers ion de la clase Application, los n o m bres de carpetas en la ruta de datos de la aplicacin de usuario local cambia para reflejar los valores de esas propiedades. Al igual que la ruta de datos comunes de la aplicacin, la ruta de carpeta de versin de producto solo usa los nmeros de v ersin principal y s ecundario espe cificados en la aplicacin, independientemente del nmero de valores especi fi ca dos en el at ri but o de la aplicacin [ AssemblyVersion ] . Si la aplicacin usa un atributo [AssemblyVersion] con un valor, por ejemplo. 1.2. 3. 4 . la parte correspondiente al numero de v ersin de la ruta de datos de usuario local de la aplicacin ser 1.2. La letra V siempre se ant epone al numero de versin principal de la aplicacin en la parte de la v ersin de nmero de la ruta de datos

MessageLoop
La propiedad booleana MessageLoop devuelve True si existe un bucle de mensajes p a r a la aplicacin y False en caso contrario. Esta propiedad es de solo l e c t u r a y no se le p u e d e a s i g n a r un v al or. C o m o t o d a s las a p l i c a c i o n e s Windows Forms necesitan un bucle de mensajes par a que los mensajes de W i n d o w s p u e d a n ser e n v i a d o s al f o r m u l a r i o c o r r e c t o , las a p l i c a c i o n e s Windows Forms dev uelven True para esta propiedad.

452

ProductName
La propiedad de cadena ProductName devuelve el nombre del producto asociado a la aplicacin. Esta propiedad es de slo lectura y no se le puede asi gnar un valor. Por defecto, a este valor se le asigna el nombre de la clase que contiene el mt odo Main ( ) de la aplicacin. Si la aplicacin especifica un n om bre de producto con el at ri but o [AssemblyProduct ]. el valor de ese atributo se usa como el valor de la propiedad de la aplicacin ProductName.

ProductVersion
La propiedad de cadena ProductVersion devuelve el n mer o de versin asociado a la aplicacin. Esta propiedad es de slo lectura y no se le puede asi gnar un valor. Por defecto, este valor es 0 . 0 . 0 . 0. Si la aplicacin especifica un numero de versin con el at ri but o [ AssemblyVers ion ] . el valor de ese atributo se usa como el valor de la propiedad de la aplicacin ProductVersion.

SafeTopLevelCaptionFormat
La propiedad de cadena Sa f eTopLeveICapt ionFormat hace referencia a la cadena de formato que el tiempo de ejecucin aplica a los ttulos de la v entana de nivel superior cuando las aplicaciones se ejecutan desde un contexto no seguro. La seguridad es una parte integral de N E T Framevvork y el entorno comn de ejecucin (CLR). El C L R respeta la configuracin de las diferentes zonas de seguridad en Internet Expl orer (Internet. Intranet local. Sitios de confianza y Sitios restringidos) y restringe los serv icios de tiempo de ejecucin par a las apl i caciones que se ejecutan en zonas no fiables. Las aplicaciones Windows Forms que se ejecutan desde zonas no fiables, como la zona Internet, tienen una etiqueta de aviso que describe la aplicacin como procedente de una localizacion no fi a ble El texto de esta etiqueta de aviso esta bas ado en la plantilla de formato de cadena al macenada en la propiedad SafeTopLevelCaptionFormat.

StartupPath
La propiedad de cadena StartupPath devuelve la ruta al archivo ej ecut a ble que inici la aplicacin. Esta propi edad slo devuelve la ruta. No i nc li ne el nombre del archivo ejecutable. Esta propiedad es de slo lectura y no se le puede asignar un valor.

UserAppDataPath
La propiedad de cadena UserAppDataPath hace referencia a una ruta en el sistema de archiv os que puede us ar la aplicacin para a lmac enar datos basados en archivos que deberan estar disponibles par a el usuario de red que esta conec tado en ese momento al equipo local. Esta propiedad es de slo lectura y no se le puede asignar un valor. Es u sad a por los usuarios locales con perfiles de sistema operativo en la red. Los usuarios que tengan perfiles de equipo local no utilizados

453

en la red usan una propiedad distinta, llamada LocalUserAppDataPath. para especi fi car dnde deben a l m a c en ar s e los datos de la aplicacin. Al igual que la propi edad CommonAppDataPath. la ruta de datos de u s u a rio local seala a una carpet a incluida dentro de la carpet a de documentos de u s u a r i o c o n e c t a d o co n u n a e s t r u c t u r a de c a r p e t a s q ue t i e n e la f o r m a CompanyName\ ProductName\ ProductVersion. Los nombres de carpeta CompanyName. Pr oductName y ProductVersion se bas an en los valores de la aplicacin del mismo nombre. Si no se asigna un valor a estas propiedades, la clase Application propor ci ona unos valores vlidos por de fecto. Si el c di g o a s i g n a un v a l o r a las p r o p i e d a d e s C o m p a n y N a m e . ProductName o ProductVersion de la clase Application, los n o m bres de carpetas en la ruta de datos de la aplicacin de usuario local cambia para reflejar los valores de esas propiedades.

UserAppDataRegistry
El me'todo UserAppDataRegistry devuelve una referencia a un objeto de clase RegistryKey. Al igual que la propiedad CommonAppDataRegistry. la propiedad devuelve un objeto de tipo RegistryKey. El objeto RegistryKey devuelto hace referencia a una clave en el registro que la aplicacin puede usar par a al macenar datos de registro que slo deberan estar disponibles para el u s u a rio actual de la aplicacin. Esta propiedad es de slo lectura y no se le puede asi gnar un valor.

Mtodos Application
La clase Application admite ocho mtodos que pueden ser llamados desde las aplicaciones de C#. Estos mtodos se describen en las siguientes secciones.

AddMessageFilter
El mtodo AddMessageFilter ( ) aade un filtro de mensajes a la ap li ca cin par a controlar los mensajes de Wi ndows mientras los mensajes son enviados a sus destinos. El filtro de mensajes que se instala en la aplicacin recibe los mensajes de W indows antes de que se enven al formulario. Un filtro de mensajes instalado por AddMessageFilter () puede cont rol ar un mensaje que se le enve y puede decidir si el mensaje debe enviarse al formulario. El listado 2 1.4 muestra cmo se puede usar el filtro de mensajes en una apl ica cin Wi ndo ws Fo rms . El cont rol ador de mensajes b us ca mensajes que anunciar cuando se hace clic con el botn izquierdo en el formulario.
Listado 21.4. Cmo instalar un filtro de mensajes using using System; Syst em .W in do ws .Forms ;

454

public

class

B1ockLeftMouseButtonMessageFi1ter

: IMessageFi1ter

{
const const public int WM_LBUTTONDOWN = 0x20 1; int WM_LBUTTONUP = 0x202; bool P r e F il te rM es sa ge (ref Message == WM_LBUTTONDOWN) left mouse button is d o w n. "); m)

{
if(m.Msg

{
Co ns ol e . W r i t e L i n e ("The return true;

}
if(m.Msg == WM^LBUTTONUP) left mous e button is up.");

{
Console.WriteLine ("The return true;

}
return false;

public

class M a m F o r m

: Form

{
public static void M a i n ( )

{
M a m F o r m MyForm = new M a m F o r m () ; BlockLeftMouseButtonMessageFilter MsgFilter B l o c k L e f t M o u s e B u t t o n M e s s a g e F i l t e r (); Ap p l i c a t i o n . A d d M e s s a g e F i l t e r ( M s g F i l t e r ) ; A p p l i c a t i o n .R u n ( M y F o r m ) ; = new

}
public MamFormO = "Message Filter Test";

{
Text

El mtodo AddMessageFilter ( ) rccibc un argumento: una implementacin de una interfaz llamada IMessageFilter . La interfaz IMessageFilter es d ef in i da p o r N E T F r a m e w o r k y se i ncl uye en el e s p a c i o de n om b r e s System. Windows .Forms. IMessageFilter declara un mtodo:
public bool PreFilterMessage (ref Message m) ;

El mtodo PreFilterMessage () toma como entrada una referencia a una instancia de una estructura llamada Message La estructura Message describe un mensaje de Wi ndo ws y contiene las siguientes propiedades:

HWnd. que describe el controlador de la ventana que debe recibir el m ens a


je

455

L P a r a m . que describe un fragment o de n mero entero que se enva con el mensaje. Ms g. que describe el numero entero ID asociado al mensaje. Cad a men saje de Wi ndows tiene su propio ID entero R e s u l t . que describe el valor que debe devolverse a Wi ndows en res puesta al control del mensaje. WP a r a m. que describe otro fragment o de nmero entero que se enva con el mensaje. El listado 21. 4 co mi en za d e c l a ra nd o una clase l la ma da B l o c k L e f t M o u s e B u t t o n M e s s a q e F i i t e r . E s t a c l a s e i m p l e m e n t a la i n t er f a z I M e s s a g e F i 1 t e r . La implement aci n del mtodo P r e F i l t e r M e s s a q e ( ) de la clase c omp ru eb a el ID del mensaje pasado al mtodo. C om pr ue ba si el ID indica que se ha pulsado el botn izquierdo del ratn. En caso afirmativo, se escribe en la consola el mensaje T h e l e f t m o u s e b u t t o n i s d o wn . A continuacin com pr ue b a si el ID indica que se ha soltado el botn izquierdo del ratn. En caso afirmativo, se escribe en la consola el mensaje T h e l e f t m o u s e b u t t o n i s up.

NOTA: La clase BlockLef tMouseButtonMessageFilter declara constantes para dar nombres a los mensajes de Windows que busca el filtro. Los nombres empiezan con WM (por Mensaje de Windows) y coinci den con los nombres definidos por Microsoft. Todos los mensajes de Windows disponibles y sus valores numricos estn explicados en la docu mentacin de Platform SDK de Microsoft.

Las implement aci ones del mtodo P r e F i l t e r M e s s a q e ( ) deben devolver un valor booleano que describe si el mensaje debe ser enviado al formulario tras pas ar por el filtro o no Si el filtro considera que el mensaje no debe ser enviado, entonces dev uelve T r u e . Si el filtro considera que el mensaje debe ser env iado, entonces dev uelve el valor F a i s e . El filtro de mensajes del listado 2 1.4 devuelve T r u e para los dos mensajes que controla y F a l s e para todos los dems m en s a jes. El mtodo M a i n ( ) en el listado 21.4 crea un nuevo objeto de la clase B l o c k L e f t M o u s e B u t t o n M e s s a g e F i l t e r y lo usa en una llamada al mtodo A d d M e s s a g e F i 1 t e r ( ) del objeto A p p l i c a t i o n . Tras instalar el filtro de mensajes, se crea y ejecuta el formulario principal. Puede ver el filtro de mensajes en accin compilando el listado 2 1 4. Al ejecu tar el codigo. aparecera el formulario principal de la aplicacin. Cuando aparezca el formulario, muev a el ratn par a que el cursor est dentro del formulario y haga clic con el botn izquierdo del ratn. Se escribir en la consola un mensaje indi cando que ha pul sado un boton del ratn.

456

DoEvents
El mt odo DoEvents ( ) procesa todos los mensajes que se encuentren en la cola de mensajes de la aplicacin de Windows. El mtodo no recibe a rgumentos m devuelve ningn valor. Este mtodo se invoca cuando se quiere estar seguro de que los mensajes en espera de Wi ndows se envan al formulario mientras se reali zan otras tareas. Suponga, por ejemplo, que crea un formulario que realiza un calculo largo. Si se mueve otra ventana delante del formul ari o mientras se realiza el calculo. Wi ndows env a a la aplicacin un mensaje de Wi ndows que ndica que el f o r mu lario debe ser dibujado de nuevo. Sin embargo, como el eodigo esta realizando un enorme clculo, el mensaje de nuevo dibujo est ar a en la cola de mensajes de la aplicacin; despus de todo, el eodigo est ocup ado realizando clculos y no procesando mensajes. Se pueden hacer llamadas al mtodo DoEvents ( ) en ciertos puntos del proceso par a a se gurarnos de que los mensajes de espera de Wi ndows se procesan mientras el eodigo esta ocup ado realizando otro trabajo.

Exit
El mt odo Exit ( ) obliga a la aplicacin a terminar. El mtodo informa a la cola de mensajes de la aplicacin que debe finalizar y cierra los formularios cuando se procesa el ultimo mensaje de la cola de mensajes de Windows. Por lo general, el eodigo no necesita inv ocar al mtodo Ex i t (). Los for mul a rios de Wi ndo ws incluyen por defecto un cuadro de cierre en la esquina superior derecha del formul ari o v al hacer clic en ese cuadro se enva un mensaje de cierre a la cola de mensajes de Windows. Sin embargo, puede ser til llamar a Ex it ( ) si el formul ar io incluye un control, como un botn o un elemento de men que debe finalizar la aplicacin al ser seleccionado.

ExitThread
El mtodo ExitThread ( ) sale del bucle de mensajes y cierra todos los formularios en el subproceso en curso. El mtodo 110 recibe argumentos 111 devuel ve ningn valor. Si la aplicacin WindowsForms contiene un solo subproceso (como es habitual), entonces la accin de llamar a ExitThread ( ) es igual que a llamar a Ex i t (). Sin embargo, si la aplicacin usa v a n o s subprocesos. enton ces los dos mtodos se comportan de forma diferente. El mtodo Ex itThread ( ) cierra un subproceso pero permite que los otros s ubprocesos sigan ejecutndose Sin embargo, el mtodo Exit ( ) . cierra todos los subprocesos a la vez. Como todos los procesos de Wi ndows, las aplicaciones W indowsForms siguen ej ecu tndose hasta que finaliza el ltimo subproceso.

OleRequired
El mtodo OleRequired ( ) inicializa OLE en el subproceso en curso de la aplicacin. Si la aplicacin va a trabajar con tecnologa COM. como COM. DC'OM.

457

ActiveX o OLE. se debe llamar a este mtodo de la aplicacin antes de usar COM El mtodo no recibe argument os, pero devuelve un valor desde una e nu m e r a cin l lamada Apartment State que describe el tipo de a p ar tamen to que intro dujo el subproceso. La enumeracin Apartment State est definida en un espacio de nombre N E T Framework llamado S y s t e m .Threading y puede tener uno de los siguientes valores: STA. se devuelve cuando el C LR decide inicializar C OM para el subproceso entrando en un a pa rt amen to de un nico subproceso. M T A . se d ev ue lv e c u a n d o el C L R decide i n i c i al i za r C O M p a r a el s ubproces o entrando en un apa rt amen to de multiproceso.

OnThreadException
El mtodo OnThreadException ( ) desencadena un evento ThreadException. El evento puede ser ca pt ur a do por un cont rol ador de eventos OnThreadException ( ) instalado en el objeto Application. El listado 21.5 muest ra cmo puede usarse una excepcin de subproceso en una aplicacin WindowsForms.
Listado 21.5. C mo trabajar con excepciones de subprocesos using using using S ys tern; S ys t e m .T h r e a di ng ; S ys t e m .W i n d o w s .F o r m s ; BlockLef tMous eButtonMessageFilter = 0x20 1; m) : IMessageFi 11er

: class p u b i ic

{
const public int WM_LBUTTONDOWN bool

P r e F i It er Me ss ag e(ref Message == WM_LBUTTONDOWN) LeftButtonDownException;

{
if(m.Msg

{
Exception LeftButtonDownExcept 1 on = new Exception("The left mouse button was p re s s e d . " ) ; A pp li ca ti on .O nT hr eadException(Le ftButt onDownException) ; return true;

}
return false;

} }
public class void A p p l i c a t 1 onEventHandlerC1ass On Th r e a d E x c e p t i o n (object sender,

{
public

458

T h r e a d E x c e p t i o n E v e n t A r g s e)

{
Exception LeftButtonDownException; LeftB uttonDownException = e . E x c e p t i o n ; C o n s o l . W r i t e L i n e (L e f t B u t t o n D o w n E x c e p t i o n . M e s s a g e ) ;

} }
public c l a s s MamFor m : Form static v o i d M a i n ()

{
public

{
A p p l i c a t i o n E v e n t H a n d l e r C l a s s A pp Ev en ts = new A p p l i c a t i o n E v e n t H a n d l e r C l a s s (); MainForm MyForm = new Ma mFo rm( ) ; B l o c k L e f t M o u s e B u t t o n M e s s a g e F i l t e r M s g F i l t e r = new B l o c k L e f tMous e But t onMe s s a g e F i l t e r () ; App1 i c a t i o n . A d d M e s s a g e F i 1t e r ( M s g F i l t e r ) ; A p p l i c a t i o n . T h r e a d E x c e p t i o n += new T h r e a d E x c e p t i o n E v e n t H a n d l e r (A pp E v e nt s . OnThr e a d E x c e p t i o n ) ; A p p l i c a t i o n . Run (My Fo r m) ;

}
public MainFormO = "A pplication Exception T est";

{
Text

} }
El l istado 21.5 es p a re c i d o al li st ado 2 1. 4 ya q ue i ncluye un c o n t r o l a d o r de m e ns aj es que b u s c a m e nsa je s que i nf or ma n c u a n d o se pu ls a el botn izqui er do del r at n en el f o r m u l a r i o de la a p l i ca c i n La d if er en ci a es qu e en el l ist ado 21. 5 se inicia un a e xc e pc i n al recibir el m e n s a j e l e f t m o u s e b u t t o n d o w n . El c o nt r o l a d o r de m e n s a j e s crea un n u e v o o b j e t o E x c e p t i o n y lo i n i c i a u s a n d o el m t o d o O n T h r e a d E x c e p t i o n ( ) del obj et o A p p l i c a t i o n . El c odi go del li st ad o 2 1.5 tambin i n c l i n e un c o n t r o l a d o r de e v e nt os de la a p li c a c i n , que se i m p l e m e n t a en una clase l l ama da A p p l i c a t i o n E v e n t H a n d l e r C l a s s . E s t a cl ase controla el e v e n t o O n T h r e a d E x c e p t i o n ( ) v el m t od o pri nci pal de la apl icaci n i nstala el c o n t r o l a d o r de e ve nt os u s a n d o la p r o p i e d a d T h r e a d E x c e p t i o n del o b j e t o A p p licatio n . El c o n t r o l a d o r de e x c e p c i o n e s del s u b p r o c e s o i n s t a l a d o en la c l a s e A p p l i c a t i o n E v e n t H a n d l e r C l a s s e x t r a e la e x c e p c i n del o b j e t o T h r e a d E x c e p t o n E v e n t A r g s del c o n t r o l a d o r y e s c r i b e el m e n s a j e de la e xc e pc i n en la consol a. C u a n d o se e jecut a el codigo en el listado 21.5. a p a r e c e el f o r m u l a r i o pri nc ipa l de la a pl ic ac i n. C u a n d o a p a r e z c a el formulario, m u e v a el r at n h a ci a su interior y h a g a clic con el bot n i zquier do del ratn. El controlador

459

de mensajes iniciara una excepcin y el cont rol ador de excepciones de la a p l i c a cin escribir mensajes de excepcin en la consola de la aplicacin.

RemoveMessageFilter
El mt odo RemoveMessageFilter ( ) elimina un filtro de mensajes i nsta lado por el mtodo AddMessageFilter (). Elimina el filtro de mensajes del generador de mensajes de la aplicacin. El mtodo RemoveMessageFilter ( ) recibe un argumento: una i mplementacin de una interfaz llamada IMessageFilter. Este ar gument o debe hacer referencia a una clase que implemcnta IMessageFilter y que ya ha sido usada en una llamada a A ddMessage Filter ( ) . El listado 2 1.6 muest ra cmo funciona este mtodo.
Listado 21.6. Cmo eliminar un filtro de mensajes instalado using using public System; System. Wi nd ow s.F o r m s ; class B 1o c :kLe f tMous eBut t onMes s age Fi 11 e r : IMessageFilter

{
const public int W M _ L BUTTONDOWN = 0x201; bool PreFilterMessage(ref == WM_LBUTTONDOWN) is down."); Message m)

{
if(m.Msg

{
C o n s o l e . W r i t e L m e ("The left mouse button A p p 1 1 cat i o n .RemoveMe ssageFilter (this) ; return true;

)
return false;

} }
public class M a m F o r m static : Form

{
public void M a i n ( )

{
MainForm MyForm = new MainForm() ; BlockLeftMouseButtonMessageFilter MsgFilter B 1oc k L e f t M o u s eB ut to nM es sa ge Fi 11er ( ); A p p 1 1 c at i o n .AddMessageFilter (MsgFilter) ; A p p l i cat i o n .Run(MyForm) ; = new

)
public; M a m F o r m f )

{
Text = "Message Filter Removal Test";

} }

460

El codigo del listado 21.6 nstala un filtro de mensajes que bus ca el mensaje left mouse button down. igual que haca el listado 2 1.4. La diferencia es que la implementacin del filtro de mensajes en del listado 21.6 elimina el filtro de mensajes cuando se recibe el mensaje. Observe que. cuando se ejecuta el cdigo del listado 21.6. solo se escribe un mensaje en la consola, independientemente del numero de v eces que pulse el boton izquierdo del ratn con el punt ero sobre el formulario. Esto es debido a que el filtro de mensajes es eliminado de la aplicacin c uando se recibe el primer m en s a je y. como se elimina el filtro de mensajes, no se pueden detectar nuevos mensajes. Todav a se env an mensajes al formulario, pero el codigo del listado 2 1.6 elimina el objeto que detecta por pri mera vez los mensajes despus de que se haya elimi nado el objeto de la lista de filtros de eventos de la aplicacin.

TRUCO: El listado 21.6 usa la palabra clave t h i s como parmetro para la llamada al mtodo R e m o v e M e s s a g e F i l t e r ( ) del objeto Application. Recuerde que la palabra clave this se emplea para ha cer referencia al objeto cuyo cdigo se est ejecutando. Puede pensar en la instruccin del listado 21.6 que llama a RemoveMessageFilter ( ) como si indicara "elimina la referencia a este filtro de mensajes del objeto Application".

Run
El mtodo Run ( ) inicia el bucle de mensajes de Wi nd ows par a una ap l ic a cin. Todos los listados de este captulo han usado el mtodo Run (). que acepta como p ar met ro una referencia a un objeto de formulario. Ya debera estar f ami liarizado con el f uncionamiento del mtodo Run ().

Cmo aadir controles al formulario


El formulario que las aplicaciones WindowsForms crean por defecto no es muy interesante. Tiene una b ar r a de ttulo, un icono por defecto y los botones est andar de Wi nd ows Minimizar. M ax imi zar y Cerr ar Los formularios que en contramos en las aplicaciones reales incluyen controles como botones, cuadros de texto, etiquetas y elementos similares. Esta seccin explica como aadir controles a los formularios de las aplicaciones C#. En esta seccin, examinaremos cmo se implementan los controles desde NE T Framcvvork. El entorno de desarrollo dispone de compatibilidad de clases N E T par a los controles integrados en el sistema operativ o Wi ndows, y los ejemplos de esta seccin muest ran su uso en la creacin de aplicaciones Windows Forms que usan controles en los formularios de la aplicacin.

461

Jerarqua de las clases de control


N E T F r a m e w o r k i n c l u y e v a r i a s c l a s e s en el e s p a c i o de n o m b r e s

S y s t e m .Windows .Forms par a encaps ul ar el comport ami ent o de un control.


Los elementos de interfaz de usuario, como botones, cuadros de texto, casillas de verificacin y elementos similares, estn representados por una clase de control. Todas estas clases se derivan de una clase base llamada Control. La figura 21.2 muest ra la j erarqua de clases de las clases de control. Todos los controles de la interfaz de usuario compart en al guna funcionalidad: todos deben ser capaces de situarse en su contenedor y gest ionar sus colores de pri mer plano v de fondo. Como todos los controles comparten este comportamiento, es lgico encapsularlo en una clase base y derivar la funcionalidad especfica al control en las clases derivadas. Los autores de las clases de control de N E T Framework adoptaron este enfoque al construir las clases.

Cmo trabajar con controles en un formulario


El listado 21.7 muest ra una aplicacin WindowsForm que incluye un boton. El botn incluye un mensaje en un cuadro de texto al hacer clic.
Listado 21.7. Cmo trabajar con un botn en un formulario using System; u sin g Sy stem.Drawing; u s m g System.Windows .Forms ; public class MainForm static : Form

{
public v oid Main()

(
MainForm MyFcrm = new M a m F o r m f ) ; A p p 11 cat i o n .Run(MyForm) ;

I
public MainFormO = new B u t t o n ();

{
Button MyButton

Text - "Button Test"; MyButton.Location - new P o i n t (25, 25); M y B u t t o n .Text - "Click Me"; MyButton.Click new EventHandler (MyButtonCiicked) ; Controls.Add(MyButton);

}
public void MyButtonCiicked(object Ar y u m e n t s ) sender, EventArgs

462

{
M e s s a g e B o x .S h o w ("The button has been clicked.")

Figura 21.2. Jerarqua de las clases de control

463

El listado 21.7 muest ra varios conceptos importantes que deben tenerse en cuenta cuando se trabaja con controles Windows F o r m s . Estudie el constructor del primer formulario. Crea un nuevo objeto de clase Button v establece su posicion en el formul ari o con la propiedad Location del botn. Esta propiedad se hereda de la clase Control (lo que significa que la propiedad esta disponible par a cualquier control derivado de la clase Contro 1) y establece la posicin de la esquina superior izquierda del boton respecto a su contenedor. En el listado 21.7. la posicin del boton se establece a 25 pixeles a la derecha del borde iz quierdo del formulario y a 25 pixeles por debajo de la parte superior del f o r mu l a rio. La posicin se establece con una nueva instancia de una est ructura llamada Poi nt. que esta disponible en el espacio de nombres System. Prawi nq de N E T Framevvork:
MyButton .I.ocat ion - new Point (2 5, 2 5) ;

TRUCO: El listado 21.7 usa la propiedad L o c a t i o n para establecer la ubicacin del control. El uso de esta propiedad para que el programa colo que los controles puede suponer demasiado trabajo en formularios compli cados con muchos controles. Visual Studio NET dispone de un diseador de formularios que permite, de forma visual, arrastrar y colocar controles en formularios. El diseador crea a continuacin los formularios C# equi valentes, liberando al programador de la tarea de tener que codificar toda la lgica de posicionamiento por s mismo.
El siguiente concepto importante del listado 21.7 est relacionado con el c o n trol de eventos de un control. Las clases de control admiten muchos eventos que se desencadenan cuando el usuario i nteracta con el control. Muchos de estos ev entos se incluyen en la clase base Contro l. aunque la clase de control especi fica controla otros ev entos. El ev ento mas evidente de un botn de control sera un evento CJlick. Los botones de los formularios no son de utilidad a menos que puedan responder a una accin de un usuario que haga clic con el boton. Los controles de N E T Framevvork usan el modelo es tndar delegado/evento para compatibilizar sus eventos. Los ev entos de control se instalan usando instan cias de un delegado llamado EventHand 1e r . Este delegado admite dos a r g u mentos. un objeto que especifica el elemento que envi el evento y un objeto de una clase llamada EventArqs que en caps ul a los ar gument os del evento. El cdigo del formul ar io del listado 21.7 incluye un mtodo llamado MyButtonC 1 icked que modela el delegado EventUandler. Este mtodo se usa como un nuevo cont rol ador de eventos y est conect ado al evento C1 ick del boton:
My But ton.Clic k < - new EventHancller (MyButtonC 1 1 cked) ;

La clase Forrn controla el evento Click del botn mos trando un cuadro de texto. Una clase llamada MessaqeBoz admite la vsualizacion de cuadros de

464

mensajes de Wi ndows La clase M e . s s a g e B o : : contiene un mtodo esttico ll amado S h o w ( ) que muest ra un mensaje en un cuadro de mensaje H 1 ultimo concepto importante del listado 21.7 es la instruccin que agrega el control a la forma:

Co n t os

.Acid ( M y B u 11 o n ) ;

La propiedad C o n t r o l esta definida en la clase base C o r h r o , (recuerde que la clase F o r r a se deriva de la clase C o n t r o ). Ls un objeto de una clase l lamada C o n t r o 1 s C o i l e e t i o n \ gestiona una lista de controles secundarios que son gestionados p or el control actual. Fl eodigo W i n d o w s F o r ir s debe a a dir controles a su coleccin C o n t r o l s de los formularios contenedores antes de que pueda ser usada realmente.

Cmo trabajar con recursos


En Windows, los recursos se definen como datos que forman parte de una aplicacin pero no afectan a la ejecucin del cdigo. Estos recursos pueden ser iconos, mapas de bits o cadenas. El sistema Wi n d o w s F o r n . s permite a lmacenar los recursos en un archivo separado durante el desarrollo del p ro gr ama e incluir los en un ensambl ado cuando se distribuya la aplicacin. La principal ventaja de g ua r da r los recursos de la aplicacin en un archivo separado es que ayuda al desarrollo del programa. Si incrustamos todas las c ade nas dentro del eodigo C#. por ejemplo, entonces solo alguien que conozca C'# s abi a donde buscar par a ca mbi ar los valores de cadena. Si la aplicacin se escri be usando cadenas en ingles v luego es necesario c amb ia r la aplicacin para que muestre cadenas en alemn, h a b a que leer todo el codigo fuente > ca mbi ar todas las cadenas. Si g uar damos las cadenas en un archivo de tabla de cadenas aparte, podemos aplicar un t raduct or a ese archivo separado para que traduzca las c ad e nas en ingles a su equivalente en alemn sin ca mbi a r el codigo CU fuente. En el eodigo de la aplicacin, el cdigo dir "lee una cadena de la tabla de cadenas" en lugar de teclear la cadena en el codigo de la aplicacin.

Cmo trabajar con recursos de cadena


Los recursos de cadena se definen en un archivo de texto separado, que debe tener la extensin . t : : t . El archivo debe contener un conjunto de pares clave, valor, separados por el signo igual. La clave para cada cadena debe ser un n om bre nico para la cadena que se v a a usar en el eodigo CU para hacer referencia a ella. El valor de cadena real se escribe tras el signo igual. Se pueden colocar comentarios en los archivos de t abla de cadenas. Los comentarios comienzan con el smbolo de la libra y llegan hasta el final de la lnea. El listado 21.8 muestra un ejemplo de archivo de tabla de cadenas. El archivo contiene una cadena c u \ o

465

nombre de clave es Message y cuyo valor es Helio ta b le !

from the

string

Listado 21.8. Ejemplo de un archivo de texto de una tabla de cadena

# String Table

# = == = =- =- - -= -=
Message - Helio from the string table!

Los archivos de t abla de cadena deben compilarse par a for mar un ensamblado de modo que las aplicaciones C# puedan leerlos. Esto se hace con una herramien ta llamada R e s G e n . La herramienta R e s G e n se incluye en el S DK de NET Framework. Es una aplicacin de consola que lee el archivo de texto y produce una representacin binaria de la tabla con extensin r e s o u r c e s . Si la tabla de cadena del listado 2 l .8 se escribe en un archivo de texto llamado L i s t i n g 2 1 8 .txt. puede compi lar la tabla de cadenas usando la siguiente lnea de coman dos:
resgen Listing21-8.txt

Esto produce un archivo llamado Listing2 1-8 .resources. Tras com pilar un archivo resources p ar a la aplicacin, se puede compilar en el e ns am blado usando el ar gument o /res par a el compi lador de C#. como muest ra la siguiente lnea de comando:
ese /res:string.resources /o u t :t e s t .exe test.es

Esta lnea de comando ordena al compi lador de C# que cree un ejecutable llamado test, exe a partir del archivo fuente de C # test.es. T ambi n le ordena incrustar en el ejecutable test, exe los recursos que encuentre en el archivo str ing .resources. C omo los recursos estn i ncrustados en el eje cutable. slo se necesita env iar el ejecutable cuando se distribuye la aplicacin. El archivo de recursos binarios no es necesario en tiempo de ejecucin. Una vez que se han incrustado los recursos en la aplicacin, se pueden leer desde el codigo de CU. El listado 21.9 es una modificacin del listado 2 1.7. en el que el mensaje del c ua dro de mensajes se lee desde un recurso de cadena.
Listado 21.9. Cmo leer desde un recurso de cadena using usmg us ing using using public System; System. D r a w m g ; S ys t e m .W i n d o w s .F o rms ; Sy st em .Resources; System.Re f 1ection; class M a m F o r m static : Form

{
public void M a i n ( )

466

{
M a m F o r m MyForm = new M a m F o r m ( ) ; Application.Run(MyForm);

}
public MamFormO = new B u t t o n ();

{
Button MyButton

Text = "Button Test"; M y B u t t o n .Location = new P o i n t (25, 25); M y B u t t o n .Text = "Click M e "; M y B u t t o n .Click += new EventHandler (MyButtonClicked) ; Controls.Add(MyButton);

}
public void M y B u t t o n C l i c k e d (object Arguments) sender, EventArgs

{
ResourceManager FormResources ResourceManager ("StringTable" , As s embl y .GetExecut m g A s semb 1 y () ) ; s t n n g Message; = new

Message = FormRes our ces .Ge tS t r m g ("Mes s age ") ; M e s s a g e B o x .Show(Message) ;

} } El listado 2 1.9 se compila con un recurso de tabla de cadenas cuyo archivo de texto contiene lo siguiente: #===========-=
# Stnng Message Table = The button has been clicked.

#===========-Este archivo de texto recibe el nombre de Str ingTabl e .t::t y se compila formando un archivo de recursos binario llamado StringTable .resources mediante la siguiente lnea de comando:
resgen S t r i ng Ta bl e.txt

Este comando produce un archivo llamado StringTable. rosources. Este recurso se vincula a la aplicacin cuando se compila el cdigo C# principal mediante la siguiente lnea de comando:
ese / r e s :S t r i ng Ta bl e.resources Listing21-C .cs

Se pueden leer recursos en las aplicaciones de C# usando una clase de NE T F ramework llamada ResourceManager. que se i ncl i ne en un espacio de nom-

467

bres llamado Gystem. Resources. El cdigo del listado 2 1 . c ) crea un nuevo objeto PesourceManager par a gestionar los recursos incrustados en el ejecu table. El const ructor recibe dos argumentos: El nombre base del archivo de recursos binarios que contiene el recurso que se esta abriendo. Se debe especificar este nombre, aunque no se nece sita el archivo fsico porque el ensambl ado a gr up a los recursos en bloques y da nombre a los bloques usando el nombre base del archivo de recursos binarios original. Una referencia al ensamblado que contiene los recursos que se estn a brien do. Este par met ro es una referencia a un objeto de una clase llamada Assembly. que se e n c u en t ra en el e spa ci o de n ombr es System. Ref leetion. Como los recursos que se estn abriendo estn i ncrus ta dos en el ensambl ado que se est ejecutando, si se llama al mtodo esttico Ge t E e c u 1 1 nqAs sernb 1y () se dev olv er una referencia al e n s a m blado actual. Tras micializar el objeto PesourceManager. las cadenas se pueden abrir desde el a dmi ni str ador mediante un mtodo llamado GetStr i ng (). Este metodo recibe un argument o de cadena: el nombre de clave de la cadena que se recupe ra. El mtodo devuelve el v alor de la cadena n om br ada por la clav e.

Cmo trabajar con recursos binarios


Las tablas de cadenas basadas en texto no son los nicos recursos que se pueden i ncrustar en los ensamblados. Tambi n se pueden i ncrust ar recursos binarios, como grficos e iconos. Los recursos binarios estn codificados, me diante codificacin BASE64 . en un document o X M L con un formato especial Este d ocument o X M L tiene la extensin . resx y es compilado p ar a for mar un archivo de recurso mediante resgen. A partir de aqu, puede usar los mtodos de la clase ResourceManager p ara t rabaj ar con los recursos binarios como si fueran recursos de texto. Desafortunadamente, el S DK de N E T Framevvork no incluye una herramienta par a generar documentos X M L con codificacin B AS E6 4 a partir de entradas de archivo binario. Sin embargo. Visual Studio N E T permite incrustar recursos binarios en los ensamblados.

Resum en
Este capitulo estudia los fundament os del proceso de desarrollo par a la el abo racin de aplicaciones WindovvsForms en C#. Tambi n se estudian algunas clases e l e me n ta l e s, c om o la c las e A p p l i c a t i o n , que g e s t i o n a la a p l i c a c i n

468

W i n do ws F or ms como un todo y la clase Form. que gestiona un formulario de la aplicacin. Tambi n se hace un repaso a la arquit ect ura de las clases de control W in do ws F or ms y se exami nan los atributos de ens ambl ado que pueden agregar informacin de versin y descriptiva al ensamblado. N E T Framcwork contiene un variado conjunto de clases para el aborar apl i ca ciones Wi ndowsForms . El subsistema W in d ows Fo rm s esta c ompuest o por varias clases; por desgracia, las limitaciones de espacio no permiten una compl et a des cripcin de todas ellas en este libro. Puede exa mi na r la document aci n de cada clase WindowsForms. Use los conceptos de este captulo par a comenz ar a investigar todas las clases del espacio de nombres WindowsForms.

469

VwX

Cmo crear aplicaciones Web con WebForms

La ltima dcada ha sido testigo del crecimiento sin precedentes de Internet como p lat af orma de negocios. Hoy en da. la may ora de los modelos de negocios estn basados en. o al menos incluyen, el concepto de Internet. Por tanto, el enfoque ha c ambi ado de las aplicaciones de escritorio a las aplicaciones Web. Este ca mbi o ha subray ado la necesidad de tecnologas que puedan simplificar el desarrollo de aplicaciones Web. Para crear aplicaciones Web, N E T Framework incluy e A S P .N ET . que es la nueva versin de ASP 3.0. Se pueden crear aplicaciones en A S P . N E T usando Visual Basic N E T o Visual C# como lenguaje de progr amaci n del servidor. Visual C# permite a los prog ramad ore s desarrollar potentes aplicaciones Web. Pero lo ms importante es que ay uda a los progr amadores a luchar contra los ciclos cada vez ms rpidos, porque les permite realizar ms operaciones con menos lneas de cdigo y con menos errores, lo que reduce consi der abl ement e el coste del proyecto. Aunque par a crear aplicaciones Web A S P . N E T slo se necesita un editor de texto, como el bloc de notas, lo ms habitual es usar una p lat af orma de de sa r ro llo. como Visual Studio NET. que p ropor ci ona un enorme conjunto de he r ra mientas para disear pginas Web. En comparacin con los primeros lenguajes de programaci n de pginas Web, en los que haba que realizar una gran cantidad de codificacin. Visual Studio N E T p ropor ci ona de una interfaz W Y S I W Y G . Esta

471

mterfaz permite ar ras trar y colocar controles en We bFor ms . que luego pueden ser pro gr amadas en Visual ('#. Al pr og ramar en Visual Studio . NET se puede s e pa rar el contenido en codigo y en H T M L de un WebForm. Esto hace que resulte muv sencillo s epa rar la progr amaci n lgica de la presentacin lgica, lo que nos permite concent rarnos en i mplementar la funcionalidad del proyecto, mas que en la presentacin de datos En este capitulo aprenderemos a crear una aplicacin Web A S P . N E T med ian te Visual CU. Mientras creamos la aplicacin, disearemos un W e bF or m que usa controles de servidor, como etiquetas, c ua dr os de texto, c ua dr os de listas, hiperv metilos y botones. Por ultimo, aprenderemos a controlar los ex entos g ene rados por los controladores de servidor.

Fundamentos de las aplicaciones ASP.NET Web


Las aplicaciones Web A S P . N E T son aplicaciones que se emplean en ser vido res Web Estas aplicaciones forman uno o mas W e b Fo r ms pr ogr amados en Vi sual C# o Visual Basic NET. En esta seccin, estudiaremos las ventajas y desventajas de las aplicaciones W'eb A S P . N E T y como crear aplicaciones A S P . N E T con Visual C#. Tambin estudiaremos las diferencias entre las aplicaciones A S P . N E T \ ASP 3.0.

Nuevas caractersticas de ASP.NET


A S P . N E T incluye algunas nuevas caractersticas que no estaban presentes en ASP 3.0. En esta seccin se describen brevemente estas caractersticas.

Ejecucin en el entorno .NET Framework


En compar aci n con los primeros lenguajes de progr amaci n Web. las a p l ic a ciones en Visual C# (y otros lenguajes Visual Studio NE T) se ejecutan en el entorno del marco de trabajo NET. As. estas aplicaciones son independientes del navegador cliente y funcionan de la misma manera en todas las pl at aformas clien te. Otra ventaja de usar un tiempo de ejecucin diferente para A S P . N E T es que las aplicaciones ASP 3.0 pueden coexistir con las aplicaciones A S P. NE T. Asi. se pueden us ar sitios Web ASP 3.0 y A S P . N E T en el mismo servidor W'eb.

Presentacin de WebForms
Los W c h h o n n s son la base de una aplicacin basada en Web. La aplicacin Web los usa para mt eraet uar con el usuario. Un We bFor m puede incluir van os controles de serv idor. como cuadros de texto, etiquetas, cuadros de listas, botones

472

de opcion. casillas de verificacin y botones. los cuales facilitan la interaccin del usuario con la aplicacin. Un W e b Fo r m consta de dos componentes, la interfaz de usuario (1U) > la lgica de la aplicacin (aplicacin). La interfaz de usuario es el componente v isual de un We bFo rm. Se c ompone de H T M L y controles especficos de la a pl i cacin Web. La interfaz de usuario es el contenedor del texto y los controles que deben apa rec er en la pagi na Web. Se especifica en un archivo con la extensin .c iS p X . La lgica de progr amaci n de una aplicacin Web de ASP N E T esta en un archivo s eparado que contiene el cdigo e nc arga do de controlar las interacciones del usuar io con el formulario. Este archivo recibe el nombre de archivo de "codi t o o c u l t o ". Cuand o se ejecuta un formulario escrito en C'#. el archivo de cdigo oculto genera di nmi cament e el resultado H T M L de la pagina. El archivo de codigo oculto de C# tiene una extensin . a s p : - : . e s La ventaja de s eparar el cdigo del contenido es que el pr og ramad or no necesi ta concentrarse en la lgica que se usa par a mos trar el resultado El diseador Web puede controlar esta tarea.

Integracin con Visual Studio .NET


Visual Studio . NET es la herramienta de desarroll rpido de aplicaciones para ASP.NET. Visual Studio .NET ofrece una completa integracin con AS P. NET v permite ar r as t ra r y colocar controladores de serv idor y disear W e b Fo r ms con el aspecto que tendrn cuando un usuario los vea. Algunas de las otras ventajas de crear aplicaciones A S P . N E T con Visual Studio . NET se resumen en la siguiente lista: Visual Studio NE T es una herramienta de desarrollo rapida de apl icaci o nes (RAD). En lugar de aadir cada control al We b Fo r m mediante p r o g r a macin. le ayuda a aadir estos controles usando el cuadro de herramientas, ahorrndole trabajo de programacin. Visual Studio N E T admite controles personalizados y compuestos. Se pueden crear controles personalizados que encapsulen una funcionalidad comn cuy o uso puede ser necesario en varias aplicaciones, del mismo modo que se usan los controles Web A S P . N E T proporci onados por Visual Studio .NET.

Presentacin de los controles de servidor


Ademas de los controles H T ML que existan en la poca de ASP 3.0. A S P . NE T presenta controles de servidor que son componentes de una aplicacin Web que se ejecutan en el servidor y encapsul an la funcionalidad de la aplicacin. Los controles H T M L hacen referencia a los elementos H T M L que se pueden usar en los We bFo rms . Por lo general, cuando los controles H T M L se envan al serv idor a trav s del nav egador, el serv idor considera que los controles H T M L

473

son opacos. Es dccir. el servidor no los procesa. Sin embargo, al convertir estos controles en controles de serv idor H T M L pueden quedar a la vista del servidor par a que realice el proceso. Mediante el uso de atributos, como ID y RUNAT. se pueden convertir los controles H T M L en controles de servidor H T ML . Puede aadir estos controles a un We b Fo r m usando la ficha H T M L del cuadro de he r ra mientas. Por otra parte, los controles de servidor son completamente t r an s p a r e n tes p ar a la aplicacin y permiten al p rog ra ma dor controlar eventos del lado del servidor par a gestionar la aplicacin Web. Apart e de los cuadros de texto convencionales, esta categoria de controles tambin incluye los controles de validacin. Los controles de validacin son con troles progr amabl es que ayudan a validar las entradas del usuario. Por ejemplo, se pueden usar estos controles par a validar el valor de un campo o el patrn de caracteres introducido por el usuario. Para validar la entrada del usuario, es necesario adj unt ar estos controles a los controles de la entrada.

Controles de usuario y compuestos


Si quiere dupl icar un conjunto de controles en varias pginas, puede crear controles en cada formulario por separado. Esta no es una opcin muy til. Sin embargo. A S P . N E T nos permite realizar esta operacin mediante los controles de usuario y compuestos. Los controles de usuar io son W e b F o r m s normales que hemos convertido en controles eliminando las etiquetas <HTML> y <FORM> del control. As. represen tan una unidad de codigo y presentacin que puede import arse a otro WebFor m. Ot ro conjunto de controles disponibles en A S P . N E T es el de los controles compuestos. Los controles compues tos son un conjunto de controles que se han compilado par a for mar una biblioteca. Para us ar controles compuestos hay que incluir una referencia a la biblioteca del mismo modo que se incluyen las referen cias a otras bibliotecas.

Controles ms usados en WebForms


La tarc a b s ica de di sear una apl icacin W e b es a ad ir controles a un We bFo rm. Algunos de los controles ms usados en un W e b Fo r m son Label.

TextBoz. CheckBox. RadioButton. ListBox. DropDownList. HyperLink. Table. Button c ImageButton. Las siguientes secciones
explican brevemente estos controles.

Control Label
El control Label se usa par a most rar texto esttico en un WebFor m. Los usuarios no pueden editar el texto de un control Label. Al aadir un control Label. el texto Label aparece como su ttulo. Sin embargo, asignando un valor a la propiedad Text del control, es posible modificar el ttulo del control. Se puede asi gnar un valor a las propiedades del control Label en tiempo de ejecucin en

474

el archivo de cdigo oculto ( es file). Por ejemplo, si se quiere c amb ia r el texto de una etiqueta cuando un usuario pul sa un botn. Para ello, puede utilizar el si guiente cdigo:
L a b e l l .Text="Welcorne"

En el anterior cdigo. Labell es el ID del control Label cuya identificacin quiere cambiar. Si quiere que el control Label desaparezca cuando un usuario pulse un boton. puede us ar el siguiente cdigo:
Labell.Visible=False

Control TextBox
El control TextBox se usa p ar a obtener informacin, como texto, nmeros y fechas, de los usuarios de un We bFor m. Por defecto, un control Tex tBox es un control de una lnea que permite a los usuarios escribir caracteres en una sola lnea. Sin embargo, tambin se puede establecer el control TextBox como un control multilnea. Un cuadro de texto multilnea mues tra varias lneas y permite el ajuste de texto. Un control TextBox tambin puede usarse par a ac ept ar c o n traseas. Los controles TextBox utilizados para acept ar contraseas ocultan los caracteres escritos por los usuarios, mostrndolos como asteriscos (*). Puede establecer la apariencia de un control TextBox mediante sus p ro pi e dades. como BackColor o ForeColor. Tambi n puede ca mb ia r la propiedad TextMode de un control TextBox para determinar si un control TextBox acta como un cuadro de texto p ar a acept ar una contrasea, una sola lnea de texto o varias lneas de texto.

Controles CheckBox y CheckBoxList


Las casillas de verificacin permiten a los usuarios seleccionar una o ms opciones de un conjunto de opciones dado. Se pueden aadir casillas de verifica cin a un W e b F o r m mediante los controles CheckBox o CheckBoxList. El control CheckBox representa una sola casilla de verificacin, mientras que el control CheckBoxList representa una coleccin de varias casillas de verifica cin. Para agr egar estos controles al formulario, simplemente tiene que a r r a s t r a r los hast a l desde el cuadro de herramientas. Tras agregar el control CheckBoxList. es necesario aadirle una lista de elementos. Para hacerlo, siga estos pasos: 1. En la ventana Propiedades, haga clic en el botn de puntos suspensivos para acceder a la propiedad Items del control CheckBoxList . Se abrira el c ua dro de dilogo Editor de la coleccin Listltem.

NOTA: Si la ventana de Propiedades no est abierta, pulse F4. Tambin puede seleccionar Ver>Ventana Propiedades, en la barra de men.

475

2.

En el cuadro de dilogo Editor de la coleccin Listltem . haga clic en A g r e g a r para crear un nuevo elemento. Se crear un nuevo elemento y sus propiedades se most rarn a la derecha del cuadro de dilogo. Verifique que el elemento est seleccionado en la lista Miembros \ a continuacin es tabl ezca las propiedades del elemento. Cad a elemento es un objeto distinto y tiene las siguientes propiedades:

3.

Selected: representa un valor booleano que indica si el elemento esta seleccionado. Text: representa el texto que se muest ra par a el elemento de la lista. Valu: representa el valor asociado al elemento. El valor de un control
no se muestra al usuario. Sin embargo, el servidor usa el valor para procesar la informacin del control. Por ejemplo, puede establecer la propiedad Text de un element como No mb re de Ci udad v la p r op i e dad Valu del cdigo postal de esa ciudad como identificacin nica. C uando el servidor procesa la informacin representada por el campo Nombre de Ciudad, se puede hacer caso omiso del texto proporci onado por el cuadro de texto y cualquier proceso se b as ara en el c or r es pon diente valor del campo. 4. 5. 6 Especifique el texto que se most rar al usuario. Repita los pasos 2-4 par a ag regar los controles necesarios al control
Ch g c kBo L i. s t .

Haga clic en A c e p t a r par a c errar el cuadro de dialogo Editor de la colec

cin Listltem.

TRUCO: La decisin de usar el control C h e c k B o x o el control C h e c k B o x L i s t depende de las necesidades especficas. El control CheckBox proporciona ms control sobre la presentacin de las casillas
de verificacin de la pgina. Por ejemplo, se puede establecer la fuente y el color de las casillas de verificacin por separado o incluir texto entre las diferentes casillas de verificacin. Por otra parte, el control CheckBoxList es una mejor opcin si se necesitan agregar series de casillas de verifica cin.

Controles RadioButton y RadioButtonList


Los botones de opcion proporci onan un conjunto de opciones para el usuario. Puede agregar botones de opcion a un Wc bFo rm usando el control RadioButton o el control RadioButtonList. El control RadioButton representa a un solo botn de opcion con el que trabajar. El control RadioButtonList es una

476

coleccin de botones de opcion. Los botones de opcion casi nunca se usan indivi dualmente. Ms bien se usan dentro de un grupo. Un g rup o de botones de opcin pr opor ci ona un conjunto de opciones m u t u a mente excluyentes. Esto significa que solo se puede seleccionar un botn de o p cion en un grupo. Un conjunto de botones de opcion puede a g rup ar se de estas dos maneras: Puede agregar un conjunto de controles Rad ioButton a la pagina y asignarlos a un grupo manualmente. Puede usar la propiedad GroupName para hacerlo. Puede agr egar un control RadioButtonLi st a la pagina Los botones de opcin en el control se agr upan aut omt icamente, de modo que 110 es necesario agr uparl os manualmente. Tras aadir un control Rddi.oButtonL.ist al We bFo rm. hay que agregar los botones de opcion. Esto se puede hacer usando la propiedad Items del m i s mo modo que hicimos con el control CheckBoxList.

Control ListBox
El control ListBox representa una coleccion de elementos de lista El c on trol permite a los usuarios seleccionar uno o mas elementos de la lista. Se pueden aadir elementos a la lista individual mediante la propiedad Items Tambi n puede especificar si el us uar io puede seleccionar varios elementos de la lista o si solo puede seleccionar un nico elemento, mediante la propi edad Se iect ion Mode del control ListBox.

Control DropDownList
El control E)ropDownList permite a los usuarios seleccionar un elemento de un conjunto de elementos predefinidos (siendo cada elemento un objeto dife rente con sus propias propiedades). Se pueden agr eg ar elementos a un control DropDownLi st mediante su p r o piedad Ttems. A diferencia del control ListBox. solo se puede seleccionar un elemento cada vez y la lista de elementos per manece oculta hasta que el usuario hace clic en el boton desplegable.

Control HyperLink
El control HyperLi nk permite a los usuarios mov erse de un We b Fo r m a otro dentro de una aplicacin. Tambi n permite a los usuarios despl azarse hasta una URL que puede estar asociada con el control Con el control HyperLink. el texto o una imagen pueden funcionar como un hiperv nculo. C uand o un usuario hace clic en el control, se abre el We b Fo r m de destino o la URL.

477

El siguiente f r ag ment o de cdigo m ue s t r a cmo es tabl ecer la propi edad

Navi gateUrl:
Hyperli n k 1 .NavigateUrl="h t t p : //w w w .ama z o n .c o m " ;

Controles Table, TableRow y TableCell


Las tablas se usan para mos trar informacin en formato tabular. Se puede agr egar una tabla a un W c b Fo r m mediante el control Table. Este control puede mo st ra r estticamente informacin estableciendo las filas y columnas durante su creacin. Sin embargo, se puede p r o g r am ar el control Table para mostrar infor macin di nmi cament e en tiempo de ejecucin. Otros dos controles relacionados con las tablas que se pueden emplear en un Wc bFor m son TableRow y TableCell. El control TableRow se usa para declarar una fila y el control Tabl eCell para declarar una celda en una tabla. Para comprender como se relacionan entre s los controles Table. TableRow y TableCell. agregue un control Table a su We b Fo r m (arrstrelo desde el e xpl orador de soluciones) y realice los siguientes pasos par a agr egar filas v cel das a la tabla: 1 En la ventana de Propiedades, haga clic en el botn de puntos suspensivos para que aparezca la propiedad Rows del control Table. Se abrir el cuadro de dilogo Editor de coleccin TableRow. En el cuadro de dialogo Editor de coleccin TableRow. que representa el control TableRow. haga clic en A gregar par a crear una nueva fila. Se crear una nueva fila y se most rarn sus propiedades a la derecha del cuadro de dilogo. Verifique que la fila ha sido seleccionada en la lista de mi embros y a continuacin haga clic en el botn de puntos suspensivos p a r a que la p r o piedad Cells aada una celda a la fila. El cuadro de dilogo Editor de coleccin TableCell se abrir.

2.

3.

4. En el c ua dro de dilogo Editor de coleccin TableCell. que representa al control TableCell. haga clic en A g regar par a crear una nueva celda.
Se creara una nueva celda y se most rarn sus propiedades en el lado d er e cho del c ua dro de dilogo. 5. 6. Especifique el texto que debe mos trars e en la celda y haga clic en A ceptar par a cerrar el cuadro de dialogo Editor de coleccin TableCell. Ha ga clic en A cep tar par a cerrar el cuadro de dilogo Editor de colec

cin TableRow.
Observe que despus de realizar estos pasos, se ha aadido una tabla 1 x 1 al formulario. La tabla 22.1 describe algunas de las propiedades de los controles

Table. TableRow v TableCell.

478

Tabla 22.1. P ropiedades de los controles Table, T a bl eR ow y TableCell

P ro p ied a d
ID Rows

D isp on ib le co n
Table Table

D escrip cin

Representa el ID nico del control. Representa una coleccin de obje tos TableRow. Un control TableRow representa una fila de la tabla. Representa una coleccin de obje tos TableCell. Un control T a b l e Cell representa una celda de la tabla. Representa el alineamiento vertical, como las partes superior e inferior de la celda. Representa el alineamiento horizon tal, como los alineamientos derecho e izquierdo, de la celda.

Cells

TableRow

VerticalAlign

TableCell

HorizontalAlign

TableCell

Control ImageButton
El control ImageButton permite a los pr og ramador es mo st rar imgenes en un W e b F o r m y gestionarlas durante el diseo o en tiempo de ejecucin. Este control representa un botn grfico, que mejora la apari enci a del We bFor m. Se puede establecer la propiedad ImageUrl p ar a que apunte a una imagen especi fica.

Controles Button y LinkButton


El control Button de un We b Fo r m se usa par a enviar la pagina al servidor. Se pueden agregar tres tipos de botones de control de servidor a un WebFor m.

Button: Representa un botn estndar. LinkButton: Represent a un botn que hace que la pgi na se enve al
servidor. Adems, tambin puede funcionar como hipervnculo a otra p a gina We b o We bFo rm.

ImageButton: Este control se estudi en el anterior apartado.

Cmo crear y configurar una aplicacin Web


Visual C # proporciona la plantilla de aplicacin Web A S P . N E T para crear aplicaciones Web AS P. NET. Esta plantilla contiene la informacin necesaria para

479

crear, procesar y emplear aplicaciones ASP. Antes de crear un proy ecto de apli cacin Web necesitara asegurarse de que se cumplen en la pl at af orma de des arro llo los siguientes requisitos bsicos par a la aplicacin Web: Deber tener acceso a un equipo que ejecute Microsoft 11S Server. Debe instalar 11S S e r \ e r en una particin N TF S. Este tipo de particin mejora la seguridad y rendimiento del servidor. I ras cumplir estos requisitos, puede us ar Visual Studio N E T para crear una aplicacin Web AS P. NET. Para ello, siga los siguientes pasos: 1 2. 3. Agregue un proy ecto de aplicacin W'eb A S P . N E T a su aplicacin. Cree la interfaz de usuario de la aplicacin Web. C odifique la lgica de la aplicacin.

En la siguiente seccin se indican los pasos par a crear un nuevo proyecto.

Cmo crear un nuevo proyecto


Ese la plantilla de aplicacin Web ASP N E T para crear proy ectos de ap li ca ciones Web Los pasos para crear una nueva aplicacin Web usando esta plantilla son los siguientes: 1 Seleccione Archivo Nuevo -Proyecto para abrir el cuadro de dialogo Nuevo Proyecto, como aparece en la figura 22 1 xj
Tipos de p ro y e c to

-J Proyectos de Visual Basic


_ J Pt...vei.tus de VI1..J :# __ I r.jei.U'. de Vi;.ual I + + Aplicacin para W indow s Bibliche'.a de clase;Biblioteca de controles ...

_J

p ,n ve c> ,s I '.nl'j.'i.'ine'-. de Visual ',h]dn

Aplicacin Web ASP.NET

servicio W eb ASP.NET

Biblioteca de contro le s W eb

zJ

P ro y e c to pa ra cre a r una aplicacin con una m te rfa s de usuario de W indow s. N om br e ; U bicacin: [ w indo w .Application i
i : ia p p k a h .c n ;.

T3

El p ro y e c to se cre a r en e :\a p p lica tio n s\W in d o w sA p p lica tio n 3 .

M s

A ceptar

Cancelar

Figura 22.1. Puede seleccionar una o ms plantillas de empresa del cuadro de dilogo Nuevo proyecto.

480

TRUCO: Tambin puede pulsar la combinacin Control-Mays-N para abrir el cuadro de dilogo Nuevo proyecto.
2. 3. 4. Seleccione Proyectos de Visual C# de la lista Tipos de proyecto. Seleccione Aplicacin W eb ASP.NET de la lista Plantillas en el cuadro de dialogo Nuevo proyecto. Escriba el nombre del provecto en el c ua dro Nombre. cin por defecto. El cuadro de dilogo Nuev o proyecto puede v erse c o m pleto en la figura 22.2.
Nuevo proyecto
T ipos d e p ro y e c to : P ro y e c to s d e Visual Basic _ _ j P r o y e c to s d e V is u a l C # _ _ 1 P r o y e c to s d e V is u a l C + + _ _ ] P r o y e c to s d e in s ta la c i n e im p le m e n ta c io n _ _ | O tr o s p r o y e c to s _ _ I S o lu c io n e s d e V is u a l S tu d io Plan tillas:

5. Escriba el nombre de 11S Server en el cuadro Ubicacin o acepte la u bi ca

*1

3
A p lic a c i n p a r a W in d o w s

B ib lio te r a d e c la s e s

53
B ib lio te c a d e c o n tr o le s ...

A p licaci n W e b A 5 P .N E T

s e r v ic io W ^ b A S P .N E T

B ib lio te c a d e c o n tr o le s W e b

P ro y e c to p a r a c r e a r u n a ap lica cin co n u n a in t e r f a z d e u s u a rio W e b .

N o m b re : U b icacin :

| | h t t p : //lo c a lh o s t/W e b A p p lic a tio n 1

El p ro y e c to se c r e a r e n h ttp : //lo c a lh o s t/W e b A p p lic a t io n l.

TM s

A c e p ta r

C a n c e la r

Ayuda

Figura 22.2. Seleccione una plantilla y especifique el nombre de la aplicacin en el cuadro de dilogo Nuevo proyecto.

TRUCO: Si el servidor Web est instalado en su equipo, tambin puede escribir http://localhost in en el cuadro Ubicacin.
6. Haga clic en A c e p t a r . Apa rece r un cuadro de dilogo mientras Visual Studio N E T crea la nueva aplicacin We b A S P. NE T. El cuadro de dilo go se muest ra en la figura 22.3.

NOTA: Quizs tenga que esperar unos instantes a que ASP.NET cree el proyecto. Tambin debe asegurarse, antes de crear la aplicacin, de que el servidor Web est funcionando. Para activar el servidor Web, seleccione lnicio>Ejecutar. En el cuadro de dilogo Ejecutar, escriba net start iisadmin y pulse Intro.

481

xJ

Creando el Web 'http://localhost/WebApplcationr,

il

Cancelar

Figura 22.3. Visual Studio

NET crea el nuevo proyecto.

Tras crear un nuevo proyecto de aplicacin Web, el asistente par a aplicacin We b crea a ut o m t i c a m e n t e al gunos ar chi vos de pro ye ct o necesarios, como Assemblylnf o .es. Web.config y Global.asax. j unt o al archivo pri n cipal de la pgina. WebForml .aspx. La figura 22.4 muest ra estos archivos en el expl orador de soluciones.
*i 3 ^ m 3 S J

S olucin 'U s e rR e g A p p ' (1 p ro y e c te ) U s e rR e g A p p + ^ R rc te n e e s

** 1 A s s e m b ly ln f .c s S G lobal. asa> U s e rR e g A p p . vsd isco 4 W e b .c o n fig

Figura 22.4. La ventana de proyecto muestra todos los archivos creados por el asistente de la aplicacin Web.

Un We b F o r m de Visual Studio N E T tiene dos vistas: D iseo y H TM L. Vista Diseo. La interfaz de usuario de un We b F o r m se disea en vista Diseo. Esta vista ofrece dos diseos p ar a el We bFor m: diseo de c u a dr cul a y diseo de flujo: Diseo de cuadrcula. En el diseo de cuadrcula, se pueden colocar los controles en el W e b F o r m segn las coordenadas de cada control. Diseo de flujo. En el diseo de flujo, se puede disear de forma linear un WebForm. del mismo modo que se disea un documento de Microsoft Word, de arriba abajo. Puede alternar entre los diferentes diseos haciendo clic con el botn dere cho en el W e b F o r m y sel ecci onando Propiedades. En la pgina Propie dades puede seleccionar el diseo que considere apropiado. Vista H T M L . Esta vista representa la correspondiente sintaxis A S P . N E T del WebFor m. Para abrir la vista H T ML , slo tiene que hacer clic en la

482

ficha H TM L. Si la ficha H T M L no est visible, puede hacer clic con el botn derecho del ratn v seleccionar Ver fuente HTML en el men a b r e viado.

Cmo agregar controles al WebForm


Se pueden ag regar controles a un W e b F o r m de dos maneras: M ediante el cuadro de herramientas. Puede agregar controles en la vista Diseo del W e b Fo r m (el archivo aspx) usando el cuadro de herramientas incluido en Visual Studio N E T Dentro del cuadro de herramientas hay varios tipos de cont rol es c las ifi cados dent ro diferentes fichas, como We bFor ms . H T M L y Datos. Por ejemplo, puede usar la ficha H T M L para crear controles de servidor H T M L y la ficha We bFor ms para crear los controles de servidor A S P . NE T. Todos los controles estudiados hasta a ho ra pertenecen a la ficha Windows Forms del cuadro de herramientas. Cuando se usa el cuadro de herramientas p ar a agr egar controles Web en vista Diseo, se genera aut omt icame nte la sintaxis C U correspondiente.

TRUCO: Al usar controles HTML debe convertirlos a controles de servi dor con el fin de que estn disponibles para ser codificados en el servidor. Para ello, haga clic con el botn derecho en el control HTML requerido y seleccione la opcin Ejecutar como control del servidor en el men abreviado. Este mtodo permite crear complicados WebForms cmoda y rpidamente.
Usar sintaxis de Visual C# para agregar los controles mediante p ro gram acin. Tamb in puede agr egar controles Web a un W e b Fo r m m e diante la sintaxis de Visual CU. Slo se puede usar la sintaxis de CU en la vista H T M L de la pgina (archivo aspx). La sintaxis real depende del tipo de control que quiera aadir. Por ejemplo, la sintaxis que se usa para agr egar un control de cuadro de texto H T M L es la siguiente.
<mput id = Textl Type = text runat = "s e rve r " >

NOTA: Visual Studio .NET permite agregar controles de servidor ASP.NET mediante una etiqueta de lenguaje extensible para el anlisis de documentos (XML). La sintaxis usada para agregar un cuadro de texto ASP.NET es:
<asp:TextBox id=TextBoxl runat^"seryer"></asp:TextBox>

Cad a control tiene una propiedad ID que se usa par a identificar unvocamente al control.

483

Para establecer la propi edad de un control en tiempo de ejecucin se usa la siguiente sintaxis:
Control ID.Property=Value

En la anterior sintaxis:

Control

ID representa la propiedad ID del control.

Property representa la propiedad del control. Valu representa el valor asignado a la propi edad del control.
La figura 22.5 muestra un W ebFo rm que contiene los habituales controles Web como etiquetas, cuadros de texto, hipervnculos. botones de opcin, casillas de verificacin y botones. Como puede ver. el W eb Fo r m es un formulario de registro de usuario. El formulario est diseado para aceptar entradas de usuario desde varios controles. Tras rellenar el formulario, el usuario puede hacer clic en el boton Submit (Enviar) para completar el registro. El botn Submit abre otro WebFor m que muestra un mensaje junto al nombre que el usuario introdujo en el control TextBox. Si el usuario hace clic en el botn Reset (Restablecer), la informacin que ha introducido el usuario se elimina de los controles de ese formulario. 3 W e b F o r m ! - M icro so ft In te r n e t E xp lo re r
Archivo Edicin Ver Favoritos Herramientas ( Ayuda Favoritos Multimedia :

j
Direccin

. j-

Bsqueda

f p *

A p p /W e b F o r r n l.a sp |- ]h r r p//loi a lh iW /i_ k e r P e g R eg istra b o nF otm am e E -M ail S tate S u scrip to f * f T ................ 3 r r

J fli,

Vnculos > >

Submit |

Reset |

| Listo

^ Intranet local

Figura 22.5. El formulario de registro de usuario muestra los controles com unes que se pueden agregar a un W ebF orm .

Para crear el formulario most rado en la figura 22.5. realice los siguientes pasos:

484

1. 2.

Seleccione el formulario W e bF or m 1 as px y pulse F4 par a que ap arez ca la ventana Propiedades. En la ventana Propiedades, pulse el botn de puntos suspensivos par a que a pa rez ca la p ropiedad bgColor y seleccione Propiedades. Se a br i r el cuadro de dilogo Selector de colores. En el c ua dro de dilogo Selector de colores, seleccione un matiz rosa y haga clic en A ceptar. El color del W e b F o r m c ambi ar al color que ha especificado. Agregue controles al formulario y cambie sus propiedades, como recoge la tabla 22.2.
Tabla 22.2. Controles que se pueden agregar a un W e bF orm

3.

4.

C ontrol
Label

P rop ied ad
T ext=Registration Form

P osicin

Para situarlo en la par te superior, inferior o en el centro del formulario

Font Bold=True Size=Larger Etiquetas para Nombre, Correo electrnico, Esta do y Suscripcin
TextBox TextBox DropDownLi s t

El texto de cada etiqueta debe ser la misma que el ttulo de seado.


ID=txtName ID=txtEmai1 ID=lstState Items=Ari z o n a , California, Florida ID=lstOptions Items=Books, Magazines ID=BtnSubmi t Text=Reset

Una bajo otra en el lado izquierdo de la pantalla

Junto a la etiqueta ame Junto a la etiqueta EMail Junto a la etiqueta State Junto a la etiqueta Suscription Bajo la etiqueta Suscription

Che c kBoxLi s t

Bu11 on

Button

ID=BtnReset Text=Reset

Junto al botn S u b m i t

485

La interfaz de su We bFo rm. como aparece en la figura 22.6. est lista. Agre gar la funcionalidad de los botones S u b m i t y R e s et en la siguiente sec cin. Sin embargo, antes de continuar, agregue a la aplicacin We b otro f or mul a rio que muestre los detalles sobre el usuario registrado cuando ste haga clic en el botn S u b m i t . Para agregar el We bFor m. siga estos pasos:

1. Seleccione Proyecto>Agregar W ebForm. Se abrir el cuadro de dialo go Agregar nuevo elemento.

TRUCO: Si no encuentra la opcin de men Agregar WebForm bajo el men Proyecto, haga clic en cualquier parte de la ventana Formulario y a continuacin seleccione la opcin de men.
UserRegApp - Microsoft Visual C # .NET [disear] - WefaFotmiJSpN* ______ ___
Archivo Adicin )er Proyecto enerar Qepurar Datos Formato Tabla Insertar Marcos

.
J --[-j'

:
Ventana Ayuda

usr*|
^ 2*

Herramientas

. Jl

HiJ ^

' *

i-

r.pbug

WebForm I .aspx*

: feegistration F o rm :

i-M a

State:: : : : : : : : : 'An' nna j j ... : : . : : '~ [BooksJ


uscnpon

3:

r [Magaanes]:

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

sj.......u................. >
Submit | ...............

Reset |

Figura 22.6. E l W e b F o r m d e b e r a t e n e r e s t e a s p e c t o u n a v e z c o m p l e t a .

2.

Seleccione W e b F o r m en la lista de Plantillas, especifique un n ombre para el W e b F o r m (o mant enga el nombre por defecto) y haga clic en A b r i r para crear un nuevo We bFo rm.

Pude u sar el recin agr egado We b Fo r m p ar a mo st rar un mensaje al usuario. Por lo tanto, necesitar agregar un control Label al formulario. Llame a la etiqueta IblMessage. T ra s ag regar controles al formulario, debe responder a los eventos generados por los controles del formulario par a t raba jar con la interaccin del usuario. Por

486

ejemplo, si un usuario hace clic en el boton S u b m i t . el formulario necesitar ser procesado y los datos de la base de datos tendrn que actualizarse. La siguiente seccin describe el procedi miento p ar a cont rol ar los eventos ge nerados por los controles de un We bFor m.

Cmo controlar eventos


C uando los usuarios mt eract an con los diferentes controles Web de una p g i na. se desencadenan eventos. Un evento es una accin que puede tener lugar sobre un objeto o sobre un control, que pueden ser generados por una accin de un usuario o por el sistema. Por ejemplo, cuando pul sa un botn del ratn o una tecla, se genera un evento. En los formularios de cliente tradicionales o en las aplicaciones We b basadas en clientes, los eventos se desencadenan y gestionan por parte del cliente. En las apl icaciones Web. los eventos se d esencadenan en el cliente o en el servidor. Sin embargo, los eventos generados siempre son controlados en el servidor. Los c on troles de servidor A S P . N E T slo admiten eventos de servidor, mientras que los controles de servidor admiten eventos de servidor y de cliente.

Viajes de ida y vuelta


Los W e b F or ms son procesados en el servidor. Por ejemplo, imagine un f o r mu lario de registro de usuario. Cuando un nuevo usuar io especifica un valor p ar a el nombre de registro, el servidor debe a se gu rars e de que el nombre de registro p ropor ci onado por el usuar io es nico. Puede as egurars e de que el nombre de registro es nico i nterceptando el evento Click de un botn y c om pa r and o el nombre de usuario con una fuente de datos. Cada vez que una interaccin de usuario requiere ser p roc es ada por el servi dor. el W e b F o r m es enviado al servidor y procesado, entonces el resultado es devuelto al cliente por medio de un navegador. Esta s ecuencia de procesami ent o de informacin en el serv idor recibe el nombre de proceso de ida y vu e lta . como muest ra la figura 22.7. Casi todas las interacciones con los controles del servidor dan como resultado v iajes de ida y vuelta. C omo un viaje de ida y v uelta implica env ar el W e b Fo r m al servidor y luego mos trar el formulario procesado en el nav cgador. el control del servidor afecta al tiempo de respuesta en el We bFor m. Por tanto, el nmero de eventos disponibles en los controles de serv idor de un W e b F o r m deben ser los menos posibles. Por lo general, esto se reduce a los eventos Click.

NOTA: Los eventos que tienen lugar con bastante frecuencia en lenguajes de secuencia de comandos, como OnMouseOver, no son compatibles con los controles de servidor. Sin embargo, algunos controles de servidor admi ten eventos que tienen lugar cuando cambia el valor del control.

487

Navegador (a s p x )

Servidor (es)

Encontrar | Elem ento l ---------------- | Enviar |

Cdigo de la aplicacin

Encontrar

Elemento

Encontrados 2 elementos

F orm u la rio pro cesa do (para el naveg ad or)

Figura 22.7. El proceso de ida y vuelta

La tabla 22.3 dcscribc los eventos ms comunes asociados a diferentes c on troles de servidor A S P . N E T
Tabla 22.3. Eventos asociados a controles de servidor A S P .N E T

Control(es)
T ez tBoz Radi oButton y CheckBoz RadioButtonList, CheckBoxList, ListBoz y DropDownLi s t Button, LinkButton y I m a g e B ut t on

Evento
TeztChanged

Descripcin
Tiene lugar cuando el foco sale del control. Tiene lugar cuando se hace clic en el control. Tiene lugar cuando se cambia la seleccin de la lista. Tiene lugar cuando se hace clic en el botn. Este evento hace que el formulario sea enviado al servidor.

CheckedChanged

SelectedlndexChanged

Click

Por defecto, en un W e b Fo r m. slo el evento Click de los controles de servi dor Button. LinkButton y ImageButton pueden hacer que se enve el formulario al servidor para ser procesado. En ese caso, el We b Fo r m es devuelto al servidor. C uand o otros controles generan los eventos de cambio, son at rapados v ocultados. No hacen que el formul ar io se enve inmediatamente. Solamente cuando el formul ar io es devuelto mediante un clic en un botn, todos los eventos ocultos se desencadenan y son procesados. No hay una secuencia parti cular para pr oc es ar estos eventos de cambi o en el servidor. Sin embargo, el evento Click

488

se p roces a solamente despus de que todos los otros eventos de cambio hayan sido procesados.

Controladores de eventos
C uan do se desencadena un evento, este necesita ser controlado par a ser p ro cesado posteriormente. Los procedimientos que se ejecutan cuando ocurre un evento reciben el nombre de controladores de eventos. Los controladores de eventos pueden ser creados a ut omt i ca o manualmente. C uando los eventos se controlan automticamente, al hacer doble clic sobre un control en la vista Diseo del W e b Fo r m ( a s p x file) se crea un controlador de eventos. Por ejemplo, cuando se hace doble clic sobre el botn. btnSubmi t. se genera el siguiente codigo. A continuacin puede escribir el cdigo en el cont rol a dor de eventos de la funcin generada por Visual Studio NET:
Public void btnSubmit Clck (Object sender, System.KventArqs e)

( } En el anterior cdigo, el procedi miento btnSubmit Click es el con tro la dor de ev entos del ev ento Click del botn. El procedimiento toma dos a r g u m e n tos. El pri mero contiene el emi sor de eventos. Un emi sor de eventos es un objeto, como un formul ari o o 1111 control, que puede generar eventos. El segundo a r g u mento contiene informacin adicional as oc ia da al evento, como las coordenadas de posicin x e v . en las que se ha pulsado el botn del ratn. Para cr ear manual ment e un cont rol ador de eventos, seleccinelo de la lista emergente de la vent ana Propiedades. Ya est pre para do p ar a implcmentar el control de eventos p ar a el We bFo rm que aparece en la figura 22.7. Al hacer clic en el botn S u b m i t . aparece una nueva pgina (en este caso W e bF o r m 2 . a s p x ) . que mues tra un mensaje de bienvenida junto al nombre del usuario registrado. Para i mplcmentar esta funcionalidad debe escribir el siguiente cdigo en el evento Click del botn S u b m i t del We b Fo r m We b Fo r m I aspx:
prvate void BtnSubmit Click (object sender, System.EventArqs t z t N a m e .T e z t ) ; e)

{
R e s p o n s e .Redirect (" W e b Fo rm 2.aspx ?s t rNam e= "+

TRUCO: Para codificar el evento del botn Submit, haga doble clic en la vista Diseo.
En el anterior cdigo, el mtodo R ed ire ct de la clase H t t p Re s po ns e redirige al usuario a la pgina We b Fo r m2 aspx y pasa el valor del parmet ro t xtName a la pgina de destino.

489

Tras p a sa r el valor del cuadro de texto t x t N a m e . debe inicializar We b Fo r m2 par a controlar la cadena p as ada desde el formulario de registro. Para hacerlo. W e b F o r m 2 . a s p \ debe t ener el siguiente cdigo en el evento L o a d :
prvate void Page Load (obj ect sender, System.EventArgs e)

(
l b l M es sa ge .T e z t = " H i ! " + Request.QueryStnng.Get("strName");

TRUCO: Para codificar el evento Load del formulario WebForm2.aspx, haga doble clic en el formulario en vista Diseo.
En el an t er i or codigo. el ttulo de la et iq uet a l b lM es s ag e en el a rchi vo W e b F o r m 2 . a s p x es el valor que se asigna al valor al macenado en la variable strN am e. Cuando el usuario hace clic en el botn S u b m i t de WebForm 1 aspx. es redirigido a la pagina We b Fo r m2 aspx. como muestra la figura 22.8.

Archivo

Edicin

Ver

Favoritos 2]

Herramientas i

Ayuda Favoritos Multimedia

I1 Jp*

Direccin | e j l-.l-tf'

* ] i ' / l " # . ! . I

Bsqueda

j ~
~

l-.-rl-'.-gA[.(.'.1

n r n 1a-[i 1 irFl.irii-aL.lir,

Ir

Vnculos

> y

Hi! John

a ]

Listo

*J

Intranet local

Figura 22.8. C uando un usuario es redirigido a otra pgina, el nombre del usuario se pasa en la cadena de consulta.

Cuand o el usuario hace clic en el botn Reset. debe generar se un evento que elimine todos los controles rellenados por el usuario en W e b Fo r m 1 aspx. Para implementar esta funcionalidad, codifique el evento C l i c k del botn Reset como se indica a continuacin:

490

prvate

voicl

Bt n R e s e t

Click(object

sender,

System. E v e n t A r g s

e)

{
t x t a m e .Text = "" ; t x t Erna 1 1 .T e x t = " " ;

IsLSLate.ClearSelectionO ; 1s t O p t o n s . C l e a r S e l e c t i o n ( );

} En el cdigo anterior, cuando se hace clic en el botn Reset del formul ari o de registro, el formulario se reinicia y vuelve a su estado original.

Cmo controlar la devolucin de datos


Como se menciono antes, slo se devuelve un W e b F o r m al servidor cuando se hace clic en un control Button. LinkButton o ImageButton control. Una vez que se ha enviado el formulario al servidor, es procesado all. Puede controlar la devolucin de datos correspondiente al clic de un botn de una de estas formas: Escribiendo un cont rol ador de exentos par a el exento Cl ick del botn. Escribiendo el cont rol ador de eventos par a el evento Load del We bFo rm. El evento Load se genera cuando se abre el formulario. Puede usar la propi edad IsPostBack del evento Load para determinar si la pagina ha sido procesada por primera v ez o si ha sido procesada por un clic de boton. El siguiente cdigo muestra el controlador de eventos para un ev ento Load de un We bFor m:
protected void Page Load(ob]ect sender, EventArgs e)

{
if ( !IsPostBack)

{
/ /E v a l a true la p r i m e r a vez que el navegador llega a

la pagina

Cmo usar el estado de vista


En las aplicaciones Web tradicionales, cada vez que se procesa una pagina Web en el servidor, la pgina se crea desde cero. El serv idor elimina la i nforma cin de la pagi na actual despus de p ro ces arl a y enva la pgi na al cliente (navegador). Como la informacin de la pagi na no esta g ua r da da en el serv idor, las paginas Web se llaman sin estado. Sin embargo, el marco de trabajo A S P . N E T resuelve esta limitacin y puede g u ar d a r la i nformacin de estado del formulario y sus controles. Para gestionar la informacin de estado. Visual Studio NE T proporci ona las siguientes opciones: G uardar el estado de vista. Puede g u ar d a r el estado de vista de los con troles de un objeto. En cada viaje de ida y vuelta, el estado del control del serv idor puede cargar se desde el estado gu ar d ad o de modo que el usuario

491

pueda ver todas las opciones que el usuario haya seleccionado con ant eri o ridad. S t a t e Ba g. La clase StateBag es el mecani smo de al macenami ent o de los controles de servidor. Esta clase propor ci ona propiedades par a al macenar informacin en pares clave-valor. Por ejemplo, si quiere al mac en ar datos especificados por el usuario par a una pgina, puede usar una instancia de la clase StateBag par a al macenar estos datos. Ca da control de servidor incluye una propi edad EnableViewState. C u a n do establece el valor de esta propiedad como true, el estado del control se conserva en el servidor entre los viajes de ida y vuelta. As, si el usuar io ha seleccionado una o ms opciones de una lista, las opciones se g ua r da n en el servidor entre los v iajes de ida y v uelta.

Resum en
En este captulo, ha aprendido a cr ear una sencilla aplicacin We b mediante Visual C# en el entorno AS P. NET. Se han estudiado los fundamentos de A S P . NE T y cmo se crean aplicaciones We b en Visual C#. A S P . N E T incluye un entorno de tiempo de ejecucin s eparado que gestiona la ejecucin de las aplicaciones A S P .N ET . Tambi n incluye nuevos componentes de servidor, llamados We b Fo r ms . que encaps ul an la funcionalidad de una pgina Web. Puede a gr egar uno o ms controles de servidor a un We bFo rm. Los c ont ro les de serv idor son los responsables de mos trar los datos a los usuarios y procesar sus interacciones. Hemos creado un proyecto de aplicacin Web y le hemos agregado un WebForm. Al crear la aplicacin, usamos la plantilla A S P . N E T p ar a aplicaciones We b par a crear una solucin y agr egar un proyecto A S P . N E T a la solucin. A co nt i nu a cin. diseamos una pgina We b u sando controles Web corrientes, como los c on troles que representan etiquetas, cuadros de texto, cuadros de listas, hipervnculos. botones y similares. Por ltimo, apr endi mos a cont rol ar los eventos que generan los controles en el We bFo rm.

492

Programacin de bases de datos conADO.NET


A D O . N E T es la tecnologa mas moderna para el acceso de datos y forma parte de N E T Framework. A D O . N E T util iza y mejora las anteriores tecnologas de acceso a datos. La incursin de Microsoft en el acceso a datos universal comenz con la conectividad abierta de bases de datos ( ODBC). La idea sobre la que se asienta esta tecnologa O D BC (crear un modo est ndar de acceso a las bases de datos mediante progr amaci n) ha sido u sada en todas las tecnologas de acceso a datos posteriores procedentes de Redmond. Washingt on (donde est la sede de Microsoft). En el caso de O D BC , este metodo est ndar esta ejemplificado en el API (Interfaz de pro gr amaci n de aplicaciones) de ODBC. Cual qui er proveedor de bases de datos que quiera gar ant i zar el cumplimiento del est ndar O D BC debe elabor ar el software que convierta una llamada O D B C (hecha de acuerdo con el API) en una llamada de una base de datos nativa. Este software recibe el nombre de controlador O D B C y es el puente entre una aplicacin de cliente genrica y una base de datos especfica. Mediante este enfoque, los pr ogr amado re s de apl i caciones evitan tener que apr ender a usar el API de base de datos especfico del proveedor. Todo lo que un p ro g ra ma do r necesita saber es cmo escribir ap l ic a ciones cliente usando el API de ODB C. Este hecho mejora la productividad y permite escribir p ro gr amas que pueden ser usados con diferentes bases de datos. Sin embargo, el API de O D BC fue diseado en un principio, sobre todo, con los pro gr amado re s de C en mente y era difcil de usar en otros lenguajes (como

495

Visual Basic). Esto condujo finalmente a la creacin de Objetos de datos de ActiveX (ADO). una tecnologa de acceso a datos diseada par a ser u sad a con cualquier lenguaje compatible con el modelo de objetos componentes ( C O M ) de Microsoft. ADO presenta un simple modelo de objetos que convierte el acceso a datos en los pro gr amas MS Wi ndows sea una tarea sencilla. Ademas. ADO introduce el c on cepto de conjuntos de datos sin conexin como un modo de t ran spo rt ar datos entre los niveles de una aplicacin distribuida. El API de bajo nivel detrs de ADO se llama OLE DB Este API fue diseado por programadores de C++ y es lo que los distribuidores de bases de datos suelen us ar p ar a escribir proveedores de OLE DB (el termino ms usado p ar a referirse a los controladores OLE DB. el software que convierte las llamadas ADO en llamadas a bases de datos nativas). Microsoft tambin ha escrito un proveedor de OL E par a OB DC . Este prov eedor permite hacer llamadas ADO a cualquier base de datos que cumpla con el estndar ODB C Como ver en este captulo. A D O . N E T mantiene un modelo de objetos similar al de ADO y mejora el concepto de conjuntos de registros sin conexin pr opo rci o nando un modo de reunir ms informacin en un objeto A D O . N E T llamado co n junto de datos. De hecho. A D O . N E T fue diseado pensando en los datos sin conexin porque su falta de estado funciona mejor en las aplicaciones de Internet distribuidas. En este captulo aprendera a usar A D O . N E T par a mani pul ar datos Si ya conoce ADO. muchos de los conceptos le sern familiares e incluso el cdigo le puede resultar conocido.

Clases Dataset y otras clases relacionadas


Esta seccin estudia las clases de A D O . N E T . Si ya conoce ADO reconocer muchos de los conceptos que aqu le presentamos. Sin embargo, tenga en cuenta que algunos conceptos de A DO han mejorado mucho en A D O . N E T y han a u m e n tado considerablemente sus formas originales. Empecemos con un nuevo c o nc ep to: la clase DataSet y sus clases relacionadas. DataSet desarrolla el concepto de conjunto de registros de ADO. Los conjuntos de registros de ADO son una abst racci n de un grupo de registros, como los datos resultantes recuperados al enviar una instruccin Select SQL. Un conjunto de registros puede contener ms de un conjunto de registros, pero los registros son independientes entre si y deben ser procesados secuencialmente i nv o ca nd o NextRecordSet ().DataSet de A D O . N E T es una abstraccin de toda una base de datos. Un DataSet no solo permite contener mas de un conjunto de registros (llamado ap rop ia dament e DataTable). sino que ademas puede definir relaciones entre DataTables. La tabla 23.1 describe todas las clases relacionadas con el DataSet. Como las clases ADO. las clases A D O . N E T usan muy a menudo las colecciones: la clase DataSet contiene una coleccin de DataTables: la clase DataTable c o n tiene una coleccin de DataColumns v as sucesivamente.

496

Tabla 23.1. D a t a S e t y c l a s e s r e l a c i o n a d a s

DataSet

Una cach en memoria de datos, que pueden consistir ] en varias DataTabies relacionadas entre s. Est di seada para su uso sin conexin en las aplicacio nes distribuidas. Un contenedor de datos, que puede componerse de varias D a t aC ol um n s . Cada fila de datos se contiene en una DataRow. Una fila de datos concreta en una DataTable La definicin de una columna (nombre, datos, tipo, etc.) en una DataTable Una relacin entre dos DataTabies de una DataSet, normalmente usada para representar relaciones de clases externas Una restriccin a una o ms DataColumns, usada para representar limitaciones como la exclusividad Asigna los nombres de columna desde la tabla de una base de datos hasta los nombres de columna de
D a t a T a b l e en el D a t a S e t

DataTable

DataRow DataColumn DataRelation

Constraint DataColumnMapping

DataTableMapping DataView

Asigna los nombres de tabla en una base de datos hasta los nombres de DataTables en DataSet Una vista personalizada de una DataTable que pue de usarse en la clasificacin, filtrado y bsqueda.

El Record Set de A DO evoluciono gr a du al me nt e como el modo es t n da r de p re par ar los datos entre los distintos niveles de una aplicacin distribuida. El DataSet asume este papel en A D O . N E T v proporciona varios mtodos para compat ibi lizar la cach en memoria con su fuente de datos en una base de datos. E sto s m t o d o s i n c l u y e n A c c e p t C h a n q e s ( ). G e t C h a n q e s ( ). HasChanges ( ) . HasErrors ( ) v Re j ectChanqes ( ) . Ademas, permiten recuper ar cualquier cambi o en forma de un DataSet modificado, ex ami nar las modificaciones en busca de errores y decidir si acept ar o rechazar los cambios. Al final de este proceso puede actual izar los datos fuente en la base de datos con una simple l lamada al mtodo IJpdate ().

Compatibilidad con OLE DB SQL Server


A D O . N E T contiene dos conjuntos de clases similares. Una es un conjunto de clases genrico que puede usarse para acceder a todas las bases de datos de los

497

proveedores de OL E DB. Un segundo conjunto de clases ha sido opt imi zado para la base de datos insignia de Microsoft. SQL Server. Todos los nombres de las clases genricas comienzan p o r O l e D b . Todos nombres de las clases especificas de SQL Server empiezan con Sql. Cad a clase genrica tiene su clase especifica SQL Server correspondiente. Por ejemplo, la clase que se usa par a ejecutar las i nstrucciones SQL en SQL Server recibe el nombre de SqlCommand. La clase genrica recibe el n ombre de 01 eDbCommand. Este capitulo emplea las clases genricas, incluso par a acceder a la base de datos SQL Server. Cuando escriba sus propias aplicaciones que accedan a SQL Server, deber decidir si quiere emplear las clases especficas SQL Server, mas lapidas, o las clases genricas, que permiten i ntercambiar distribuidores c a m biando la cadena de conexin. La eleccin se basa en velocidad o portabilidad. Las clases SQL Server llaman directamente al nivel nativo de la base de datos. Las clases genricas usan OloDb y at raviesan un nivel C O M antes de llamar al nivel nativo de la base de datos. El coste de este nivel adicional supone un descen so en el rendimiento. Las clases DataSet se usan en conjuncin con el proveedor de OL E DB y el proveedor de SQL Server. La tabla 23.2 enumera las clases especficas de cada prov eedor. Mucha s de ellas le resultaran conocidas a alguien que va ha t rabajado con ADO
Tabla 23.2. DataSet y clases relacionadas

Clases de proveedores de SQL


S qlC o m m a n d

Descripcin

de OLE DB
O le D b C o m m a n d Un contenedor de clase para una instruccin SQL. La clase puede administrar instrucciones directas S Q L c o m o las i n s t r u c c i o n e s SELECT, UPDATE, D E L E T E 0 i n s e r t y una llamada al p ro ce d i miento almacenado. Usada para generar las in stru ccio nes SQL s e l e c t ,UPDATE. DELETE 0 INSERT. Una conexin a una base de datos '

S q lC o m m a n d B u ild e r

O le D b C o m m a n d B u ild e r

S q lD ataC onnection S q lD ataA dapter

O leD bConnection O le D b D a taA d a pte r

Un c o n j u n t o de i n s t r u c c i o n e s SELECT, UPDATE, DELETE. 0 i i n s e r t y una conexin a una base de datos que puede usarse para completar un DataSet y a c tu a li zar la base de datos subyacente. Un conjunto de registros de datos slo hacia adelante.

S qlD ataR eader

OleD b D a taR e a de r

498

Clases de proveedores de SQL


SqIError

Descripcin

de OLE DB
O le D bE rro r Un aviso o error devuelto por la base de datos, perteneciente a una coleccin Errors El tipo de excepcin iniciado cu a n do ocurren errores en la base de datos Un parmetro para un procedim ien to almacenado Una transaccin de base de datos

SqIException

OleDbException

S qlP aram eter

O le D b P a ram e te r

SqlT ransaction

OleD bT ransaction

En la siguiente seccin estudiaremos el modo en el que estas clases t rabaj an con las clases comunes. DataSet y sus clases relacionadas, par a realizar o pe r a ciones con las bases de datos comunes.

Operaciones de bases de datos comunes mediante ADO.NET


Cada uno de los ejemplos de esta seccin omite las declaraciones using en beneficio de la sencillez. Se supone que las siguientes tres declaraciones de e s p a cio de nombres estn presentes en este captulo: using using using System; System.Data; S y s t e m .D a t a .OleDb;

Adems, muchas funciones se han sacado del contexto de su clase. Se s u p o ne que las funciones estn incluidas en el mbi to definido por la siguiente defini cin de clase.
namespace ADOdotNET

(
class ADOdotNET Coloque aqu la funcin

(
// NOTA:

} } Una vez hechos estos comentarios previos, podemos adentrarnos en ADO.NET. Una a una. esta seccin examina cada categora de operaciones que puede reali zarse con ADO NET:

499

Operaci ones que no devuelven filas. Operaci ones que slo devuelven una fila. Operaciones que slo afectan a una fila. Operaci ones que devuelven varias filas. Op eraciones que afectan a varias filas. Operaci ones que devuelven datos jerrquicos.

Operaciones que no devuelven filas


Muchas operaciones de SQL (por ejemplo, las instrucciones Insert. Delete y Update) devuelve slo xito o fr aca so (o los nmeros de filas afectados por la operacin).

NOTA: El programador de SQL Server controla si el nmero de filas afec tadas se devuelve desde un procedimiento almacenado mediante la instruc cin SET NOCOUNT [ON | O F F ] . Los programadores en SQL Server suelen desactivar esta caracterstica mediante SET NOCOUNT ON porque mejora ligeramente el rendimiento.
El listado 23.3 mues tra lo sencillo que resulta ejecutar una instruccin SQL que no devuelve filas en A D O . N E T . En este proceso se emplean dos objetos. En primer lugar se usa un objeto OleDbConnection p ar a establecer una c o nexin con una base de datos. El listado 2 3 . 1 mues tra un ejemplo de cadena de conexin u sada para acceder a la base de datos Nort hwi nd de una instruccin de SQL Server i nstalada localmente.
Listado 23.1. Ejemplo de cadena de conexin para SQL Server prvate static stnng o 1 eDbConnec 1 1 onString

{
ge t

{
// NOTA: Usar la cuenta sa para producir // aplicaciones es, por supuesto, una practica // muy mala. Ademas, dejar en blanco la // contrasea para la cuenta sa es igualmente // inadmisible. return "Provider = SQLOLEDB. 1; " +"User ID = sa ;I m t i a l Catalog = N o r t h w m d ; Data S o u r c e = 1 o c a 1h o s t ; " ;

} ) El listado 23.2 mu es tra un ejemplo de cadena de conexin p ar a Access 2000.

500

Listado 23.2. Ejemplo de cadena de conexin para Microsoft Access private static string oleDbConnectionStnng

{
get

{
// NOTA: Se presupone que se nstalo // Microsoft Office Pro en el directorio por defecto return "Provider=M ier os of t.Jet.OLEDB.4.0;" f'Data Source = C :W P r o g r a m Fi 1 e s \\Micros oft Of f ice\\Of f ice\\Samples \ \Nor t h w m d .M D B " ;

El segundo objeto que se usa p ar a ejecutar una consulta es OleDbCommand. Su constructor recibe un argumento de cadena (el texto de la instruccin SQL que se q u i e r e e j e c u t a r ) v un o b j e t o O 1 e D b C o n n e c t i o n . La p r o p i e d a d CommandType permite es pecificar si el c omando que se ejecuta es un proc edi miento al macenado, una consulta Access o texto simple. La consulta se realiza medi ant e el mt odo ExecuteNonQuery ( ) . Los errores, como una infraccin de clave primaria, se notifican mediante excepciones. T am bi n se pueden u sar objetos Command p ar a ejecutar comandos SQL que no devuelven filas de datos, como en el ejemplo del listado 23.3:
Listado 23.3. Plantilla para usar un c om ando y ejecutar una instruccin SQL que no devuelve filas // Declare y asigne los valores apropiados para o l e D b C o n n e c t i o n S t r m g y strSQLStatement // Crea objetos OleDb OleDbConnection databaseConnection = new OleDbConnection ( o le Db Co nn ec ti on St rm g) ; OleDbCommand databaseCommand = new OleDbCommand(st rS QL St at em en t, da ta ba se Co nn ec ti o n) ; // NOTA: Solo se debe usar una de las dos instrucciones que se muestran a continuacin, NO AMBAS. // Si estamos tratando C 0 2 7 una instruccin SQL (es decir, NO con un procedimiento almacenado) , use: datab as eC om ma nd .CommandType = Co mm a n d T y p e .Text ; // Si estamos tratando con procedimiento almacenado, use: datab as eC om ma nd .CommandType = Co m m a n d T y p e .StoredProcedure ; t ry

{
// Establece la conexion de base de datos d a t a b a s e C o n n e c t i o n .Open () ; // Ejecuta el comando de SQL int numRows = d at ab as eC om ma nd .Ex ec u t e N o n Q u e r y (); // Haz otra cosa, p. e j . informar sobre numRows

}
catch (Exception e)

501

//Controla la excepcin, p. ej . : C o n s o l e . W n t e L m e (" + ***** Caught an e .Messa ge );

exception: \n{0) ",

) finally {
databaseConnection.Clo.se () ;

} La invocacin de procedimientos al macenados con par met ros es un poco mas complicada. El listado 23.4 muest ra el cdigo SQL par a un procedimiento a lmacenado al que se quiere llamar.
Listado 23.4. Un procedimiento alm acenado de SQL Server para insertar un registro USE [Northwmd] GO CREATE PROCEDURE [pc m s C u s t o m e r s ] (0CustomerID_1 [nchar] (5), @CompanyName 2 [nvarchar] (40) , 0ContactName 3 [nvarchar] (30) , 0Contact Tit 1e_4 [nvarchar] (30), @Address 5 [nvarchar] (c0) , @City c [nvarchar] (15), @Region 7 [nvarchar](15), @P o s t a 1C o d e 8 [nvarchar] (10) , pCountry G [nvarchar] (15), 0 P h o n e 11 J [nvarchar] (24) , 0 F a x 11 [nvarchar] (24) ) AS INSERT INTO) [Northwmd] . [dbo] . [Customers) ( [Cus t ome r I D ] , [C o m p a n y N a m e ] , [C c >n t a c t .N a me ] , [C on t a ct.T 1 1 1e J , [Addr e s s ] , [C 1 1 y ] , [Re g l o n ], [Po.s t a 1Code J , [C o u n t r y ] , [Phone] , [Fax ] ) VALUE'.'. ( 0CustomerID 1, 0CompanyMame 2, 0ContactName 3, 0ContactTitle 4, 0Addr e s s 5 , 0C l t y_-; , @Peqion 7 , 0 P o s t a 1C o c le 8 ,

502

@Country 9, @Phone 10, @Faz 11)

La nica parte compl icada es saber cmo definir y establecer los parmetros. Esto se hace mediante la coleccion P a r a m e t e r s . C omo en cualqui er coleccion. los nuev os mi embros se crean con el mtodo A d d ( ) . El p ar amet ro recien creado es devuelto y se puede establecer la direccin (tanto si el p ar a me tr o se usa solo para introducir datos, par a salida de datos o para ambas operaciones) y el valor. Los p ar met ros del mtodo A d d ( ) son el nombre del p ar amet ro del procedi mien to almacenado, su nombre, su tipo de datos y su tamao. El listado 23.5 muestra el cdigo para todo el proceso.
Listado 23.5. Cmo llamar a un procedimiento alm acenado con parmetros en A D O .N E T static void TestlnsertWi thSPStatement s t n n g cus t orne r ID )

i
/ '/ Establece la cadena de ins t rucci o r , SQL string st rSQLlnse r t . - "[pe insCustomersj // Crea objetos OleDb OleDbConnection databaseComiection new Ole DbConne c t.ion (o 1e DbC onne c t r onS t ring ; ; OleDbCominand insertCommand = new OleDbCommand !st.r SQLlnserf , databaseConnecti 011 ) ; // Est amos tratando con una p r o c e d m u ento aImacenado (es d e c i r , I J O con una instruccin SQL) rns e r t Command .CominandType = ComniandType .S t o red Pr ocedu r e ; // Agregue cada parametro (1 de 11' OleDbParameter param = inserto ommand .Parameters .Add ( "@Cu.st orne r I D J " , O l e D b T y p e .VarChar , 5) ; param.Drrection - P ar am et erDirection.Inpu t; param.Valu = customerID; // Agregue cada parametro (#2 de 11 param = insertCommand .Parameters .Add ( ," @CompanyName _2 " , 01 eDbType.VarChar, 40) ; param.Direction = ParameterDrrection.Input; param.Value = "Hungry Coyote Export S t o r e " ; // Agregue cada parametro 3-10 // Etc. // Agregue cada parametro (11 de 11) param = insertCommand.Pa r a m e t e r s . A d d ("@Fax 11", O leDbType.VarChar, 24) ; p a r a m .Direction = ParameterDrrection.Input; param.Value = "(b03) b55-2376"; try

503

// Establezca la conexin de la base de datos da t aba s eC onne c f i on .Open ! ; // Ene-cu te el comando SQL m t numPow.s - iuse rtCommand .ExecuteNonQuery () ; // Informe de los resultados C ons o 1 .e .W rite L m e ( " Tn s erted {0 } r ow (s ) ." , n u m P o w s .ToSt r in g ( ) ) ;

}
cat ch (Excepfion
e )

Consol e.Wri tep.ne (" ** e .M e s s a q e ; ; Caught an except ion: \nj )",

}
final 1y 1 da t aba s eConnecti o n .C 1 ose () ; 1

Operaciones de datos que devuelven entidades de fila nica


Algunas operaciones de datos, como recuperar un registro basado en una clave primaria, solo devuelven una fila. A D O . N E T propor ci ona tres modos de recupe rar una sola fila. Un modo solo se aplica a las entidades de fila nica \ los otros dos modos son genericos y pueden ser usados par a recuperar v a n a s filas (como ver en la siguiente seccin). El modo mas eficiente de recuper ar una entidad de fila nica suele ser medi an te un par amet ro de salida. Sin embargo, este mtodo slo se puede usar cuando se esta seguro de que el procedimiento devuelve una sola fila. El listado 23.6 m ue s tra un procedimiento SQL Server al macenado que recupera un nico registro mediante par met ros de salida.
Listado 23.6. Un procedimiento SQL Server almacenado para recuperar un nico registro USE F i o rt hw ind ] GO CPEATE PPC.'CFJitJPF. [pe getContaet B yCu s t orne r I D ] (0Cust ornerID I [n e h a r ] <5) , @Cont ar-t llame 7 [nvarcharj 30) output, 0C: ontact Tirle 3 [nva r char| t 30 o u tp u t) SELEGT @Cont actame 2 - [ContactNariie] , 0C o 111 a c t T 1 1 1e 3 - [ContactTitle]

504

FROM [ N o r t h w m d J . [dbo] . [Customers W H ERE [CustomerID] = @ C u s t o m e r I D 1

La invocacin de este procedimiento almac en ad o es similar al codigo usado par a llamar al procedimiento al macenado que inserta una fila (vase el listado 2 3 . 3 ) . Por supuesto, la direccin par a los par met ros de salida se establece en ParameterDirect i o n .Output . Tra s ejecutar el procedimiento a l m a c en a do. puede usar la coleccin Parameters para recuperar los valores de los par met ros de salida, como muest ra el listado 23.7.
Listado 23.7. Cmo recuperar un nico registro mediante parmetros de salida
stati c voici Tes t .S P W i t h O u t P a ram (st ring customerlD)

{
// E s t a b l e z c a las c adenas ce la i n s t r u c c i n SQL st r i n g s t r S Q L S e l e c t = "[pe ge t C o n t a c t ByCus t orne r 11 ']" ; // Cree ob jet os Ol eDb O l e D b C o n n e c t i o n d a t a b a s e C o n n e c t i o n - new OleDbConnection ( .o 1 e DbC onne c 1 . 1 onS t r ing ) ; O l e D b C o m m a n d selectCoiranand = ne w O l e D b C o m m a n d (st rSQLSe 1ect , d a t a b a s e C o n n e c t i o n ); // E stamos t r a t a n d o con un p r o c e d i m i e n t o a l m a c e n a d o (es decir, NO una i n s t r u c c i n SQL) s e 1 e c t C o m m a n d .C o m m a n d T y p e = CominandType .S t or edPr ocedu r e ; // A g r e g u e cada p a r a m e t r o (1 de 3) OleDbParameter param = s e 1 e c t C o m m a n d . P a r amet e r s .A d d ("@Cus torne rID_ 1", O l e D b T y p e .V a r C h a r , 5) ; p a r a m . V a l u - cust.omerlD; // A g r e g u e cada p a r a m e t r o (2 de 3) param = se l e c t C o m m a n d . P a r a m e t e r s .Add ("SOont act Nam e 2", OleDbType.VarChar, 30); par a m .Di r ect i on = Par amet er Di r ect ion .Output. ; // A g r e g u e cada p a r a m e t r o (3 de 3) p a r a m = s e l e c t C o m m a n d . P a r a m e t e r s . A d d (" @ C o n t a c t T i t l e 3", O l e D b T y p e .V a r C h a r , 30); param.Direction = ParameterDirection.Output; t ry

{
// E s t a b l e z c a la c o n e x i o n de d a t a b a s e C o n n e c t i o n . O p e n () ; la base de datos

// E j e cu te el co m a n d o SQL s e l e c t C o m m a n d .E x e c u t e N o n Q u e r y (); // Informe de los r e s u l tad os

505

string contactName = s e 1e ct C o m m a n d .Pa r ame t e rs ["@Cont a c t N a m e _ 2 "] .Value.ToString!) ; string contactTitle = s electCommand.Parameters["@ContactTrtle 3 " ] .V a l u e . T o S t r i n g (); Console . W r i t e L m e ("Cont act name is {0 } , title is {!}.", contactName, contactTitle) ;

}
catch (Exception e) Caught an exception:\n{0}" ,

{
Console.WriteLine ("** + + ** e .M e s s a g e ) ;

}
finally

{
da t a b a seConnection.Close ( );

} } Observe a hora los mtodos genricos de lectura de datos. El primero usa un o bj et o O l e D b D a t a R e a d e r . El o b j e t o C o m m a n d t i e n e un m t o d o EzecuteReader ( ) . que devuelve un objeto OleDbDataReader. A cont i nuacin puede usar el mtodo Read ( ) par a recorrer el contenido del DataReader. Read ( ) d evuelve True c uando se encuentran datos durante la lectura y False en caso contrario. El listado 23.8 mues tra cmo hacerlo. Observe que este ejem plo usa una instruccin SQL par a acceder a un procedimiento al macenado solo par a mo st rar un modo alternativo de llamar a un procedimiento almacenado. Esto slo se hace con fines demostrativos, ya que es ms eficiente llamar a un p roc edi miento almac en ad o de la forma que se mues tra en el listado 23 .7.
Listado 23.8. Cmo recuperar un registro nico mediante DataReader static void Test Se le ct Wi th Da ta Re ad er (string customerID)

{
// Establezca las cadenas de instruccin SQL, dando por sentado que customerID no contiene comillas string strSQLSelect = "EXEC [pe getCustomer ByCustornerID ] @CustomerID 1= ' " + customerID + " // Cree objetos OleDb OleDbConnecti on databaseConnection = new 0 1 e D b C o n n e c 1 1 on (o 1e Db C o n n e c 1 1 o n S t r i n g ) ; OleDbCommand selectCommand = new OleDbCommand(strSQLSelect, databaseConnection); // Estamos tratando con una instruccin SQL (es decir, procedimiento almacenado) s e l ec tC om ma nd .CommandType = CommandType .Text ; try NO con

un

(
// Establezca la conex i on de la base de datos

506

d a t a b a s e C o n n e c t i o n .O p e n (); // Ejecute el comando SQL OleDbDataReader rowReader // if

se 1 ectC o m m a n d .ExecuteReader ( );

Informe de los resultados (r o w Re ad er .R e a d ( ))

{
string contactName = r owReader ["ContactName " ] . T o S t n n g ; string contactTitle = r o w R e a d e r (" C o n t a c tT it le "] .ToString ( ); Con s o l e . W r i t e L m e ("Contact name contactName, contactTitle) ;

is

{0 } , title

is

{1 } . " ,

}
else

{
Console . W r i t e L m e ("No rows found!");

} }
catch (Exception e) Caught an ex c e p t i o n :\n( 0 1",

{
Console.WriteLine ("** + *** e.Message);

}
finally

{
databaseConnection.Close () ;

) } El otro mtodo genrico de r ecuper ar datos es mediante el verstil objeto

DataSet. C omo el objeto DataSet fue diseado par a ser usado i ndependien t ement e de la fuente de datos que lo origino, no hay 01 e D b DataSet m SqlDataSet. solo un DataSet. Un DataSet se usa en conjuncin con un DataAdapter. Un objeto DataAdapter se usa especficamente par a a l m a cenar datos (es decir, se usa OleDbDataAdaper) y contiene cuatr o objetos de
comando par a realizar operaciones:

InsertCommand SelectCommand UpdateCommand DeleteCommand

Tras seleccionar el objeto SelectCommand se puede em pl ea r el mtodo Fill ( ) par a completar un DataSet La siguiente seccin muest ra cmo usar los otros tres comandos par a modificar los datos que contiene un DataSet. Un DataSet contiene uno o ms objetos DataTable. Cada DataTable cont ie

507

ne uno o ms objetos DataRow. Estos objetos DataRow se almacenan en la coleccion Rows del DataSet. Un objeto DataRow contiene uno o ms objetos DataColumn. Estos objetos DataColumn se a l m a c en an en la coleccin Columns del DataRow. Las colecciones Row y Column son indizadas m e diante el ndice y el nombre. De hecho, puede imagi nar el objeto DataSet como una base de datos en memoria. El listado 23.9 mues tra un p ro gr a ma de ejemplo que recupera un nico registro usando un objeto DataSet.
Listado 23.9. Cmo recuperar un registro nico mediante DataSet static void TestSelectWithDataSet(string customerID)

I
// Establezca las cadenas de instruccin SQL string strSQLSelect - "EXEC [pe getCustomer ByCustornerID ] 0CustomerID 1-'" + customerID + // Cree objetos OleDb OleDbConnecti on databaseConnection = new 0 1 e Db Co n n e c 1 1 on (o 1e Db Co nn ec t i o n S t r i n g ) ; OleDbCommand se 1ectCommand = new OleDbCommand(strSQLSelect, databaseConnection); 0 1eDbDataAdapter dsCmd = new O le Db Da ta A d a p t e r ( ); DataSet resultDataSet = new D a t a S e t (); // Estamos tratando con una instruccin SQL (es decir, procedimiento almacenado) se 1e ct Co mm an d.CommandType = C o m m a n d T y p e .T e x t ; try NO con

un

{
// Establezca la conexi on de la base d at a b a s e C o n n e c 1 1 o n .Open () ; de datos

// Ejecute el comando SQL d s C m d .Se 1ectCommand = se 1ectC o m m a n d ; int numRows = d s C m d .F i 11 (resultDataSet, "Customers") ; // if Informe de los (numRows > 0) resultados

(
string contactName = resultDataSet.Tables["Customers"] . Rows [0 ] ["ContactName"] . T o S t n n g O ; string .T a b l e s ["Customers"] . Rows [0 ] ["ContactTitle" ] .T o S t n n g () ; Console.WriteLine("Contact contactName, c name is {0}, title is {1}.",

else
Console.WriteLine ("No rows found!");

508

catch

(Exception

e) Caught an exception:\n(0} ",

{
Consol.WriteLine ("** + *** e.Message);

}
fina 11y

{
d a t a b a s e C o n n e c t i o n . C i s e ();

} }

Operaciones de datos que afectan a las entidades de fila nica


Esta seccin estudia las propiedades InsertCommand. UpdateCommand v DeleteCommand del objeto DataAdapter. Para cada uno de estos c o m a n dos se puede est abl ecer el coman do mediante p rog ramaci n o se puede generar automt icamente. El pri mer mtodo suele dar como resultado un mejor rendi miento porque supone menos encabezados.

Operaciones de introduccin de datos que afectan a las entidades de fila nica


El cdigo del listado 23.10 usa un idioma aut omt ico que es til par a generar au t o mt i came nt e instrucciones Insert. Medi ant e Se 1ectCommand se c ons i gue un DataSet Yaci. Esta llamada Fill() solo sirve p ar a recuperar la es truc tu ra de las filas que quiere manipular. Esto es ms flexible que definir la es tructur a mediante programacin. El secreto par a generar aut omt icame nte comandos DataAdapter es crear un objeto CommandBuiIder que usa el DataAdapter como un ar gu me nt o en el constructor, como mues tran las siguientes lneas:
// La siguiente linea es clave para generar instrucciones autom t ic am en te !! ! OleDbCommandBuilder custCB = new O l e D b C o m m a n d B u i l d e r (d s C m d );

Sin estas lneas, la posterior instruccin Update ( ) funcionar mal porque InsertCommand no puede generar se automt icamente. Las operaciones gene radas aut omt icame nte UpdateCommand y DeleteCommand tienen los m i s mos requisitos. El listado 23.10 mues tra todo el procedimiento en funcionamiento. Tras re cuperar la estructura de la tabla Customers mediante un procedi miento a l m a cenado (que aparece en el listado 23.1 1). se crea una nueva fila mediante una l lamada al mtodo NewRow ( ) . A continuacin se asigna un valor a cada c ol u m na de la nueva fila y esa fila recin compl et ada se agrega a la coleccion Rows

509

mediante una llamada al mtodo AddRow (). Finalmente, este cambi o se enva a la fuente de datos cr eada mediante una l lamada del DataAdapter al mtodo

IJpdate ().
Listado 23.10. Cmo agregar un registro nico mediante un co mando InsertC ommand generado automticamente static void Te.stAutoInsertWithDataSet (string customerID)

I
// Establezca las cadenas de instruccin SQL, solo necesitamos los metadatos de modo que // ningn registro concuerde con este CustomerID. string strSQLSelect = "EXEC [pe getCustomer ByCus t ome r ID ] 0Cus t ome r ID 1-'???'" ; // Crea objetos OleDb QleDhConnecti on databaseConnecti on = new 0 1 e DbConne ct i on (oleDbConnectionString) ; OleDbCommand selectCommand = new OleDbCommand(strSQLSelect, databaseConnecti o n ) ; OleDbDataAdapter dsCmd = new OleDbDataAdapter ( ); // La siguiente linea es clave para generar instrucciones a u t o m t i c a m e n t e !!! OleDbCommandBuiIder custCB = new OleDbCommandBuilder(dsCmd); DataSet resul.tDataSet = new DataSet ( ); // Estamos tratando con una instruccin SQL (es decir, procedimiento almacenado) sel ectC o m m a n d .CommandType - C o m m an dT yp e .T e x t ; try NO con

un

{
// Establezca la conexion de la base de datos d a t a b a s e C o n n e c t i o n .Open () ; // Ejecute el comando SQL dsCmd .S e ]ectCommand = se1ectC om m a n d ; // Recupera la estructura de la tabla Customers int numPows = d s C m d .F i 11(resultD a t aS et , "Customers"); // Cree una nueva fila DataRow workRow = r e s u 11Da t a S e t .T a b 1es ["Custome r s "] .N e w R o w ( ); // Complete los datos workrow workRow["CustomerID"] = customerID; // 1 w o r k R o w ["CompanyName" ] = "Hungry Coyote Export

Store";

//

2
w o r k R o w ["ContactName"] = "Yoshi Latimer"; // 3 w o r k R o w ["ContactTitle"] = "Sales Representative"; // 4 w o r k R o w ["Address"] = "City Center Plaza 516 Main St.";

// 5

510

w o r k R o w ["City"] = "Elgin"; // 6 w o r k R o w ["Region"] = "OR"; // 7 w o r k R o w ["PostalCode " ] = "9782 7 "; // 8 w o r k R o w ["Country" ] = "USA"; // 9 workRow ["P ho ne ' '] = "(503) 555- 68 74 "; // 10 w o r k R o w ["F ax " ] = "(503) 555-2376"; // 11 resultDataSet.Tables ["Oust ome r s "] .R o w s .Add(work Row) ; // Compatibilice los cambios con la fuente de datos dsCmd.Update(resultDataSet, "Customers); // Informe de los resultados Console. W r i t e L m e ("Inserted 1 r ow ." ) ;

}
catch (Exception e) Caught an exception:\n(0}",

{
C o n s o l e . W n t e L i n e ("****** e .Mes s a g e ) ;

}
finally

{
d a t a b a s e C o n n e c t l o n .C 1ose () ;

Listado 23.11. Procedimiento almacenado para recuperar la estructura de la tabla C ustom ers USE [Northwind] GO CREATE PROCEDURE [pc^getCustomer_ByCustomerID] (@CustomerID_l [ nchar](5)) AS SELECT [C u s t o m e r I D ] , [CompanyName], [ContactName], [C o n t a c t T i t 1e ], [ Addres s ] , [City], [R e g o n ], [P o s t a l C o d e ], [C o u n t r y ], [P h o n e ], [Fax] FROM [Northwind]. [dbo]. [Customers] WHERE [CustomerID] = 0CustomerID_1

Hay que definir mediante pro gr amaci n un comando que realice la int roduc cin de datos. Ya aprendi a hacerlo con un procedimiento almac en ad o con

511

par met ros (por cierto, uno de los modos ms eficientes de realizar operaciones con datos) en el listado 23.5. Tra s definir el comando y sus parmetros, todo lo que debe hacer es establecer el InsertCommand de DataAdapter. como muest ra el listado 23.12. El resto del cdigo (crear una nueva fila, dar valores a las columnas, agr egar la nuev a fila y actual izar el cdigo fuente) es igual que el codigo usado para un InsertCommand generado aut omt icamente. C om o se usa un enfoque igual a la creacin manual de un comando para Updat eCorranand v DeleteCommand. la siguiente seccin solo mues tra c mo usar los comandos generados automticamente.
Listado 23.12. Cmo agregar un registro nico mediante InsertC ommand static void TestDataSetInsertCommand(string customerID)

{
// Establezca las cadenas de instruccin SQL string strSQLSelect - "EXEC [pe getCustomer ByCustornerID] @Cus t orne r IE > 1 ; string strSQLInsert = "[pe insCustorners]" ; // Cree objetos OleDb 'tleDbConnection dat abas eConnect i on = new 0 1 e D b C o nncct ion oleDbConnectonString) ; OJ eDbCommand s ele ct Command = new OleDbCommand !strSQLSelect. , datahaseCo n nection) ; OleDbDal. aAdcipter clsCmcl - new 01 eDbDat aAdap t e r () ; DataSet resultDataSet - new D a t a S e t (); // Estamos tratando con una instruccin SQL (es decir, procedimiento almacenado) s e 1ec t C om ma nd .OommandType = Co mm an d T y p e .T e x t ; NO con

un

OleDbCommand InsertCommand = new O leDbCommand(strSQLInseit, dat ab a s e C o n n e c 1 1 o n ) ; ins e r t C o m m a n d .C ommandType = Co mm an d T y p e .StoredProcedure; ins e r tCommand .CommanclTe xt = "[pe insCustomers] insert Co mm an d.Connection = da ta ba seConnection; // Agregue cada parametro (1 de 11) O 1eDbParameter param = inserto o m m a n d .Pa r a m e t e r s .A d d ("@Cus t orne rID 1" , OieDbType.VarChar, 5) ; param.Direction = ParameterDirection.Input; param.SourceColumn = "CustomerID"; // Agregue cada parametro (2 de 11) param - insert Co mm an d.P a r am et er s.A d d ("0CompanyName 2", O i e D b T y p e .V a r C h a r , 40); param.Directron = ParameteiDirection.Input; param.SourceColumn = "Co mpanyName"; // Agregue cada parametro 3-10 // Etc. // Aqrecjue cada parametro (11 de 11)

512

param = m s e r t C o m m a n d .Paramet e r s .A d d ("0Fax 11", O l e D b T v p e .V a r C h a r , 24); param.SourceColumn try = "Fax";

{
// Establezca la conexion de la base de datos d a t ab a s e Co nn e c 1 1 o n .O p e n ( ); // Ejecute el comando SQL d s C m d .SelectCommand = se1ec tC om ma nd ; d s C m d .InsertCommand = insertCommand; mt numRows = d s C m d .Fi11 (resultDataSet , "Customers")

// Cree una nueva fila DataRow workRow = resultDataSet .Tables ["Oust ome r s " ] .NewRow (, ); // Complete los datos workrow workRow CustomerID"] = customerID; // 1 workRow Co mp an yN am e"] = "Hungry Coyote Export

Store // 3 St.

//

2
workRow wor kRow wor kRow Contac tN am e" ] = Address"] "Yoshi Latimer"; Plaza

= "City Center

516 M a m

// 5 workRow wor kRow wor kRow workRow workRow workRow City"] = "Elgin"; // 6 Region"] = "OR"; // 7 PostalCode"] = "97827"; // 8 Country"] = "USA"; // 9 Phone"] = "(503) 555-6874"; // 10 Fax"] = "(503) 555-2376"; // 11

re su ltDataSet.Tables ["Cus tome r s " ] .Rows.Add(wo r k R o w ) ; // Compatibilice los cambios con la fuente de datos d s C m d . U pd at e(resultDataSet, "Customers"); // Informe de los resultados C o n s o l e . Wr iteLine("Inserted 1 r o w .");

}
catch (Exception e) an exception: \n( 0) "

{
Console .WriteLine (''***** * Caught e.Message);

}
finally

{
d a ta ba s e C on ne c1 1 o n .C 1 ose ( );

Operaciones de actualizacin que afectan a entidades de fila nica


Para realizar operaciones que tienen lugar mediante un DataSet. ob vi amen te es necesario recuperar antes la fila que se quiere modificar. Por tanto, no es necesario el truco sugerido p ar a la instruccin Insert. Tras recuper ar un DataSet. se puede simplemente ac tual izar una col umna de una fila especfica. En ese moment o se puede l lamar al mtodo Update ( ) de DataAdapter para p r opa ga r los cambios en la fuente de datos. Por ahora, el contenido del listado 23.13 le resultar conocido. Como se seal en la seccin anterior, el no usar instrucciones generadas aut omticamente slo significa que deber crear m a nu al mente un co man do que controle la instruccin Update.
Listado 23.13. Cmo actualizar un registro nico mediante un U pdateC om m and generado autom ticamente static void TestAutoUpda te Wi th Da ta Se t(string customerID)

{
// Establezca las cadenas de instruccin SQL string strSQLSelect = "EXEC [pc_getCustomer ByCustornerID] 0CustomerID 1= ' " + customerID + " // Cree objetos OleDb OleDbConnection databaseConnection = new O l e D b C o n n e c t i o n (o le Db Co n n e c t i o n S t r i n g ) ; OleDbCommand selectCommand = new OleDbCommand(strSQLSelect, da ta ba s e C o n n e c t i o n ) ; OleDbDataAdapter dsCmd = new O le Db D a t a A d a p t e r ( ); // ;La siguiente linea es clave para generar instrucciones a u t o m t i c a m e n t e ! !! 0 1 eDbCommandBuilder custCB = new OleDbCommandBuilder(dsCmd); DataSet resultDataSet - new DataSet ( ); // Estamos tratando con una instruccin SQL (es decir, procedimiento almacenado) se le ct Co mm an d.CommandType = C om ma n d T y p e .T e x t ; t ry NO con

un

<
// Establezca la conexion de la base de datos d a t a b a s e C o n n e c t i o n . O p e n (); // Ejecute el comando SQL d s C m d .S e 1ectCommand = selectCommand; m t numRows = dsCmd.Fill(resultDataSet, // f Informe de los (numRows > 0) resultados

"Customers");

i
r e s u lt Da ta Se t. Ta bl es ["Customers"].R o w s [0]["ContactTitle"] "Sr. Sales Representative" ;

514

// Compatibi1ice los cambios con la fuente de datos d s C m d .Update (resultDataSet, "Customers") ; C on so le . W r i t e L i n e ("1 row u p d a t e d !");

}
else

{
Co n s o l e .W ri te Li ne ("No rows found!");

) }
catch (Exception e) an exception: \n{ 0) ",

{
Console .WriteLine (''***** * Caught e.Message);

}
finally

{
databaseConnection.Close ( );

} }

Operaciones de borrado que afectan a las entidades de fila nica


Por supuesto, no todas las operaciones que afectan a las entidades de fila nica deben realizarse mediante un D a t a S e t . Tambi n se puede usar un procedi miento al macenado o una instruccin SQL. El listado 23.14 muestra como usar una instruccin SQL para borrar una fila nica en una tabla
Listado 23.14. C mo borrar un registro nico mediante una instruccin SQL static void T e s t D e 1ete St at em en t(string customer ID)

{
// Establezca las cadenas de instruccin SQL string strSQLDelete = "DELETE FROM Customers WHERE + customer ID + CustomerID

// Cree objetos OleDb OleDbConnection databaseConnection - new 01 eDbConnect i on (ol eD bC on ne ct io nS tn ng ) ; OleDbCommand deleteCommand = new O l e D b C o m m a n d (s tr SQLDelete, databaseConnection); // Estamos tratando con una instruccin SQL (es decir, procedimiento almacenado) d e le te Co mm an d.CommandType = C om ma n d T y p e .Text ; try NO con

un

{
// Establezca la conexion de la base de datos d a t a b a s e C o n n e c t i o n .Open () ;

515

// Ejecute el comando SQL int numRows = d e le te Co mm an d.E xe cu te N o n Q u e r y (); // Informe de los resultados Console.WriteLine("Deleted {0} n umP o w s .T o S t rin g () ) ;

row(s)

}
catch (Exception e) Caught an exception: \n{0) ",

{
Console.WnteLme e .M e s s a g e ) ;

}
final 1y

{
d a t a b a s e C o n n e c t ion.Close () ;

} } El l i s t a d o 2 3 . 1 5 f i n a l i z a con el e s t u d i o de los c o m a n d o s g e n e r a d o s automticamente, mostrndole cmo borr ar una fila nica usando este sistema Tras completar un DataSet, puede eliminar una fila con una llamada Delete (). Como siempre, se necesita una llamada Update ( ) par a fijar este cambio en la fuente de datos.
Listado 23.15. Cmo borrar un registro nico con un DeleteComm and generado auto m tica m e n te. static void Tes t . Au toDeleteWithDataSet (string cust orne r ID )

(
// Establezca las cadenas de instruccin SQL string strSQLSelect = "EXEC [pc_getCustorner_ByCustornerID ] @ Cu stomerID_1= ' " + customer ID + // Cree objetos OleDb OleDbConnection databaseConnection = new 0 1 eD bC o n n e c 1 1 o n (o 1e Db Co n n e c t i o n S t r i n g ) ; OleDbCommand s e 1ectCommand = new OleDbCommand(strSQLSelect, databaseConnection); 0 1eDbDataAdapter dsCmd = new 0 1 eD bD at a A d a p t e r (); // La siguiente linea es clave para generar instrucciones automticamente!! ! 0 1eDbCommandBuilder custCB = new OleDbCommandBuilder(dsCmd); DataSet resultDataSet = new DataSet () ; // Estamos tratando con una instruccin SQL (es decir, procedimiento almacenado) s e 1e c t C om ma nd .CommandType = Co mm an d T y p e .T e x t ; try NO con

un

(
// Establezca la conexion de da ta ba s e C o n n e c 1 1 o n .O p e n ( ); la base de datos

516

// Ejecute el comando SQL d s C m d .SelectCommand = s e 1ec tC om ma nd ; int numRows = d s C m d .F i l l (resultDataSet, "Gustmers") // if Informe de los (numRows > 0) resultados

{
resultDataSet.Tables ["Cus torne rs"] .Rows [0] .Delete () ; // C ompatbi1iza los cambios con la fuente de datos ds C m d .Update (resultDataSet, "Customers") ; Consol.WriteLinc ("1 r ow deleted !" ;

}
e 1s e

(
Consol . W r i t e L m e ("No rows found !" ) ;

} }
catch (Exception e) Caught an exception: \n((l) ",

{
Consol . W n t e L i n e ("*****+ e .M e s s a g e ) ;

}
f i n a 11 y

{
databaseConnection.Cise ( );

} }

Operaciones de datos que devuelven conjuntos de filas


Ya vimos dos maner as de r ecuper ar conjuntos de filas cuando explicamos cmo r ecuperar una fila nica. El listado 23.16 usa un procedimiento almacenado p ar a explicar la recuperacin de un conjunto de filas. Usa una instruccin TOP 5 p ar a mantener el nmero de filas devueltas en un numero aceptable La nica diferencia reseable entre el listado 23.17 \ el listado 23.8 es el uso del bucle w h i l e (en lugar de la instruccin i f ) par a recorrer todos los registros.
Listado 23.16. Procedimiento almacenado SQL Server para seleccionar un conjunto de registros USE [Northwind] GO CREATE PROCEDURE AS SELECT TOP 5 [Cus t orne r I D ] , [C o m p a n y N a m e ],

[pc_getCus t orner s ]

517

[C o n t a c t N a m e ], [C o n t a c t T i1 1e ] , [Address], [City] , [R e g i o n ], [P o s t a l C o d e ], [Country], [P h o n e ] , [Fax ] FROM [Northwind]. [dbo]. [Customers] Listado 23.17. Cmo recuperar un conjunto de registros con DataReader static void TestSelectManyWithData R e a d e r (string customerID)

{
// Establezca las cadenas de instruccin SQL string strSQLSelect = "[pe getC usto me r s]" ; // Cree objetos OleDb 01 eDbConnecti on databaseConnection = new 0 1 e D b C o n n e c t i o n (o 1eD bC on ne c t i o n S t r i n g ); OleDbCommand se1ectCommand = new O l e D b C o m m a n d (strSQLSelect , databaseConnection); // Estamos tratando con procedimientos almacenados (es decir, NO con una instruccin SQL) select C o m m a n d .0 ommandType = C om ma nd Ty pe .StoredProcedure; t ry

{
// Establezca la conexin de la base de datos databaseConnection.Open () ; // Ejecuta el comando SQL OleDbDataReader rowReader

s e 1ectC o m m a n d .Exe cute R e a d e r ();

// Informe de los resultados whi 1e (r owR e a d e r .Read ( ))

{
string contact.Name = r o w R e a d e r ["Cont a c tN a m e "] .T o S t r i n g ( ); string contactT i tie = r owReade r ["Cont actTi t le " ] . T o S t n n g O ; Console . W r i t e L m e ("Contact name contactName, c on tactTitie) ;

is

(0),

title

is

{1}.",

} }
catch (Exception e) Caught an exception: \n( 0) ",

{
Console . W n t e L i n e ("* + **** e .M e s s a g e ) ;

}
finally

518

{
databaseConnection.Clo.se ( );

} } El uso de un objeto DataSet par a recuper ar un conjunto de registros t a m bin le resultar familiar (vase el listado 23.9). De nuevo, todo lo que tiene que hacer es aadir una iteracin par a c ap tur ar todos los registros recuperados. Esto puede hacerse con un bucle for. como mues tra el listado 23.1 8.
Listado 23.18. Cmo recuperar un conjunto de registros con DataSet. static void TestSelectManyWithDataSet(string customerID)

{
// Establezca las cadenas de instruccin SQL string strSQLSelect = "[pe g et Customers] " ; // Cree objetos OleDb OleDbConnection databaseConnection = new OleDbConnection ( o l e D bC on ne ct io nS tn ng ) ; OleDbCommand selectCommand = new O l e D b C o m m a n d (strSQL Se le ct , databaseConnection); OleDbDataAdapter dsCmd = new O le Db D a t a A d a p t e r (); DataSet resultDataSet = new DataSet (); // Estamos tratando con procedimientos almacenados (es decir, NO con una instruccin SQL) sel ec tC om ma nd .CommandType = C o m m a n d T y p e .S t or ed Procedure; try

{
// Establezca la conexin de la base de datos databaseConnecti o n .Open () ; // Ejecute el comando SQL d s C m d .SelectCommand = selectCommand; int numRows = d s C m d .F i l l (resultDataSet, "Customers"); // if Informe de los (numRows > 0) resultados

(
// numRows = r e s u l t D a t a S e t .Tables ["Cust orne r s "] .Rows.Count for (int i=0; i<= numRows - 1; i++)

{
string contactName resultDataSet.T a b l e s ["Customers"].R o w s [i ]["ContactName" J . ToStnng ( ); string contactTitle resultDataSet.Tables ["Customers"] .Rows [i ] ["ContactTitle"] . T o S t n n g () ;

519

C o n s o l e .WriteLine (" Contact { 1} . , contdctMame, contactTitle) ;

name

is

{0},

title

is

} )
else

{
Console.WriteLine ("No rows found!") ;

) ) catch { I
f in a 11 y

( Ex c e p t i o n e )
Caught an exception:\n(0) ",

Console.WriteLine ("* + **** e.Mess age) ;

(
databaseConnection.Close () ;

Operaciones de datos que afectan a conjuntos de filas


Las operaciones de datos que afectan a conjuntos de filas siguen la misma estructura que las operaciones que afectan a las filas nicas. El listado 23.1 agrega dos nuevas filas antes de llamar al comando Update (). Si lo c o m p a r a mos con el listado 23.10 no aparece ninguna diferencia, aparte de la obvia adicin del cdigo que crea, da valor y agrega la segunda fila Debido a las similitudes entre el cdigo para una fila nica y el cdigo par a filas mltiples, esta seccin no repetir todos los ejemplos most rados con anterioridad par a las instrucciones que afectan a varias filas Update y Delete.
Listado 23.19. Cmo agregar dos registros mediante un InsertC ommand generado a u to m tica m en te static stnng void TestAutolnsert2WithDataSet (string cus torne r ID2 ) customerIDl,

(
// Establezca las cadenas de instruccin SQL s t n n g strSQLSelect = "EXEC [pe getCustomer ByCust orne r ID ] @ C u s t orne r ID 1=' ? ? ? ' " ; // Cree objetos OleDb OleDbConnection databaseConnection = new O l e D b C o n n e c t i o n (oleDbConnectionString) ; 0 1 eDbCommand selectCommand = new OleDbCommand(strSQLSelect, d a t a b a s e C o n n e c t i o n ); OleDbDataAdapter dsCmd = new 01 eD bD at a A d a p t e r (); // La siguiente linea es clave para generar instrucciones automticamente!! !

520

Ol e DbCommandBu i ]de r custCB = new uleDbConimandBui Ider idsCmd; DataSet resultDataSet - new DataSet ( ); // Estamos tratando con una un procedimiento almacenado) sele ct Co mm an d.CommandType = try / / Establezca la conexion de ddt.abaseConnection.Open () ; la l ia s e de datos ion SQL

les

deci.

C o m m a n d T y p e .Text ;

// Ejecute el comando SQL d s C m d .Se 1ectCommand = se 1ectC o m m a n d ; int. numRows = dsCmd. Fil 1 (resultliata.Set // Cree una nueva prime r a fila DataRow workRow = re su l t D a t a S e t .Tabi es ["Custorne r s "] .MewRow // C omp ete los datos work row wo r k R ow "Custome rID" ] = cust ome r 1D 1; wo r kRow "CompanyName "] = "Hungry Coyote

' Cus t orne r s " )

// 1 : Store F , : -po r t

workRow "ContactName "] = "Yoshi Latimer"; // 3 wo r k . Row "ContactTitl e " ] = "Sales Pepresent.at iv e " ; wo r kRow "Address"] = "City Center Plaza 51 6 M a m St . workRow wor kRow workRow workRow workRow workRow "City"] = "Elgin"; // 6 "Region"] - "OR"; // 7 "PostalCode" ] - "9782'/"; // 8 "Count r y "] "USA"; // "Phone"] = ' (503) 555-6874"; "Fax"] = "(503) 5 5 5-2376"; //

// J

10

.Tables ["Cust orne r s " ] .Rows .Acid (workP ow ) // Cree una nueva segunda linea workRow = resultDataSet.Tables["Customers Complete los datos work row wo rkRow "CustomerlD"] = custome rI D2 ; workRow "CompanyName"] - "Hungry Coyote

.N e w R o w (

// 1 Export

Store'

workRow "ContactName"] = "Yoshi Latimer"; // 3 workRow "ContactTit1e "] = "Sales Representative"; workRow "Address ] - "City Center Plaza 516 Main S t . workRow workRow workRow workRow workRow

"City"]

= "Elgin";

// 6

"Region"] = "OR"; // 7 "PostalCode"] = "97 827"; // 8 "Country"] = "USA"; // 9 "Phone"] = "(503) 555-68 74"; //

10

521

w o r k R o w ["Fax "]

= "(503)

555-2376"

//

11

resultDataSet.Tables ["Cus t o m e r s "] .R o w s .A d d ( wo rkRow) ; // Compatlbi1ice los cambios con la fuente de datos d s C m d .Update (resultDataSet, "Customers") ; // Informe de los resultados Console . W r i t e L m e ("Inserted 2

rows ." ) ;

}
catch (Exception e) Caught an exception: \n{ 0 }" ,

{
Console . W r i t e L m e ("* + + *** e .Mes s a g e ) ;

}
finally

{
databaseConnection.Close ( );

} }

Operaciones que no devuelven datos jerrquicos


Un aspecto poco conocido de A DO es que es posible recuper ar varios c on ju n tos de datos de una pasada. A D O . N E T tambin dispone de esta caracterstica. Obser ve los dos procedimientos al macenados consecutivos del procedimiento a l macenado en el listado 23.20. (De nuevo, el resultado se limita a cinco registros par a cada uno. par a realizar la prueba).
Listado 23.20. Un procedimiento almacenado SQL Server con dos instrucciones Select USE [N orthwmd] GO CREATE PROCEDURE AS SELECT TOP 5 Orde r ID , Cus torne r ID , E m p 1oye e ID , OrderDate, RequiredDate, ShippedDate, ShipVia, Freght, S h ip N a m e , S hipAdd r e s s , S hipC11 y ,

[pc_getOrdersAndDetai1s ]

522

ShipRegion, ShipPostalCode, ShipCount ry FROM Orders SELECT TOP 5 Orde r I D , ProductID, UnitPrice, Quantx t y , Discount FROM [Order Details] GO

Para recuperar esto datos, emplee un DataReader de la mi sma forma que hizo p a r a recuper ar conjuntos de filas. Sin embargo, si c om p a r a el cdigo del listado 23.21 con el cdigo del listado 23.17, c o mp ro b ar que hay un bucle a di cional alrededor de la iteracin de filas. Este bucle adicional t ermina cuando NextResults ( ) es False. Esto es lo que se debe saber p ar a recuper ar c on juntos de filas mltiples.
Listado 23.21. Cmo recuperar varios c onjuntos de datos con DataReader static void TestSelectHierWithDataReader ()

{
// Establezca las cadenas de instruccin SQL s t n n g strSQLSelect = " [pc_getOrdersAndDetails ] " ; // Cree objetos OleDb OleDbConnection databaseConnection = new O l e D b C o n n e c t i o n (oleDbConnectionS t ring) ; OleDbCommand selectCommand = new OleDbCommand(strSQLSelect, databaseConnection); // Estamos tratando con procedimientos almacenados (es decir, NO con una instruccin SQL) sel ec tC om ma nd .CommandType = C o m m a n d T y p e .S toredProcedure; t ry

{
// Establezca la conexion de la base de datos databaseConnection.Open () ; // Ejecute el comando SQL OleDbDataReader rowReader // Informe de los for (; ; )

selectCommand.ExecuteReader () ;

resultados

{
w h i 1e (r o w R e a d e r .Read () )

{
st ring row = " " ;

523

for

(int

i=0;

i<=

r ow Re ad er .FieldCount + ", {0}", ";

- 1;

i++)

{
row = row + rowReader[i]

}
C o n s o l e .W r i t e L i n e ("Row is r ow .S u b s t r i n g (0, row.Length -2) ) ;

}
if ( !rowReader.NextResult ( )) break; else Console.WriteLine("Next Results:");

( )
catch (E x ception e) Caught an exception :\n {0 }" ,

{
Console .WriteLine (''****** e .M e s s a g e ) ;

}
finally

{
databaseConnection.Close () ;

} ) En la ultima seccin del codigo esta uno de los puntos fuertes del objeto D a t a S e t : la recuperacin de datos relacionados. C omo el DataSet fue diseado par a t rabaj ar como una base de datos en memoria, tiene toda la funcionalidad necesaria para tratar con las relaciones primarias y secundarias. Los siguientes dos listados ejemplifican la recuperacin de datos. El listado 23.22 muest ra cmo se recuperan datos relacionados mediante una instruccin S QL y el listado 23.23 muest ra como recuperar datos relacionados usando un objeto D a t a S e t . El lista do 23.23 demuestra como trat ar con este tipo de relaciones. De nuevo, se usa un procedimiento al macenado que devuelve datos de dos instrucciones S e l e c t . Las instrucciones S e l e c t estn relacionadas y se quiere conseguir el mismo result a do en A D O . N E T como si se recuperasen los datos con una instruccin SQL igual a la que aparece en el listado 23.22.
Listado 23.22. Cmo recuperar datos con instrucciones SQL SELECT Oid e r s . r d c r ID , O r d e r s .C u s t .orne r 11> , O r d e r s .Employ e e ID , O r d e rs .O rd e r Da t e , O r d e r s .R e q u i r e d D a t e , O r d e r s .S h ip p e d D ate", O rd e r s .S h ip V ra , O r d e r s .F r e i g h t , O r d e r s .S hip M ame, Or d e r s .S h i pA dd r e s s ,

524

O r d e r s .ShipCity, O r d e r s .ShipRegion, O r d e r s .ShipPostalCode, O r d e r s .ShipCountry, [Order Details] .ProductID, [Order Details] . U m t P n c e , [Order Details].Quantity, [Order Details].Discount FROM Orders INNER JOIN [Order Details] ON Orders.OrderlD = [Order

Details].OrderlD

En la instruccin try del listado 23.23. se empieza as ignando las tablas de datos a las tablas de origen usadas en la consulta SQL. El codigo que le sigue, completando el DataSet, es el cdigo habitual incluido ms abajo. A continuacin v iene la parte en la que se define la relacin entre las dos tablas. Al establecer las relaciones entre las claves externas en un sistema de gestin de bases de datos relacinales ( R D B M S ) se necesitan las claves pri mari as y la base de datos en memori a no es diferente. La propiedad PrmaryKey recibe una matriz de obj e tos DataColumn. T ra s establecer las claves primarias, se puede definir una relacin. El primer par amet ro es el nombre de la relacin, que us ar a ms tarde par a recuper ar los registros secundarios. A modo de demostracin, el ejemplo recupera slo la primera fila principal. A continuacin recupera todas las filas secundari as as ociadas mediante el mtodo GetChildRows ( ) us ando el n o m bre de la relacin. A continuacin se puede usar un bucle que recorra la matriz de objetos DataRow par a mostrar las filas secundarias.
Listado 23.23. Cmo recuperar datos relacionados con DataSet static void TestSelectHierWithDataSetI)

I
// Establezca las cadenas de instruccin SQL string strSQLSelect - " [pc getOrdersAndDeta i1s ]"; // Cree objetos OleDb OleDbConnection databaseConnection = new QleDbConnection (oleDbConnect l o n S t n n g l ; OleDbCommand selectCommand = new OleDbCommand(strSQLSelect, d a t a b a s e C o n n e c t i o n ); OleDbDataAdapter dsCmd = new O l e D b D a t a A d a p t e r (); DataSet result DataSet = new DataSet (j ; // Estamos tratando con procedimientos almacenados (es decir, NO con una instruccin SQL) selectCommand .CommandType = CommandType .St.or edProcedure ; try

{
d s C m d .TableMappings.Add("Orders", "Orders); d s C m d .T a b 1e M a p p m g s .A d d ("Or d e r s 1", "Order D e t ai ls ") ;

525

// Establezca la conexin de la base de datos d at ab as e C o n n e c 1 1 o n .O p e n ( ); // Ejecute el comando SQL d s C m d .SelectCommand = selectCommand; // Como no hay tablas en el DataSet antes de invocar el mtodo F i l l , // el OleDbDataAdapter crear automticamente las tablas para el DataSet // y las completar con los datos devueltos. Si crea las tablas antes de ejecutar // el mtodo FillDataSet, el OleDbDataAdapter simplemente completara las tablas existentes. int numRows = dsCmd.F i l l (resultDataSet, "Orders"); // Reduzca el numero de puntos evitando las referencias tablas DataTable orderTable = resultD at aS et .T a b l e s ["Orders"]; DataTable detailsTable = resultD at aS e t.T a b l e s ["Order Details"]; las a

// Establezca la clave primaria de las tablas orderTable .P n m a r y K e y = new D a t a C o l u m n [ ] { o r d er Ta bl e.C o l u m n s ["OrderID"] }; detailsTable .P n m a r y K e y = new DataColumn [] { detailsTable.Column s ["OrderID"] , d et a i l s T a b l e .C o l u m n s ["Product ID"] }; // Establezca la relacin de clave externa entre las tablas res ul tD at aS et .R e l a t i o n s .A d d (new D a t a R e l a t i o n ("Or de r_Det a 1 1", new D a t a C o l u m n [ ] { orderTable.Column s [" Or de rI D" ] }, new D a t a C o l u m n [ ] { detailsTable.Column s ["OrderID"]

} ) >;
// Informe de los resultados // Muestre el pedido DataRow orderRow = o rd e r T a b l e .R o w s [0]; Console. W n t e L i n e (" Order ID is {0}, date is {1} , Ship To is {2} .", o r d e r R o w ["OrderID" ] , o r d e r R o w ["OrderDate " ] , o r d e r R o w ["S h l p N a m e "]); // Recupere las filas secundarias para el pedido usando el nombre de la relacin DataRow[] detailRows = ord e r R o w .GetChildRows ("O r der_Deta 1 1") ; // Hace algo con la coleccion de filas secundarias DataRow detaiIRow; for (int i = 0; i <= de t ai lRows .Length - 1; i + +)

{
// Hace algo con la fila detail detailRow = deta ilRows [i ] ; Console . W n t e L m e ("Product ID is { 1 ) -" ,

{0},

Quantity

is

526

d e t a i 1R o w ["P r o d u c t I D "], d et a i l R o w [ " Q u a n t i t y " ]);

} }
catch (Exception e) Caught an exception: \n{ 0} " ,

{
Console . W n t e L m e ("****** e.Message);

}
finally

{
d a t a b a s e C o n n e c t i o n .Close ( );

} }

Resumen
Este captulo describe todos los tipos de operaciones que puede realizar en A DO . N E T . Tambi n se m ues tra lo sencillos y verstiles que son los objetos en el espacio de nombres System. Data, incluyendo el potente objeto DataSet, que f unciona como una base de datos en memoria. Tambi n describe cmo dev ol ver filas con entidades nicas y cmo b or r ar y actual izar operaciones. Ten ga en cuenta que la ar quit ect ura de prov eedor A D O . N E T se refleja en las clases N E T Framework que admiten A DO . N E T . Podemos usar las clases s q i par a a pr ovechar el proveedor SQL Server de A D 0 . N E T . Si su aplicacin slo v a a admitir S QL Server, debe us ar las clases SQL. porque el proveedor SQL Serv er par a A D 0 . N E T es ms eficiente y funciona mejor que el proveedor OL E DB cuando se trat a de SQL Server. Si su aplicacin necesita incluir compatibilidad con otras bases de datos que no son S QL Server, es aconsejable elegir clases OleDb.

527

3 Cmo trabajar con archivos y con el registro de Windows


Las operaciones de archivo son algo a lo que todo p r o gr a ma do r debe enfren tarse en un momento u otro. La clase S y s t e m . 1 0 contiene una cantidad ingente de mtodos par a leer v escribir en y desde archivos. Esta clase simplifica la E/S de archivos y su manipulacin y brinda un gran control de acceso a archiv os. De forma parecida a la E/S del pasado, el acceso al registro de Wi ndows siempre ha sido una tarea muy pesada. Esta tarea requera muchas llamadas al API que reducan el rendimiento de la aplicacin y solan obligar al p r o g r a ma do r a escri bir sus propias clases contenedoras par a estas operaciones. Con N E T todo esto cambio. En este captulo a prender a leer v escribir datos en y desde archivos. El capitulo estudia las operaciones de E/S que operan con texto normal y con datos binarios. Tambi n estudia al gunas operaciones de archivos tiles, como mover, renombr ar v eliminar archivos. Por ultimo, apr ender a a superv isar el sistema de archivos par a b us ca r cambios en archivos especficos y seguir recorriendo el registro de Wi ndows.

Cm o acceder a archivos
El acceso a archivos en N E T suele hacerse con objetos de secuencia. Sin embargo, algunas clases confan en los objetos de secuencia par a acceder a los

529

archivos. En este captulo exami naremos dos de estas clases para mejorar su conocimiento de la E/S de archivos.

Acceso binario
Las clases BinaryReader y BinaryWriter son compatibles con el a c ceso binario a archivos. Estas clases permiten el acceso a archivos binarios y las operaciones binarias hacia y desde secuencias. Como se usan secuencias, las clases pueden ser muy flexibles y no tienen que t r at ar con detalles, como la p o s i cin de la secuencia o el acceso a la misma. El siguiente ap art ado exami na la clase de acceso BinaryWriter.

BinaryWriter
La clase BinaryWriter permite escribir tipos de datos primitivos en se cuencias y con el uso de las subclases, se pueden reempl azar los mtodos de esta clase y cumpl ir con los requisitos de la codificacin nica de caracteres. Como esta clase usa una secuencia subyacente, hay que t rabaj ar con muy pocos mtodos y propiedades. La tabla 24.1 contiene las cinco propiedades y mtodos bsicos que mas usar para t rabajar con la clase BinaryWriter.
Tabla 24.1. Miembros bsicos de la clase BinaryWriter

Nom bre

T ipo

F u n cin

BaseStream Close

Propiedad Mtodo

Permite el acceso a la secuencia subya cente BinaryWriter Cierra la clase BinaryWriter y la se cuencia subyacente, eliminando todas las operaciones de escritura pendientes. Escribe todos los datos almacenados en el bfer en la secuencia subyacente y lue go limpia los bferes. Establece la posicin actual dentro de la secuencia en uso. Este mtodo sobrecargado escribe un va lor en la secuencia en uso. Actualmente admite 18 variaciones de tipos de datos.

Flush

Mtodo

Seek Write

Mtodo Mtodo

Para escribir datos en un archivo, antes hay que crear una secuencia de ar chi vos. Seguidamente se puede instanciar una nueva clase BinaryWriter. p a s n dola a la secuencia. Tras crear esta clase BinaryWriter. slo hay que llamar a su mtodo Write ( ) y pasarle los datos que se deben escribir, como se puede ver en el listado 2 4 . 1.

530

Listado 24.1. Cmo escribir datos en una secuencia de archivos mediante la clase B in aryW riter static void M a i n (s t r i n g [ ] args)

{
FileStream myFStream = new FileStream ("c :\\T es tF il e.dat " , F i l e M o d e .O p e nO rC re at e, F i l e A c c e s s .R e a d Wr it e) ; BinaryWriter binWrit = new BinaryWriter(myFStream) ; string t e s t S t r m g = "This is a test string."; b i n W n t .Write (t es tS t n n g ) ; b i nW rit.Cise ( ); myFS tream.Cise ( );

} Al a c a ba r con la clasc BinaryWriter. hay que as egurars e de cerrarla y de c e r r a r la secuenci a. Si no se ci er ra la cl ase B i n a r y W r i t e r o la clase FileStream. se puede producir una prdida de datos.

BinaryReader
La clase BinaryReader. al igual que la clase BinaryWriter. se basa en un objeto FileStream par a acceder a los archivos. P ar a comprender la clase BinaryReader. examine la apl icacin del listado 24.2. que lee la informacin del ttulo binario de un archivo de m a p a de bits A parti r de la i nformacin de este ttulo, se puede determinar el t amao horizontal y vertical del archivo de imagen, adems de su prof undidad de color en bits.
Listado 24.2. Aplicacin BitmapSize using using System; System.10; BitmapSize Classl void M a i n (s t r i n g [ ] args)

namespace

{
class

{
static

{
long bmpWidth = 0; long bmpHeight = 0; int bmpPlanes = 0; int bmpBitCount = 0; string [ ] cma = Envi ronment .G e t C o m m a n d L m e A r g s () ; f (c m a .G e t U p p e r B o u n d (0 ) >= 1)

(
FileStream myFStream = new F i l e S t r e a m (c m a [1],F i l e M o d e .O p e n , F i l e A c c e s s .R e a d ) ; BinaryReader binRead = new BinaryReader (myFStream) ; bi nR ea d . B a s e S t r e a m . P o s i t i o n = 0 x l 2 ; bmpWidth = b i n R e a d .Read ln t32 ( );

531

bmpHeight= b in Re ad .Readlnt32 ( ); bmpPlanes= binRead.Readlntl6() ; bmpBitCount = b i n R e a d .Readlnt16 ( ); Consol . W r i t e L m e ("[{ 0 } ] {l}x{2} {3}b i t " ,c m a [1] ,b m p W i d t h , b m p H e i g h t ,b m p B i t C o u n t ) ; b i n R e a d . C i s e (); myFSt r e am.Cise ( );

Lo primero que se debe hacer en esta aplicacin es declarar algunas variables par a que contengan la informacin que se lee desde el archivo de m ap a de bits y. a continuacin, hay que a lmac enar todos los argument os de lnea de c omandos en una matriz de cadenas. En el ant er ior ejemplo, se al mac enan los a rgume nt os de lnea de c omandos en una matriz de cadenas, porque uno de estos argument os determina que archivo debe procesarse. El elemento uno de la mat ri z de cadenas debe contener el nombre del archivo que debe procesarse. Tr as determinar si existe un ar gume nt o de lnea de c o m a n dos. se puede crear un objeto FileStream p as and o el nombre del archivo y el modo que quiere usar par a abrir el archivo, como se muest ra a continuacin:
FileStream myFStream = new FileStream( Fi 1cAcc e s s .Re a d ) ; c m a [1] , F il eM o d e .Open,

Al igual que la clase BinaryWriter. se crea el objeto B m a r y R e a d e r v se pasa al objeto FileStream que se quiere usar. En este punto, ya esta p r e pa rado para leer un archivo usando el modo binario. Tras exami nar el diseo del archivo de mapa de bits, sabe que la informacin que quiere obtener empieza en la posicin IX (posicin hexadecimal 12) del archivo. Al us ar el objeto de la clase Binar yPeader BaseS t r can. se puede a c ced er d i rec tamen te al objeto F i LeSt ream. A partir de aqu, establece la propiedad Position del objeto a 0 \ 12. que busca en el archiv o, a la posicin desde la que se quiere leer. C uando el puntero del archiv o esta en posicin, hay que leer dos valores lonq desde el archivo, seguidos por dos valores enteros. Un valor long necesita c u a tro bvtes. de modo que se usa el mtodo Readlnt 3 2 dos veces para recuperar los valores. A continuacin, se usa el mtodo Readlnt 16 para recuperar los dos archi vos enteros del archivo. Observe en la tabla 24.2 la lista de los mtodos mas usados en la clase BmaryReader. Una vez que se ha recuperado la i nformacin del archivo, slo queda mostrar los valores al macenados en la consola. Tras compi lar esta aplicacin, vaya a la ventana de consola y prubela con una imagen de m ap a de bits, como muest ra la figura 24 1.

532

T abla 24.2. Mtodos ms usados dentro de la clase BinaryReader

M todo

D escrip cin

Close PeekChar

Cierra el objeto Bi nar yR e ad e r y la secuencia base Lee el siguiente byte disponible de la secuencia pero no hace avanzar la posicin del byte o del carcter en el archivo Lee un valor booleano (True/False) de la secuen cia Lee un solo byte de la secuencia. Tambin existe un mtodo R ea dB y te s para especificar el nmero de bytes que se deben leer. Lee un solo valor char de la secuencia. Tambin existe un mtodo Re ad c ha r s para especificar el nmero de chars que se deben leer. Lee un valor entero (2 bytes) Lee un valor long (4 bytes) Lee un entero de ocho bytes con signo

ReadBoolean ReadByte

ReadChar

Readlnt16 Readln32 Readlnt64

c i C:\WINDOWS\System32\cmd.exe
C :\>bitmapsize c:\testl.bmp [c:\testl.bmp] 455x695 24-bit

JslPi X

Ld
Figura 24.1. Al usar BinaryReader, puede observar el tamao de la imagen de un archivo de mapa de bits

Cmo supervisar los cambios de archivo


La supervisin de los cambios de archivo con C# es cada vez mas fcil g r a cias al uso del objeto F i l e S y s t e m W a t c h e r . Este objeto permite observar un

533

archivo concreto, un grupo de archivos, un directorio o toda una unidad par a bu s ca r varios eventos, incluyendo los cambios de archivo, eliminaciones de a r chivo. creaciones de archivo y cambi os de n ombre de archivos. Se empieza usando el objeto FileSystemWatcher en uno de estos dos modos. Se puede cr ear un objeto FileSystemWatcher us and o cdigo y lue go creando mtodos par a cont rol ar los diferentes eventos, o se puede u sar el mtodo mas sencillo. El cua dr o de herrami ent as de la mt erfaz de desarrollo de Visual Studio N E T tambin contiene un objeto FileSystemWatcher que se puede insertar en el proyecto haciendo doble clic sobre ella. Las aplicaciones, como Microsoft Wo r d y Microsoft Excel, supervisan los archivos que se estn usando por si se producen cambios en ellos desde fuera. A continuacin a pa rec er la opcin de volver a abrir el archivo de modo que pueda obser var todos los cambios que se han hecho en l. Pa ra expl orar las caracter st i cas del objeto FileSystemWatcher se c onstruye una aplicacin que s uper vi sa todos los archivos de texto en la raz de la unidad C: y muest ra la informacin importante en la ventana de la aplicacin.

Cmo usar la supervisin de archivos


Para empezar esta aplicacin de ejemplo, abra una nueva aplicacin de Windows C#. Tras abrir la ventana del nuevo proyecto, agregue dos botones y un cuadro de lista. Tras agr egar los c omponentes a Forml, cambie los nombres de los botones a btnStart y btnStop. Cambi e las propiedades Text de estos botones a S t a r t y Stop, respectivamente. Ahora que los controles estn en su sitio, colquelos como se mues tra en la figura 24.2.

Figura 24.2. Arrastre y coloque controles en la interfaz File monitor como se muestra aqu

Debe ag reg ar otro objeto ms al provecto: FileSystemWatcher. Selec cione la ficha Com ponentes del cuadro de herramientas, como muest ra la fi gu ra 24.3. Haga doble clic en FileSystemWatcher par a agregar una instancia de este objeto al proyecto.

534

*. File Monitor - Microsoft Visual C# .NET [disear] - Forml.cs [DifefioJ*


rchivo Adicin Ver Proyecto (enerar Depurar Datgs Herramientas Ventana Ayyda

?
Cuadro de herramientas Datos Componentes Puntero ! FileSystemWatcher [^| EVentlog ^

f * tC 'fb u g
f tn

*
Explorador de soluciones - File ... ^

:
X

F o rm l.cs [D iseo]*

::i T
^

ps

J Solucin Tile Moniho, (1 ptovefh: i


:J' F ile M o n it o r

P^ferfnre:.
Ai-emblvInN ,

H ]A p t i . n o

^ 3 DirectoryEntry * ^ OirectorySearcher MessageQueue 1 __j PerformanceCounter 3 Process Mi) ServiceController ^ Q Timer ReportDocument

~ p!F o rm l.c s

Stop

Windows Forms Anillo del Portapapeles General Listo

Figura 24.3. La ficha C o m p on e n te s del cuadro de herramientas contiene el objeto FileSyst emWat che r

Sclcccionc el c om pon en te f ileSystemWatcherl situado i nm ed i at am en te debajo de Forml en el diseador de formularios. La propiedad EnableRaisingEvents activa el objeto y le permite empez ar a b us ca r eventos del sistema de archivos. C omo tiene los botones Start y Stop p ar a conseguirlo, debe a s e g u rarse de que el objeto no se activa cuando se ejecuta la aplicacin. Cambi e la propi edad EnableRaisingEvents a False. La propiedad Filter p er m i te asi gnar una m s c a r a de archivo o un archivo que se debe observar. Como queremos ver todos los archivos, escriba * . t>:t en la propiedad Filter. Por ultimo, necesita definir la carpet a en la que quiere supervisar archivos. Escriba C : \ en la propi edad P a t h par a as egurars e de que solo exami na los archivos que se encuentran en la raz de la unidad C Se puede supervisar toda la unidad as ignando a la propiedad IncludeSubdirectories el valor True pero es prob abl e que esto reduzca el rendimiento del sistema. Ha ga doble clic en el botn Start en Forml y aada el cdigo del listado 24.3 al co nt rol ador de eventos Click.
Listado 24.3. Evento clic del botn Start prvate void b tn Start_C1i c k (object sender, System.EventArgs = true; e)

{
f ileSystemWatcherl .E n a b l e R a i s m g E v e n t s b t n S t o p .Enabled = true; b t n S t a r t .Enabled = false;

535

El anterior cdigo asigna a la propiedad E n a b l e R a i s i n g E v e n t s el valor


T r u e . lo que activa el objeto F i l e S y s t e m W a t c . h e r . A continuacin desactive

el boton Start para que no se pueda volver a hacer clic en l y active el boton

Stop
A h o r a d e b e a g r e g a r a l g o de c o d i g o al b o t o n del boton Stop.
Listado 24.4. Evento clic del botn Stop p r iv a t .o y o ir i bt n'.top Cl ick objcct sender, = System.EventArgs false; ei

Stop p a r a d e s a c t i v a r

F i 1 e S y s t e m W a t c h e r . Agregue el codigo del listado 24.4 al evento C l i c ) :

(
f i 1c S y s t emWa t che r 1 .Enab eP.aisinqEvcnts b t n S t op .En a b i ed = fa 1se ; 3 1 .nS 1 a rt .En a b 1ed - true;
i

F i l c M / s t e m W a t c h e r ya esta operativo, pero debe agregar los controladores

de evento para c a pt ur a r todos los eventos de archivo. Regrese al editor de f o r m u larios haciendo doble clic en F o r m l en el Explorador de soluciones y hac ie n do clic en el objeto f i l e S y s t e m W a t c h e r 1. En la ventana Propiedades, haga clic en el icono Eventos de la ba r ra de tareas. Al hacer clic en los eventos que aparecen en la ventana, ap arecera el editor de codigo par a que pueda modifi car esos controladores de eventos. El listado 24.5 contiene el codigo que debe introducir en los cuatro eventos.
Listado 24.5. Controladores de eventos FileSystemWatcher prvate void f i 1 eSyst emWatcher 1 De 1eted (obj ect S ys t em .IO .F i 1eS y . s t emEvent Ar gs e ) sender,

I
1 istBoxJ .1 1 e m s .Add ( "[" + e .ame + "] Deleted" );

}
prvate void fi 1eSystemWatcher 1 Renamed(object 5y s t e m . I O .PenamedEventArgs e ) 1 i s t R o x 1 .I t e m s . A d d ( "[" e .Mame i; + e.OldName + "] sender,

Renamed

to

" +

}
prvate void fi]eS ys temWatcher1 C h a n g e d (object Syst e m .TO .F i i .eS ys t emEventArgs e ) sender,

{
1 ist Ro x1. I t e m s . A d d ( "[" + e .ame + "] C h an g ed ); sender,

}
prvate void f 1 1eS ys temWatcher1 Created(object S ys t em .TO .F i 1e S ys t :emEvent Ar gs e )

{
1 st.Box 1 .Items .Add ( " (" + e .ame + " ] C re a te d1 ') ;

536

Estos controladores de eventos son bastante simples: solamente muestran un mensaje en el cuadro de lista cuando se produce una operacin. Antes de c o m p ro bar esta aplicacin, es importante tener en cuenta algunas cosas. C omo puede ver en cada una de estas funciones, los eventos Chanqcd. Created y Deleted muest ran los mismos datos; por tanto, tienen la misma firma. Lo extrao aqui es el evento Re ame d . Como tres de los cuatro ev entos pasan los mismos datos al procedimiento del evento, es posible usar un cont rol ador de eventos que controle estos tres eventos, pero seguir necesitando que un cont rol ador distinto se haga cargo del evento Renamed. Pulse F5 para ejecutar el p rog rama y empezar a exami narl o como se indica a continuacin: 1. Cuando el pr ogr ama se abra, haga clic en el boton S t a r t . La aplicacin esta superv isando la raiz de la unidad C . buscando cambios en los ar chi vos de texto. Abra el Explorador de W indows. Ha ga clic con el boton derecho en la ventana del exp lo ra do r v seleccione Nuevo>Docum ento de texto para cr ear un nuevo documento. En el nuevo documento, o bs er var una entrada en el cuadro de lista de su aplicacin File Monitor que ndica que se ha creado un archivo. Abra este nuevo archivo de texto, agregele algo de texto y gurdelo. De nuevo, vera entradas en la ventana de registro de la aplicacin. Ahora intente r enombr ar el archivo v borrarlo a continuacin. Los resulta dos deberan ser similares a los que aparecen en la figura 24.4.
O F ile M o n ito r
[n e w [n e w t e t [n e w text [n e w text docum ent docum ent d o cu m e n t docum ent txtj tyt] txt] txt] C reated L hanged |_hanged R e n a m e d to briarv: I

2.

3.

4.

-l lx l

[b n a n : t - i] D e le te d

Stop 1

1 1

Figura 24.4. Su aplicacin File monitor muestra la actividad del archivo en tiempo real

Debe ser consciente de que el evento Changed puede desencadenarse v a rias veces, porque FileSystemWatcher est exami nando varias caracter s ticas del archivo. Si el t ama o del archivo cambia, se desencadena el evento

537

Changed. Si la fecha de modificacin y la m ar ca de hora del archivo cambian, el evento Changed se d esencadena de nuevo y as sucesivamente. No se d e s
anime si un evento se desencadena ms de una vez. Por lo general no es un p r o b l e m a de la a p l i c a c i n sino u n a g a r a n t a de que se ha e s t a b l e c i d o el NotifyFilters correcto.

Cmo codificar FileSystemWatcher


Puede agregar un FileSystemWatcher a su proyecto de C# sin usar el cuadro de herramientas de Visual Studio. Para conseguirlo, agregue una d e cl ar a cin al objeto situado i nmediatamente debajo de la declaracin de la clase, como muest ra el listado 24.6.
Listado 24.6. Cmo agregar una instancia Fi le Sy stemWatcher a declaraciones de clase public class Forml : System.Windows.F o r m s .Form

{
prvate FileSys t emWat che r M y F i 1eWat che r = new F i 1e S ys t emWat che r ( );

C omo est cr eando el control en tiempo de ejecucin, no puede ir a la ventana

Propiedades y asi gnar valores a las diferentes propiedades segn sea necesario. En cambio, estas tareas se controlan desde dentro del evento Click del botn
Start. Tras establecer las propiedades, como en el anterior ejemplo del listado 24.6. debe crear controladores de eventos y dirigirlos a las funciones adecuadas. El listado 24.7 mues tra el listado actual izado del evento Click del botn Start.
Listado 24.7. Cmo crear declaraciones de controla dores de eventos en el evento click del botn Start prvate void btnStart Click(object sender, System.EventArgs e)

{
M y F i 1eW at c h e r .Path = "c:\\"; M y F i l e W a t c h e r .Filter = " * .t x t " ; M y F i 1eW a t c h e r .IncludeSubdirectories = false; M y F i l e W a t c h e r .E n a b l e R a i s m g E v e n t s = true; t his .MyFileWatcher.Renamed += new System.IO.RenamedEventHandler ( t h i s .M y F i 1eWatcher Renamed ) ; this.MyFileWatcher.Changed += new System.10.Fi le Sy stemEventHandler( t h i s .M y F i 1eWatcher Changed ) ; b t n S t a r t .Enabled = false; btnStop.Enabled = true;

} A continuacin, agregue codigo al botn Stop y cree controladores de eventos para Fi leSy.s temWatcher . Los nombres de funcin par a estos controladores de eventos deben coincidir con la declaraci n que coloc en el evento click de

538

los botones S t a r t . El listado 2 4 . K contiene el evento Stop Click y los controladores de evento p ar a los eventos Changed y Renamed.
Listado 24.8. Cmo crear controladores de evento para el objeto FileSystemWatcher prvate void btnStop Click(object sender, System.EventArgs e)

{
M y F i l e W a t c h e r .EnableRaisingEvents b t n S t o p .Enabled = false; b t n S t a r t .Enabled = true; = false;

}
prvate void MyFileWatcher Changed(ob]ect Syste m. 10.FileSystemEventArgs e) sender,

{
1 ist B o x ' 1.Items .Add ("[" + e.FullPath + "] Changed");

}
prvate void MyFileWatcher Renamed (ob]ect System.10.RenamedEventArgs e) sender,

{
l is tB ox 1.It e m s . A d d (" [" + e.OldName e . a m e ); + "] renamed to " +

Cmo manipular archivos


La mani pul aci n de archivos es un acceso a archivos que solo mani pul a el archiv o y 110 los contenidos. La mani pul aci n de archivos puede incluir la copia, borrado y traslado del archivo. Precisamente. N E T proporciona una clase l lama da Filelnfo incluida en el espacio de nombres System. 10 para estas ope raciones. Esta seccin describe algunos de los mtodos de mani pul aci n y su modo de empleo.

Cmo copiar archivos


La clase Filelnfo contiene, entre otras cosas, un mtodo par a copiar a r chivos. Este mtodo. CopyTo. esta s obrecargado y tiene dos variantes. La pri mera simplemente recibe el nombre del archivo de destino. Si ya existe un archivo con ese nombre, el mtodo termina. La segunda variante recibe un nombre de archivo de destino y un valor booleano que indica si los archivos se pueden o no sobrescribir. Para most rar el mtodo CopyTo. esta seccin le mues tra como construir una aplicacin de consola p ar a copiar archivos. Como Wi ndows ya tiene un comando de copia, asigne al nuevo mtodo el nombre cp. que es el comando de copia p ar a UNIX. El listado 24.9 muest ra la implementacin c o m pleta del comando Copy en C#. Cree una nueva aplicacin de consola de C# l lamada cp e i nt roduzca el siguiente cdigo.

539

Listado 24.9. Implementacion C# del c om ando File Copy using System; using System.10; namespace cp

{
c 1ass Class 1 void Main (string[ ] a rg s )

{
static

(
string [] cl.a = Env l ronment .Ge t C o m m a n d L m e A r gs ( ) ; l f !c 1 .a .Ge tUppe r Bound (U ) -= 2)

I
F ] 1e I n f o fi new Fl 1 e I n f o ( c 1 a [ 1 ] ) ;

f i .CopyTo (cl a [2] ,truej ; Console.Wri t e L m e ("Copied

" +

fi .Length

^ " bytes."};

I
e 1s e Console.WriteLine f i ie " i ; ("Usage: cp < input f i i e > < output

E s t e c o d i g o u s a el m t o d o G e t C o m m a n d L i n e A r g s de la c l a s e Environment para recuper ar los argument os de lnea de comandos que se pasan a la aplicacin. Si el numero de argument os no es igual a 2. simplemente muest ra un mensaje de uso. como se puede ver en la parte inferior del listado 24.9 y sale. En caso contrario, los argument os de la lnea de comandos se almacenan en la matriz de cadenas el a para ser usados ms tarde. Al us ar la clase Filelnfo. debe crear en p rimer l ugar un objeto Filelnfo y pasarle el nombre del archivo con el que est trabajando. Al usar esta ap li ca cin. el ar gument o de la pri mera lnea de comandos es el nombre del archivo fuente. C omo esto se al macena en el elemento 1 de la matriz de cadenas, si mple mente pselo al objeto Filelnfo. Para copiar un archivo usando esta clase, simplemente llame a su mtodo CopyTo j unt o con el nombre del archivo de destino (que est en el elemento 2 de la matriz de cadenas) y un valor booleano que indique si se debe s obrescribir un archivo con el mismo nombre. Abra el intrprete de comandos p ar a pr ob a r este pr og rama despus de compilarlo, como muest ra la figura 24.5. ( orno puede ver. agreg algo inesperado al programa. Una vez que el mtodo CopyTo se haya completado, se muest ra un mensaje en la consola que indica que la operacin ha concluido y se muest ra el nmero de bytes que se han copiado, gracias a la propiedad Length de la clase Filelnfo.

Cmo eliminar archivos


El proceso de eliminacin de archivos con la clase Filelnfo resulta tan sencillo como l lamar al mtodo Delete ( ) . Si el archivo que quiere eliminar

540

tiene un valor en su atributo R e a d - O n l y . obt endr una excepcin. El ejemplo del listado 24. 10 crea una i mplementacion de C# del c omando De l e t e del a r chivo. Despus de b or r ar el archivo, la utilidad mue st ra el nombre del archivo eliminado v sus atributos.
c\ C:\WINDOWS\System32\cmd.exe C:\>cp xp.bnp xpcopy.bmp Copied 950814 hyt.es. C:\>

i l

^ISJ

Figura 24.5. C opyTo permite copiar un archivo y mostrar inform acin adicional

Cree un nuevo proyect o de aplicacin de consola de C# llamad rm e i nt roduz ca el cdigo del listado 24.10.
Listado 24.10. Uso de la clase Fileinf o para eliminar archivos fcilmente using System; using System.10; namespace rm

{
class Classl void M a i n (str i n g [] args)

{
static

{
string [ ] cla = E nv ir o n m e n t .Ge tC om ma n d L i n e A r g s (); if (c l a .G e t U p p e r B o u n d (0) == 1)

{
Filelnfo fi = new Filelnfo (cla [1] ) ; fi.Delete ( ); Console.WriteLine("File : " + cla [1] ) ; Co nsole.WriteLine("Attributes: " + fi .Attributes.ToStringO ) ; Cons ole.WriteLine ("File Deleted. . .") ;

}
else Console.WriteLine ("Usage: rm <filename>") ;

541

C omo en los anteriores ejemplos, est al mac en an do los argument os de lnea de comandos dentro de una matriz de cadenas. Si esa matriz no contiene el n m e ro correcto de elementos, solamente se mos tr ar un mensaje de uso y finalizar.

. TRUCO?

Delet { d* 1 tese

puede dinliBar directdHOSj adems de archivos.

Tra s invocar al mtodo Dele te ( ) de la elase Filelnfo, puede mos trar al usuario el nombre del archivo y sus atributos, indicando que ha sido eliminado. Mediante la propiedad Attributes. puede det erminar de un modo seguro, antes de eliminar el archivo, si tiene asignado su atributo Read-Only. En ese caso, puede avisar al usuario y/o eliminar el atributo Read-Only us ando la propiedad Attributes junto con el en umer ado r FileAttributes. Una vez que su p r o gr a ma haya sido compilado, a b r a un intrprete de c o m a n dos \ prubelo. Simplemente escri ba rm seguido del nombre del archivo que quiere eliminar. Los resultados deberan ser similares a los de la figura 24.6.
C A C:\WINDOWS\System32\cmd.exe
C:\>rn TempFile.dat File : TempFile.dat Attributes: Archive File De l e t e d . .. C:\>
X

Figura 24.6. El mtodo DeleteQ de la clase Filelnfo muestra los atributos del archivo elim inado

Cmo trasladar archivos


El mtodo MoveTo ( ) de la clase Filelnfo en realidad enc aps ul a dos m todos diferentes: CopyTo () y Delete (). Despus de copiar un archivo en el nombre de archivo o directorio adecuado. MoveTo ( ) simplement e elimina el archivo de forma muy par eci da a cmo lo hace el mtodo Delete ( ) . El siguiente ejemplo de aplicacin admite dos a rgume nt os de lnea de c o m a n dos: Source Filename y Destination Filename. Tras trasladar el archivo, el pr og r am a mues tra cuando se cre en realidad el archivo y a dnde se

542

traslad. Ni nguna de estas indicaciones tiene un uso practico, excepto p ar a m o s t rar cmo se pueden obtener algunos atributos, como la hora en que se cre el archivo, mediante la propi edad CreationTime. Cree una nueva aplicacin de consola CU y llame al provecto mv. como el comando de UNIX. El listado 24.1 1 mues tra por completo la aplicacin.
Listado 24.11. Im plem entacin de File Move using System; using System.10; namespace mv

f
class Cas si void Main (s t n n g [] args)

{
static

{
stnng [ ] ca = Envi r onment .GetCommandLineAr gs ( ); if (c a .G e t U p p e r B o u n d (O ) == 2)

{
Filelnfo fi = new FileInfo(cla[l]); f i . M o v e T o (c a [2]); Consol . W r i t e L m e ("File Created : " + f i . C r e a t i o n T i m e . T o S t r i n g ()); Consol. W r i t e L m e ("Moved to : + ca [2] ) ;

}
e1se C o n s o l .W n t e L i n e < d e s t m a t i o n file>") ; ("Usage: mv <source file>

} } } La figura 24.7 mues tra el resultado de la utilidad File Move.

Figura 24.7. Mueva archivos con el mtodo MoveTo de la clase Fileinf o

543

Obser ve que en este ejemplo, el nombre del archivo de destino puede ser un nombre de archivo o un nombre de directorio. Si se especifica un nombre de directorio, el archivo se traslada. Si hay un nombre de archivo, el archivo es renombrado y/o trasladado. El mtodo M ove To ( ) bsicamente incorpora las funciones de copia y ren omb rad o en un mtodo.

Cmo acceder al registro


El acceso al Registro era una tarea bastante pesada en el API de Windows. C# propor ci ona al gunos objetos de clase que permiten leer y escribir en y desde el registro fcilmente. El uso del registro tiene varias ventajas sobre los antiguos mtodos, como archiv os INI con formato texto. Como el registro est indizado. la bsqueda de claves se realiza rpidamente. El registro es un "documento" es tru c turado. lo que permite que la informacin estructurada, como una base de datos, slo tenga que no mb ra r un tipo.

Cmo leer claves del registro


El acceso a la funcionalidad del registro se incluye en el espacio de nombres Mi c r o s o f t .Win32. as que tenemos que incluir este espacio de nombres en todos los proyectos introduciendo la siguiente lnea en la parte superior del ar chi vo de cdigo fuente:
using M i cr os of t. Wi n3 2;

Para leer una clave del registro use el objeto Regis tryKey. Para empezar a estudiar este objeto, examine el listado 24.12. una aplicacin que recupera dos fragmentos de informacin del registro.
Listado 24.12. Recupera el tipo de CPU y su velocidad del Registro us m g using S ys t em; Microsoft . W m 3 2 ; CPUInfo

namespace

{
c 1 a s s C 1a s s 1

{
static voicl Main (string[] args)

{
RegistryKey RegKey = Regs t r y .L o c a l M a c h m e ; RegKey = R e g K e y .O p e n S u b K e y ( "H A R D W A R E W D E S C R I P T I O N \ \ S y s t e m \ \ C e n t r a 1Processor\\0 " ) ; Ob]ect cpuSpeed = R e g K e y .G e t V a l u e ("-MH z"); Ob]ect cpuType = R e g K e y .G e t V a l u e ("VendorIdentifer " ) ; C ons ol e .Wr 1 1 e L m e ("You have a {0} running at {1}

544

M H z .",cpuType,cpuSpeed) ;

Al instanciar una instancia de RegistryKey. hace que su valor sea igual a un m iem br o de la clase Registry. El a nt er i or ej empl o a s i gn a al objeto RegistryKey el valor del c a mpo Registry .LocaIMachine, que permite el acceso a la clave base HKEY LOCAL MACHINE. La tabla 24.3 tiene una lista de todos los ca mpos pblicos de la clase de registro. T r a s e s t a b l e c e r el o b j e t o R e g i s t r y K e y . i n v o q u e a su m t o d o OpenSubKey ( ) y proporcione la clave que quiere abrir. En este caso conc re to. de be d i r i g i r s e a la cl av e H K E Y L O C A L M A C H IN E \ H A R D W A R E \ DESCRIPTION\System\Central\Processor\C)\ y leer dos valores de esa clave. Teng a en cuenta que debe incluir dos bar ras invertidas en la cadena p a r a que no sean confundidas con un signo de escape. T ra s abrir la siibclave. use las siguientes dos lneas de cdigo p a r a recuperar los valores "~MHz" v "VendorIdentif ier" de esa subclave:
Object Object cpuSpeed cpuType R e g K e y . G e t V a l u e ("-MHz "); R e g K e y .GetValue ("VendorIdent ifier") ;

Aho ra tiene los valores al mac enados en las v ariables adecuadas, de modo que puede mo st rar la informacin en la ventana. Exami ne el p ro g ra ma desde una v entana de consola, como mues tra la figura 24.8.
Tabla 24.3. C am pos pblicos de la clase Registry

Cam po

D escrip cin

ClassesRoot

ClassesRoot define los tipos de documentos y las propiedades asociadas a esos tipos. Este cam po empieza en la clave h k e y c l a s s e s r o o t del registro de Windows. CurrentConfig contiene informacin relativa al hardware de su equipo. Este campo empieza en la clave h k e y _ c u r r e n t _ c o n f i g del registro de Windows. Aqu se almacenan todas las preferencias del ac tual usuario. Este campo empieza en la clave h k e y c u r r e n t u s e r del registro de Windows. DynData. LocalMachine contiene informacin para el equi po. Este campo empieza en la clave h k e y l o c a l m a c h i n e del registro de Windows.

CurrentConfig

CurrentUser

DynData LocalMachine

545

Campo

Descripcin

PerformanceData

La clave base almacena informacin relativa al rendi miento de los diferentes componentes de software. Este campo empieza en la clave h k e y p e r f o r m a n ce d a t a del Registro de Windows. Esta clave base contiene informacin para la confi guracin de usuario por defecto. Este campo empie za en la clave h k e y u s e r s del registro de Windows.

Users

c\ C:\WINDOWS\System32\cmd.exe C:\>cpuinfo Vou hau.e a fluthent icAMD running at 1396 MHz. C:\>_

^jnj _x

Figura 24.8. La clase p.egistryKey simplifica la lectura de la im portante inform acin del registro

Si se esta trabaj ando en equipos con varios procesadores puede obtener una lista de todos los procesadores enumerando la clave Cent ralProcessor. Hay una subclave en CentralProcessor para cada CPU del equipo.

Cmo escribir claves de registro


Cr ea r y escribir claves en el Registro tambin se consigue us ando el objeto

RegistryKey. Varios mtodos de la clase RegistryKey son tiles para


escribir claves. La tabla 24.4 describe la funcin de algunos de los miembros mas importantes.

ADVERTENCIA: Escribir valores puede ser peligroso y puede hacer que su sistema no responda si no se tiene suficiente cuidado. Compruebe dos veces todo el cdigo antes de probar cualquier aplicacin que escriba valo res en el Registro.

546

Tabla 24.4. Miembros co m u n es de RegistryKey

Nombre
SubKeyCount ValueCount Close

Tipo
Propiedad Propiedad Mtodo

Descripcin
Esta propiedad recupera un recuento de las subclaves de la clave actual. Esta propiedad recupera un recuento del nmero de valores de la clave actual. Este mtodo cierra la clave actual. Si se han realizado cambios en la clave, los cambios se guardan en el disco. Este mtodo crea una nueva subclave o abre la subclave si ya existe. Este mtodo elimina una subclave. Este mtodo est sobrecargado y contiene un parmetro booleano que permite que se inicie una excepcin si no se puede en contrar la clave. Este mtodo elimina una clave y todas las subclaves secundarias de manera re currente. Este mtodo elimina un valor de una cla ve. Este mtodo est sobrecargado y con tiene un parmetro booleano que permite que se inicie una excepcin si no se pue de encontrar el valor. Este mtodo devuelve una matriz de ca denas que contiene todos los nombres de las subclaves. Este mtodo devuelve un valor para una clave especfica. Este mtodo est so brecargado y contiene un parmetro que admite un valor por defecto. Si no se pue de encontrar el valor para la clave, se devuelve el valor por defecto que se es pecific. Este mtodo devuelve una matriz de ca denas que contiene todos los valores para la clave especificada. Este mtodo abre una subclave para un proceso (acceso de lectura y escritura). Este mtodo asigna un valor a una clave. Para asignar el valor por defecto a una clave, asigne el parmetro s u b K e y a una cadena vaca.

CreateSubKey DeleteSubKey

Mtodo Mtodo

DeleteSubKeyTree

Mtodo

DeleteValue

Mtodo

GetSubKeyNames

Mtodo

GetValue

Mtodo

GetValueNames

Mtodo

OpenSubKey SetValue

Mtodo Mtodo

547

El listado 24.13 muest ra una sencilla aplicacin que escribe dos valores en el Registro y a continuacin lee esos valores p a r a mostrarlos.
Listado 24.13. C m o escribir t e x t o y un v a l o r D W o r d en el R e g i s t r o
usi ng usmg System; M i c r o s o f t . W in 3 2 ; WriteRegValues C 1ass 1 void M ain

namespace

{
class

{
s ta t ic

( st r ing [] arg.s)
= R e g i s t r y .C u r r e n t U s e r ;

{
RegistryKey R egK eyWrite

RegKeyWrite = RegKeyWrite.CreateSubKey ("Software\\CSHARP\\WriteRegist ryVa le") ;


R e g K e y W r i t e . S e t V a l u e ("Success", "TRUE") ;

RegKeyWrite.SetValue("AttemptNumber",1);
RegKeyWrite.Cise ( ); RegistryKey RegKeyRead = R e g i s t r y .C u r r e n t U s e r ;

RegKeyRead - RegKeyRead.OpenSubKey ("Software\\C SHARP\\WriteRegist ryVale" );


Ob je c t r e g S u c c e s s f u l = R e g K e y R e a d .G e t V a l e ("S u c c e s s "); Ob ject r e g A t t e m p t N u m b e r = R e g K e y P e a d . G e t V a l u e (" A t t e m p t N u m b e r " ); R e g K e y R e a d . C o s e (); ( ( s t n n g ) r e g S u c c e s s f u l == "TRUE") C o n s o l . W r i t e L m e ("Succeeded on at t empt {0} ", regAt t e m p t N u m b e r ) ; e 1s e C o n s o l . W r i t e L i n e ( " F a i l e d ! "); if

} } } Tras crear un objeto R e g i s t r y K e y . puede crear una nueva subclave con el m t o do C r e a t e S u b K e y () . Asegrese de emplear dos barras invertidas al usar este mtodo p ar a que el compi lador no confunda los caracteres con una secuencia de escape. En este ejemplo, se crea una nueva clave bajo HKEY C U R R E N T USER. A l m a c e n e los v a l or e s en la s u b c l a v e \ S o f t w a r e \ C S H A R P \ W r i t e Reg s tr yV al u e . Una vez que la nueva clave est en su sitio, use el mtodo S e t V a l u e ( ) par a especificar el nombre del valor y el valor actual. Este ej em p l o a l m a c e n a t e x t o en el v a l o r S u c c e s s y un D W o r d en el v a l o r A t t e m p t N u m b e r . Una vez asignados los valores, es aconsejable cerrar la clave por si se produce un corte de luz o algn fallo similar. En este punto, se han producido cambios en el registro. Si abre la aplicacin R e g E d i t y se dirige a la clave adecuada, debera ver los valores most rados en la figura 24.9.

548

' Editor del Registro


A rch iv o + + + + + + Edicin Ver F a v o rito s Ayuda

- ! ! X|

_ _j ahead _ _ | B a b y lo n _ _ | B a ttle .n e t _ _ | B o rla n d _ ] _J _ | _J BST CDCES C la s s e s C SH AR P

N o m b re 5 ] ( P r e d e te r m in a d o ) S jJ ]A tte m p tN u m b e r

T ip o PEG s ; R E G J 'W P .D R E 'j _S ;

D a to s ( v a lo r n o e s ta b le c id o ) O - 0 0 0 0 0 0 0 1 (1 ) TPI IE

J
j

'

^ ^ ^ ^ ^ ^ I W r it e R e g is t r y V a lu e + + + + _ _ | L y b e r L in k _ | _ | _ | C ydoor C y d o o r S e rv ic e s ['iv X N e tv v o rk s

_ _ | D v d 2 A v i g u iV j .. ...............

zl ll

2J

Mi P C \H K E Y _C U R R E N T _ U S E R \S o l:tw a re \C S H A R P \W rite R e g is try V a lu e

Figura 24.9. R e g E d i t i n di ca q u e s e h a n g u a r d a d o s u s v a l o r e s

C omo en el ejemplo anterior, crea un nuevo objeto R e g i s t r y K e y y lee de nuevo los valores. Si el valor de Success es realmente I 1 ru. se muestra la informacin en la pantalla, como se muest ra en la figura 24.10.
o\ C:\WINDOWS\System32\cmd.exe
C:\>ui*itei'egualues .exe Succeeded on attempt I t 1

^ Jn J

z i
Figura 24.10. L a s c l a v e s q u e s e l een d e la c o n s o l a s e m u e s t r a n e n la c o n s o l a

Esta aplicacin muest ra una sencilla tcnica par a escribir valores en el regis tro. Este mtodo ha demost rado ser til par a controlar la configuracin de los progr amas, g u ar d ar la ltima posicion y t amao de la mterfaz de las aplicaciones y acciones similares. Las posibilidades son ilimitadas.

Cmo enumerar claves del registro


La enumeracin de claves de Registro es muy pareci da a la utilidad Buscar archivo de Windows: permite b us car en el registro desde cualquiera de sus puntos

549

y r ecuper ar todas las subclaves y valores debajo de ese punt o inicial. A c tu a lm e n te no hay ningn mtodo en N E T p ar a enumer ar las claves de registro. Deber crear sus propias funciones si las necesita. El conocimiento de la est ructura de las claves que se desean e nu mer ar hace que la t area resulte mucho ms sencillo, va que puede u sar un simple bucle. Si no se conoce la est ructur a de las entradas del registro, necesitar crear una funcin que pueda llamar y p as ar la clave ini cial cada vez que es invocada. El listado 24. 14 es un ejemplo de enumer aci n de claves de registro. Este ejemplo inspecciona el registro en b us ca de una lista de todo el software que tiene instalado en su equipo. Este p r o g r am a enumer a cualquier aplicacin que a parece en la seccin Agregar o quitar program as del Panel de control.
Listado 24.14. C m o enumerar claves de Registro using using System; Microsoft.W in 3 2 ; Installed Classl void M a i n (s t r i n g [ ] args)

namespace

{
class

{
static

{
RegstryKey myRegKey=Regist r y .Loea lM ac hi ne ; m y R e g K e y = m y R e g K e y .OpenSubKey ("SOFTWARE\\Micros oft\\Windows\\CurrentVersion\\Uninstall") ; String [ ] subkeyNames = m y R e g K e y .GetSubKeyNames ( ); foreach (String s in subkeyNames)

{
RegistryKey UninstallKey=Registry.LocalMachine; U n i n s t a l l K e y = U n m s t a l l K e y . OpenSubKey ("SOFTWARE\\Mi c ros of t \ \ Windows\\CurrentVersion\\Uninstall\\"

s) ;
try

{
Ob]ect o V a 1ue=Uninsta 11K e y .GetVa le ("D i s p 1a y N a m e ") ; Consol . W n t e L m e (oValue . T o S t r m g ( ) );

)
catch ( NulIRe f e renceExcept ion)

{ }

Tras crear un objeto RegistryKey. abra la subclavc Uninstall. que contiene una lista de todos los p r o g r am as instalados. A par ti r de aqu, use GetSubKeyNames, que devuelve una matriz de cadenas de todas las subclaves.

550

Ahora que tiene una lista de subclavcs. use el oper ador foreach para recorrer todos los elementos de la matriz de cadenas de subclave. Al recorrer cada clave, se bus ca un valor llamado DisplayName. Este v a lor es el nombre que se mues tra en la seccin A gregar o quitar program as del Panel de control. Recuerde que no todas las claves tendrn este valor. Por tanto, debe e nc a ps ul ar el mtodo GetValue con una instruccin try . .cat ch par a c a p t ur a r todas las posibles excepciones. C uand o se encuent ra un valor DisplayName. se recupera el valor y se muest ra en la ventana. A c ont inua cin. la instruccin foreach pas a a la siguiente clave de registro de la matriz de cadenas. Pulse F5 para p robar la aplicacin. Probablemente vera una larga lista de aplicaciones despl azndose a medida que el pr og r am a inspecciona el registro (vase la figura 24.1 1). Una cosa que no se intenta en este p ro gr am a es ordenar las aplicaciones alfabticamente. Los elementos del registro no se al macenan as. pero para sol u cionar esto, puede simplemente al mac enar los resultados en una matriz de c ad e nas y llamar al mtodo Sort para ordenar el resultado de la manera deseada.

Figura 24.11. Cmo inspeccionar todas las aplicaciones instaladas con un enumerador de Registro

Resumen
N E T Framevvork ha reducido enormemente la cantidad de cdigo y tiempo necesario par a t rat ar efectivamente con archivos y con el registro de Windows. Entre los muchos beneficios de N E T Framevvork. ahora tiene acceso a c o m p o nentes como FileSystemWat cher que permite exami nar un sistema de ar chi vos para b us car cambios realizados en cualquier archivo. Sin embargo, debe tener

551

cuidado al escribir aplicaciones que traten con el registro de Wi ndows, porque si elimina por error claves de registro puede hacer que su sistema se vuelva i nest a ble o incluso que deje de funcionar.

552

Wn Cmo acceder a secuencias de datos


N E T F ramework tiene clases que propor ci onan un gran nivel de compat ibi li dad par a la lectura y escritura de datos. Tradicionalmente. los lenguajes han proporci onado compatibilidad integrada p ar a la lectura y escritura de archivos de disco y han confiado en las interfaces de progr amaci n de los sistemas operativos par a la lectura y escritura de otros tipos de secuencias de datos, como conexiones de red o archivos de memoria. N E T Framework unifica la E/S de datos al p r o po r cionar un conjunto de clases comn que admite lecturas y escrituras de datos sin importar el sistema de almacenami ent o s ubyacente usado par a propor ci onar el acceso a los datos. Todas estas clase pueden usarse desde el codigo C'#. En este captulo aprender a usar secuencias. Aprender a usar lectores y escritores para leer y escribir datos en una secuencia y a realizar operaciones de archiv o en segundo plano.

Jerarqua de clases de E/S de datos


La figura 25.1 muest ra la j erarqu a de clases para las clases bsicas NET F ramework que se emplean al t raba jar con E/S de datos. Las clases se agr upan en una de estas tres categoras: secuencias, escritores y lectores.

555

O b je c t

BinaryReader

MarshalByRefObject

BinaryW riter

File

Directory

Path

Figura 25.1. Jerarqua de clases de E/S de datos

Cmo usar secuencias


Las clases de secuencia propor ci onan un mecani smo para hacer referencia a un contenedor de datos. Las clases de secuencia compar ten una clase base comn l lamada S t r e a m . que esta definida en un espacio de nombres N E T Framework llamado S y s t e m . I O .

556

La clase base Stream contiene propi edades y mtodos que permiten a los m o c a do r es t ra ba j ar con la secuencia de datos. N E T F ramework dispone de varias clases que se derivan de la clase base Stream. Ca da clase proporciona una implementacin especfica de una secuencia de datos us ad a par a un entorno particular. La clase FileStream. por ejemplo, p ropor ci ona una implementacin que permite a los invocadores t rab aj ar con secuencias de datos vinculadas a un a rch i vo de disco. Del mismo modo, la clase Networ kStream proporciona una implementacin que permite a los mvocadores t raba jar con secuencias de datos a las que se accede mediante una red de comunicaciones.

Cmo usar escritores


Las secuencias admiten el acceso de datos en el nivel de byte. Incluyen m todos llamados R e a d ( ) y W r i t e ( ) . que t rabajan con una matriz de bytcs que se procesan durante la llamada. Sin embargo, t raba jar a nivel de byte puede no ser lo mejor par a una aplicacin. Suponga, por ejemplo, que una aplicacin debe escribir una serie de nmeros enteros en una secuencia. Como los nmeros ente ros en la i mplementacin de 32 bits tienen un t amao de cuatr o bytes. el cdigo C# necesitar convertir cada nmero entero en una cadena de cuatro bytes que pueda ser us ada en una l lamada a la implementacin de W r i t e ( ) de la s ec uen cia. N E T F ramework incluye clases de escritor que permiten escribir varios tipos de datos de nivel superior en una secuencia. Un escritor puede admi tir muchas sobre carga s de un mtodo Write (). Por ejemplo, un escritor puede ac ept ar datos como int. long o double. Las implement aci ones de la clase writer convierten los tipos de datos en una serie de bytes y pasan esa secuencia de bytes convertidos a un objeto Stream. Este diseo de clase libera al cdigo de tener que t ra ba j ar con secuencias de nivel de byte. El cdigo de la aplicacin de C# puede simplemente indicar, por ejemplo, "escribe este dato long sin signo en la secuencia" y permitir que la clase writer realice el t rabajo necesario par a obtener el valor al macenado en la secuencia como una serie de bytes.

Cmo usar lectores


Las clases de lectores complementan a las clase de escritores C omo las clases de escritores, las clases de lectores admiten la lectura de tipos de datos que va mas alia de la simple matriz de bytes admitida por las clases de secuencia. En N E T Framework. hay una clase de lector par a compl ement ar a cada clase de escritor. Las clases de lector p roporci onan varias s obrecargas de un mtodo Read ( ) que permite que el cdigo de una aplicacin lea v arios tipos de datos, como cadenas, enteros, long. etc.

557

Cmo trabajar con secuencias


Las secuencias admiten dos mtodos de E/S: E/S sincrnica, en la que las llamadas que realizan la secuencia de E/S no regresan al invocador hasta que la operacin de E/S solicitada se ha c o m pletado. E/S asincrnica, en la que las llamadas que realizan la secuencia de E/S regresan al invocador antes de que la operacin de E/S solicitada se haya compl et ado y. posteriormente, informa al invocador de la conclusin de la operacin.

E/S sincrnica
El listado 25.1 muestra una E/S de secuencia sincrnica. Crea un archivo y escribe 256 bvtes de datos binarios en l. A continuacin, lee los 256 bytes del archivo y se as egura de que la lectura de datos coincida con los datos escritos.
Listado 25.1. E/S de archivos sincrnica using using class System; System.10; FileTestClass FileStream BinaryFile; byte [ ] ByteArray; Fi le T e s t C l a s s ( ) FileMode .Create,

{
prvate prvate public

{
B m a r y F i l e = new FileStreamC'test.dat", FileAccess .R e a d W n t e ) ; ByteArray = new byte [256];

}
public void WriteByt.es ( ) Arraylndex;

{
mt

for ArrayIndex = 0; Arraylndex < 25c; Arraylndex + + ) ByteArray[Arraylndex] = (byte)Arraylndex; B m a r y F i l e .Write (ByteArray, 0, 25c);

}
public bool ReadBytes( )

{
in t A r r a y l n d e x ;

558

BmaryFile.Seek(0, S e e k O n g m . B e g m ) ; B m a r y F i l e .Read (ByteArray, 0, 256) ; f or (Ar raylndex = 0; Arraylndex < 2 5c;

A r r a y In d e ; : + +)

{
i f (ByteArray[Arraylndex] return false; != (byte)A rr a y l n d e x )

}
return true;

} }
class MamClass public void M a i n ( ) = new Fi 1eTestClass I) ;

{
statrc

{
FileTestelass FileTest bool ReadTest;

F i 1 e T e s t .W r 1 1 e B y t e s () ; ReadTest = FileTest .ReadByte.s ( ); f(ReadTest == true) Consol .WriteLine ("The readback e1se C o n s o l e . W r i t e L m e ("The readback

test test

v/as successful ." ;

f ailed. " ;

) } El listado 2 5 . 1 nnplemcnta dos clases C#: Fi 1 e T e s t C i a s s . que contiene el codigo de E/S de la secuencia \ M a m C l a s s . que contiene el mtodo M a i n ) de la aplicacin. El mtodo Mal n ( ) crea un objeto de la clase Fi i e T e s t C i a s s y pide al objeto que escriba y lea datos. La clase F i l e T e s t C 1 a s s contiene un mi embro privado que representa un objeto F i 1 e S t r e a m . El c o n s t r u c t o r de la c l as e cr ea un n ue v o o bj et o F i l c S t r e a m mediante un const ructor que acepta tres argumentos: La ruta de la secuencia de archivo con la que se va a trabajar. Una especificacin de modo par a la operacin de archivos. Una especificacin de modo para el acceso a archivos.

La especificacin de modo para la operacin de archivos esta representada por una enumeracin llamada Fi l e M o d e . La enumeracin F i l e M o d e se incluye en el espacio de nombres S y s t e m . 1 0 de . NET y admite los siguientes miembros de enumeracin: A p p e n d . que ordena a la secuencia de archivos que abr a el archivo indi cado si lo encuentra. Si el archivo indicado existe, la clase de secuencia de archivos se inicializa para escribir datos al final del archivo. Si el archivo indicado no existe, la clase crea un nuevo archivo con el nombre especifi cado.

559

Create. que ordena a la secuencia de archivos que cree el archivo indica do. Si el archivo ya existe, se sobrescribe. CreateNew. que. como Create. ordena a la secuencia de archivos que cree el archivo indicado. La diferencia entre CreateNew y Create es el modo de t raba jar con los archivos existentes. Si el archivo ya existe c u a n do se especifica CreateNew como modo de archivos, la secuencia de archivos inicia una excepcin de la clase lOException. Open. que ordena a la secuencia de archivos que a br a el archivo indicado. OpenOrCreate. que ordena a la secuencia de archivos que cree el ar chi vo indicado. Si el archivo ya existe, el objeto FileStream abre el ar chi vo indicado. Trncate, que ordena a la secuencia de archivos que abr a el archivo
indicado y. a continuacin, lo trunca par a que su t amao sea cero bytes La especificacin del modo de acceso a archivos est representada por una enumeracin llamada FileAccess. La enumeracin FileAccess tambin se encuentra en el espacio de nombres N E T System. 10 de N E T y admite los siguientes mi embros de enumeracin:

Read. que especifica que la clase FileStream debe permitir el acceso de lectura al archiv o especificado. ReadWr ite. que especifica que la clase Fi leSt ream debe permitir el acceso de lectura y escritura al archivo especificado. Wr i te. que especifica que la clase FileStream debe permitir el acceso de escri tura al archivo especificado. Se pueden escribir datos en el a r c h i vo, pero no se pueden leer.

El constructor Fi leTes tClass del listado 25.1 crea una nueva secuencia de archivos que gestiona un archivo llamado test .dat. El archivo se abre en modo de creacin p ar a el acceso de lectura y escritura. El mtodo WriteByt.es (') de FileTestClass se coloca en un bfer de 256 de bytes. que crea el constructor de la clase. Se ubica en el bfer de 256 bytes con v alores que van desde 00 hexadecimal a FF hexadecimal. A continuacin se escribe el bfer en la s ecuencia mediante el mtodo de secuencia de archivos Write ( ) . El mtodo Write ( ) acept a tres argumentos: Una referencia al bufer de bytes que contiene los datos que se van a escri bir. Un nmero entero que especifica el elemento de matriz del pri mer bv te del bfer que se va a escribir. Un numero entero que especifica el nmero de bytes que se van a escribir

560

El mtodo W r i t e ( ) es sincrnico y no regresa hasta que los datos se han escrito realmente en la secuencia. El mtodo ReadBytes ( ) de FileTestClass lee los 256 bytes escritos por WriteBytes ( ) y com pa r a los bytes con el patrn de bytes i mplementado por WriteBytes (). La pri mera o peracin que realiza el mtodo ReadBytes ( ) supone trasladar el puntero de la secuencia al principio del archivo. La posicin de las secuencias es un concepto importante y merece una especial atencin. Las secuencias a dm i ten el concepto de posi ci onami ent o de fila. Una posicin de s ecuencia hace refe rencia a una posicin en la secuencia donde tendr lugar la pr xi ma operacin de E/S. Por lo general, una posicin de secuencia se sita al principio de una secuen cia c uando se inicializa esa secuencia. A medida que se leen o escriben datos en la secuencia, la posicin de la secuencia avanza hast a la posicin inmediatamente despus de la ltima operacin. La figura 25.2 refleja este concepto. Mues tra una secuencia con seis bytes de datos.
E s ta d o d e la s e c u e n c ia d e a r c h iv o s al in ic ia liz a r el o b |e to

po sici n

E s ta d o d e la s e c u e n c ia d e a r c h iv o s d e s p u e s d e le e r tr e s b y te s

2 j

_____

po sici n

Figura 25.2. La secuencia de E/S se mueve a la siguiente posicin de secuencia

Cu an do la secuencia se abre por primera vez. la posicin de secuencia apunt a al primer byte de la secuencia. Esto a parece reflejado en el d i ag ra ma superior de la figura 25 .2. Imagine que el cdigo que gestiona la secuencia lee tres bytes del archivo. Se leen los tres bytes y la posicin de secuencia a p u nt a r a al byte inme di at ament e despus de la ltima posicin que se ha ledo Siguiendo con el ej em plo. la posicin de secuencia a pun ta r al cuart o byte de la secuencia. Esto se refleja en la parte inferior del di agrama de la figura 25.2. La relacin con el cdigo 25.1 tiene que ver con el hecho de que se crea un archivo v se escriben 256 bvtes en l. C uando se han escrito los bvtes. se leen. Sin

561

embargo, es importante recordar dos conceptos de posicionamiento de s ec uen cias: La posicion del archivo se actualiza despus de cada operacin de lectura o escritura, para sealar una posicin inmediatamente posterior a la ltima operacin. Las operaciones de lectura y escritura empiezan en el byte al que hace referencia la posicin de secuencia. C uando el cdigo del listado 25.1 crea la nueva secuencia de archivos, la posicin de archivo es situada al principio del archivo (vaco). Tras escribir los 256 bvtes. la posicin del archivo se actualiza par a hacer referencia a la posicin i nmediatamente posterior a los 256 bvtes. Si el cdigo va a leer los 256 bvtes inmediatamente despus de la operacin de escritura, la operacion de lectura fallara porque la posicin de secuencia apunt a hacia el final del archivo tras la operacion de escritura y la operacin de lectura intentara leer 256 bvtes a partir de esa posicin, pero no hay bvtes disponibles en esa posicin. El eodigo debe decir "antes de que empiece la operacion de lectura, vuelve a a pu nt ar el puntero del archivo hacia el principio de la secuencia par a que la operacion de lectura pueda realizarse." Lsta tarea la realiza un mtodo de la clase St.rcam llamada Scok ;). El mt odo Seck ( ) permite al eodigo t ras ladar o b us car la posicion de secuencia a cualquier posicin disponible en la secuencia. El mtodo S o o k u recibe dos parmetros: Un numero entero long. que especifica un des pl azami ent o de posicion en bvtes. Un valor de una enumeracin llamada SeekOrigin. que especifica la posicion de secuencia que debe usarse en el punto inicial para la operacion de bsqueda. La enumeracin Seei-kOr i g i n se declara en el espacio de nombre S y s t e m . 10 v admite los siguientes v alores:

Beg in . que indica que la operacion de b s queda debe realizarse respecto al principio de la secuencia. Current. que ndica que la operacion de bsqueda debe realizarse res pecto a la actual posicion de la secuencia. End. que indica que la operacion de bs queda debe realizarse respecto al final de la secuencia.
El mtodo Seek ( ) ajusta la posicion de la secuencia para que apunte a la posicion de secuencia a la que hace referencia la enumeracin SeekOrigi n . que se despl aza el numero especificado de bvtes. El despl azami ent o de bvtes

562

u sa do en el mt odo Seek ( ) puede ser positivo o negativo. El siguiente ejemplo usa un valor de despl azami ent o positivo:
File.Seek (4, SeekOngm.Begin) ;

La anterior lnea ajusta el puntero de la secuencia para que apunte cuatro bytes ms all del principio de la secuencia. Los valores de despl azami ent o po si tivo desplazan el puntero de la secuencia hacia el final de la secuencia. El siguien te ejemplo usa un valor de despl azami ent o negativo:
F i l e .S e e k (-2, Se ek O r i g i n .E n d );

Este ejemplo ajusta el puntero de la s ecuencia p ar a que apunt e dos bytes antes del final de la secuencia. Los valores de d espl azami ent o negativos desplazan el puntero de la secuencia hacia el principio de la secuencia. El cdigo del listado 25.1 usa el siguiente cdigo de bs queda antes de que se lean los 256 bytes:
B m a r y F i l e . S e e k (0, SeekOrigm.Begm) ;

Esta llamada ajusta el puntero hacia el principio de la secuencia. Cuando empi eza la operacin de lectura, comi enza leyendo desde el principio de la se cuencia. El mtodo ReadBytes ( ) usa el mtodo FileStream llamado Read ( ) par a realizar una lectura sincrnica de E/S en la secuencia. El mtodo Read ( ) admite tres argumentos: Una referencia al bfer de bytes que se usar para contener la lectura de bytes de la secuencia. Un numero entero que especifica el elemento de mat ri z del pri mer bv te en el bfer que contendr la lectura de datos de la secuencia. Un numero entero que especifica el numero de bytes que se van a leer. El mtodo Read ( ) es sincrnico v no regresa hasta que se han ledo real men te los datos de la secuencia. Cuando la operacin de lectura se completa, el codigo c omp rue ba el patrn de bytes de la matriz par a asegurarse de que concuerda con el patrn de bytes que se escribi.

E/S asincrnica
El listado 25. 2 es una mo di fi cac i n del listado 25 1 que refleja la E/S asincrnica. A diferencia de la E/S sincrnica, en la que las llamadas para leer y escribir operaciones no regresan hasta que la operacin esta completa, las l lama das a operaciones de E/S asincrnicas regresan poco despus de ser llamadas. La operacin de E/S actual se realiza de forma oculta, en un subproceso distinto creado por la implement aci n de los mtodos de E/S asi ncrnicos de N E T

563

Framevvork y cuando la operacin se ha completado se advierte al cdigo med ian te un delegado. La ventaja de la E/S asincrnica es que el cdigo principal no necesita depender de que se complete una operacin de E/S. La realizacin de largas operaciones de E/S en segundo plano evita que la aplicacin tenga que realizar otras tareas, como proces ar los mensajes de Wi ndows en aplicaciones de Wi ndows Forms.

Cmo leer de forma asincrnica


El listado 25.2 mejora el listado 25.1 realizando la operaci n de lectura asincrnicamente. La operacin de escritura sigue realizndose sincrnicamente. La secuencia se inicializa de la mi sma manera, sin i mport ar cmo se realiza la E/ S. Las secuencias pueden mani pul arse asincrnicamente p ar a todas las o per aci o nes de E/S. de forma sincrnica par a todas las operaciones de E/S o en una combi nacin de forma sincrnica y asincrnica.
Listado 25.2. Escritura sincrnica, lectura asincrnica using using using class System; System.10; System.Threading; FileTestClass FileStream B m a r y F i l e ; byte [ ] ByteArray; IA.syncResult AsyncResul t Implement at ion ; A s y n c C a 1lback ReadBytesCompleteCallback; Fi ieTestC1ass ( )

{
prvate prvate prvate prvate public

{
AsyncResultImplementation = nuil; B m a r y F i l e = new Fil eS tr ea mC te st .d at ", F i l e A c c e s s .Rea dW rite) ; ByteArray = new byte [2 5 6 j ; ReadBytesCompleteCallback = new As y n c C a l l b a c k (O nR ea dB yt es Co mp 1e t e ) ; FileMode .C r e a t e ,

}
public void WriteBytes () Arraylndex;

{
mt

for (Arraylndex = 0; Arraylndex < 25c; Arraylndex + + ) ByteArray[Arraylndex] = (byte)Arraylndex; B m a r y F i l e .Write (ByteArray, 0, 25 6) ;

}
public void ReadBytes( ) SeekOrigrn .B e g m ) ;

{
BinaryFi le .Seek (0,

564

AsyncResultImplementation = B ina r yFi 1 e .B e g m R e ad (By t eAr r a y , 0, ReadBytesCompleteCallback, null);

25c,

}
public void OnReadByt esComp le t e (IAs yncResult AsyncP.esult)

{
int Arraylndex; int BytesRead; int Failures; BytesRead = B m a r y F i l e .EndRead (AsyncResult) ; C o n s o l e . W n t e L i n e ("Bytes r e a d ........ : (0}", BytesRead) ; Failures = 0; for(Arraylndex = U; Arraylndex < 2 5c; A rr ay In d e x + + )

{
l f (ByteArray[ArrayIndex] != (byte)Arraylndex) f Console . W n t e L m e ("Read test failed for byte {0}.", Arraylndex);

at

offset

} }
Console.WriteLine ("Read test failures: (0} , Failures);

public

void

WaitForReadOperat io n T o F i n i s h ( ) WaitOnReadIO;

{
WaitHandle WaitOnReadIO = A sy n c R e sultImplementat i o n .A s y n c W a 1 1 Ha nd le ; Wa it OnReadIO.WaitOne () ;

} }
class MamClass void M a i n ( ) FileTest = new ; s ()

static public

FileTest . W n t e B y t e s () ; FileTest.ReadBytes ( ); FileTest .Wa 1 1 For Re adOpe r at o n T o F i m s h () ;

} } El codigo de las operaciones de escritura del listado 25.2 se controla de forma sincrnica v su cdigo es idntico al cdigo de las operaciones de escritura del listado 25.1. Sin embargo, la operacin de lectura es bastante diferente. El cdigo de las operaciones de lectura del listado 25.2 no empieza con una llamada al mtodo sincrnico R e a d ( ) de la secuencia sino con una llamada al mt odo asi ncr nico B e q i n R e a d ( ) . Esta llamada admite cinco parmetros. Los

565

tres primeros eoneuerdan con los par met ros admitidos con el mtodo sincrnico Read (). pero los dos ltimos p ar met ro s son nuevos: Una referencia al bfer de bytes que se u s ar p a r a contener la lectura de bytes de la secuencia. Un nmero entero que especifica el elemento de m at ri z del pri mer bvtc en el bfer que contendr la lectura de datos de la secuencia. Un nmero entero que especifica el nmero de bytes que se van a leer. Datos especficos de llamada. El d e l e g a d o c a l l b a c k d e b e s e r un o b j e t o de u n a c l a s e l l a m a d a AsyncCallback. La clase AsyncCallback se declara en el espacio de n o m bres System de N E T F ramewo rk y gestiona un mtodo que no devuelve nada \ admite una referencia a un interfaz llamada IAsyncResult . El listado 25.2 crea una instancia de este delegado en el constructor de la clase FileTestClass:
ReadBytesCompleteCallback = new AsyncCallback(OnReadBytesComplete);

La clase FileTestClass del listado 25.2 i n c li n e un nuevo mtodo l la ma do OnReadBytesComplete (). que se usa como mtodo delegado. El objeto Stream invoca a este delegado cuando se completa la operacin de lectura. La interfaz IAsyncResult. que se emplea como par met ro para el del ega do AsyncCallback. se define en el espacio de nombres System de NE T Framework. Admite cuatro propiedades que pueden usarse p ar a obtener ms in formacin sobre la nat ural eza de la operacin asincrnica:

AsyncState. que es una referencia al objeto que se proporcion como el ltimo p a r a m e t r o del mt odo BeginRead () . Los mt odos de E/S
asincrnicos permiten as oc ia r datos con una operacin especifica del lti mo par amet ro a un mtodo de E/S. En la propiedad AsyncState ha\ disponible una copia de estos datos. El listado 25.2 no necesita que los datos se asocien a la llamada, por lo que pasa un valor nuil como ultimo p a r a m e t r o p a r a B e g i n R e a d ( ) C o m o r e s u l t a d o , la p r o p i e d a d AsyncState tambin tiene un valor nuil. Quizas quiera usar estos datos para, por ejemplo, diferenciar una llamada de E/S de otra. Por ejem plo. puede usar la misma referencia de delegado en varias llamadas de E/S asincrnicas y quizas quiera p as ar junto a ella los datos que diferencian una llamada de otra.

As y n cWai t Hand le. que es una r ef er enci a a un obj et o de cl ase WaitHandle. La clase WaitHandle se declara en el espacio de n o m bres Sys tem .Thread i ng de . NET Framework. Este objeto encapsula
una sincronizacin de primitivos y sirve de clase base par a los primitivos especficos, como mutex y semforos. El cdigo puede es perar en este

566

control p ar a det erminar cundo la operacin de lectura est realmente terminada. El codigo del listado 25.2 hace precisamente eso.

CompletedSynchronous 1 y. que es un booleano cuyo valor es True si la llamada BeginRead ( ) se completa de forma sincrnica y Falso
en caso contrario. Casi todas las implementaciones de secuencia devuelven False par a esta propiedad cuando la interfaz hace referencia a una op e racin de E/S asincrnica.

IsCompleted. que es un booleano cuyo valor es Truc si el objeto Stream ha compl et ado la operacin asincrnica. Hast a ese momento, la propi edad tiene un valor False. El codigo puede destruir todos los recur
s o s r e l a c i o n a d o s c o n s e c u e n c i a s d e s p u s de q u e la p r o p i e d a d IsCompleted devuelve True. La llamada a BeginRead ( ) tambin devuelve una mplementaeion de la interfaz IAsyncCallback. El codigo del listado 25.2 ca ptu ra la referencia de interfaz para su uso posterior. El mt odo A s y n c C a l lback. que. en el l i st ad o 25 .2 . es el m t o do OnReadByt esComplet e ( ) . es invocado por el objeto Stream cuando se completa la operacin asincrnica. La implementacin que se muest ra en el lista do 25.2 empieza con una llamada a EndRead (). que devuelve el n umero de bytes que se leen realmente desde la operacin. Este numero debe ser igual al numero de bytes que se solicito leer mediante BeginRead ).

TRUCO: La llamada a EndRead () en el listado 25.2 se muestra para que se pueda encontrar el nmero de bytes afectados por la operacin asincrnica. Si el cdigo no necesita este valor, no es necesario llamar a EndRead ( ).
El resto de la implementacin del m t o d o O n R e a d B y t e s C o m p ie t e ( ; c o m prue ba el patrn de bvtes ledos por la operacin de E/S y enva sus resultados a la consola. El mtodo Main ( ) del listado 25. 2 agrega una nueva llamada de mtodo al cdigo del listado 25. 1. que es para un mtodo privado del objeto Fi leTestClass ll amado Wa i t Fo r ReadOpe r a t i onTo F ini sh (). ('orno la operacin de lectura asincrnica es la ultima operacin del codigo. la ap li ca cin puede salir antes de que se complete la operacin de lectura. Recuerde que el procesamiento de la operacin de E/S asincrnica se realiza en un subproceso diferente. Si el proceso principal sale antes de que el subproceso de E/S pueda terminar, el codigo de OnReadBytesComplete ( ) no tiene oport uni dad de terminar. El mtodo Wait ForReadOperat ionToFinish ( ) garant iza que la operacin se complete antes de regresar a su invocador. El mtodo W a i t F o rReadOperationToFim sh ( ) usa el temporizado! de espera en la implementacin de la interfaz IAsyncCa 1 iha h. para realizar

567

su trabajo. El mtodo llama al mtodo WaitHandle WaitOne ( ) para que e s p e re h a s t a que el t e m p o r i z a d o r de e s p e r a est m a r c a d o . La l l a m a d a a WaitOne ( ) no regresa hasta que el t empori zador de espera est marcado. El objeto Stream m ar ca el t empori zador de espera slo despus de que la operaclon de E/S se complete. Despus de que la llamada a WaitOne ( ) regrese, puede estar seguro de que toda la operacin se ha completado.

Cmo escribir de forma asincrnica


Las operaciones de E/S asincrnicas son parecidas a las operaciones de E/S sincrnicas. La nica diferencia es que se emplea el mtodo BeginWr i te ( ) en lugar del mtodo BeqinB.ead ( ) . El listado 25.3 perfecciona el listado 25.2 al i mplemcntar una operacin de escritura asincrnica.
Listado 25.3. Escritura asincrnica, lectura asincrnica using usmg using System; S ys t em .IO ; S y s tem.Threading;

{
prvate prvate prvate prvate prvate prvate public FileStream BinaryFile; byte [] ByteArray; IAsyncRe.sult AsyncReadResultImplementation; IAsyncRe.sult AsyncWr iteResult Implementat ion ; AsyncCallback ReadBytesCompleteCallback ; A s y n c C a 1lback W ri te BytesCompleteCallback; Fi1e T e s t C l a s s ( )

{
As yn cReadResu11I m p 1ementation = nuil ; B m a r y F i l e = new FileStream("test.dat", FileAccess .R e a d W n t e ) ; ByteArray = new byte [256]; ReadBytesComp1ete Ca 1lback - new A s y n c C a l l b a c k (O n P e a d B y t e s C o m p l e t e ); Wr iteBytesCompleteCal lback = new As y n c C a 1lback (OnWriteBytes C o m p 1et e ) ; Fi l eM o d e .C r e a t e ,

}
public void WriteBytes(') Arraylndez;

{
nt

for (Arraylndex = 0; ArrayIndex < 25 6 ; Ar raylndex + + ) ByteArray[Arraylndex] = (byte)Arraylndex; As yncWriteResultImp1ement ation = BinaryFi l e .BeginWri te (ByteArray, 0, 25 6, W r i t e By tes Co mp 1eteCallback, nuil);

568

public

void

ReadBytes ( )

{
W a i t F o r W r 1 t e O p e r a t 1 o n T o F i n i s h (); B m a r y F i l e . S e e k (0, S e e k O r i g m . Begin) ; AsyncReadResultImplementation B m a r y F i l e . B e g m R e a d (ByteArray, 0, 25c, ReadBytesCompleteCa1l b a ck , n u l l ) ;

}
public void O n R e a d B y te sC om pl et e(IAsyncResult AsyncResultj

{
int Arraylndex; int BytesRead; int Failures; BytesRead = Bi na r y F i l e .En dR ea d(AsyncResult); Console .WriteLine ("Bytes r e a d ........ : {())", BytesRead) ; Failures = 0 ; for (Arraylndex = 0; Arraylndex < 256; Arraylndex. + t)

(
if(ByteArray[Arraylndex] != (byte)Arraylndex) failed for byte at

{
offset Console.WriteLine("Read {0 } ." , A r r a y l n d e x ) ; test

I )
C o n s o l e . Wr it eL in e("Read test failures: KM", Failures);

}
public void W a 1 1ForReadOpera1 1 onToFinish () WaitOnReadIO;

{
laitHandle

WaitOnReadIO = AsyncReadResultImplement at i o n .As y n c W a i t H a n d l e ; W a i t O n R e a d 10.W a i t O n e ();

}
public void O n W r it eB yt es Co mp le te (IAsyncResult AsyncResult)

{
B m a r y F i l e .EndW rite (As yncResu It) ;

}
private void W a 1 1ForWr 1 1eOperationToFinish () WaitOnWntelO;

{
WaitHandle

WaitOnWritelO = As yncWr i t e Re su lt Im p1ement a 1 1 on.As y n c W a 1 1 H a n d 1e ; W a 1 1OnWritelO.Wait One ( );

} }

569

el as s M a m C l a s s

(
static piiblic void Main () FileTest = new FileTestClass () ;

{
FileTestClass F i I eT e s t .. W n t e B y tes () ; Fi 1e T e s t .PeadBytes () ;

} } El mtodo EndWrite ( ) no devuelve un valor, a diferencia del mtodo EndRcad (). Sin embargo, los dos mtodos se bloquean hasta que se termina la operacin de E S

Escritores y lectores
N E T Framework tiene muchas clases escritoras y lectoras que facilitan el trabajo con datos mas complejos que simples secuencias de bytes. Los lectores \ los escritores encapsul an una secuencia y propor ci onan un nivel de conversin que con\ erte los \ alores en sus secuencias de bytes equivalentes (para los escri tores) \ \ i c c \ c r s a (para los lectores). Las clases lectoras y escritoras de NET suelen tener un nombre que refleja el tipo de cambi o de formato que realizan. Por ejemplo, la clase H t.rr:Te:-:t.Wr i t . e r escribe \ al o r e s destinados para la infor macin de respuesta de H T T P enviada por A S P . N E T y la clase S t r i n g R e a c i e r lee \ alores escritos usando su representacin de cadena. Las clases escritoras y lectoras tambin controlan varios esquemas de codifi cacin. algo imposible de realizar mediante objetos de secuencia de bajo nivel. Por ejemplo, las clases derivadas de la clase abs tra ct a Te:-:tWr iter. permiten al codigo C# escribir texto y codificarlo en la secuencia mediante los algoritmos codificadores ASCII. Unicode. UTF7 o UTFK.

Cmo escribir secuencias con BinaryWriter


El listado 25.4 muestra la clase BinaryWriter en funcionamiento. La f un cin de la clase BinaryWriter es conv ertir tipos de datos de C# en series de bytes que puedan escribirse en una secuencia subyacente.
Listado 25.4. Cmo trabajar con la clase BinaryWriter u sing S y s t e m ; u.sing Syst.em. T O ; ciass FileTestClass

570

private BinaryWriter Writer; private FileStream B m a r y F i l e ; public FileTestClass( )

{
B m a r y F i l e = new Fi 1 eS t r e am (" t e s t .da t " , FileMode .Create, F i l e A c c e s s .ReadWrite) ; Writer = new B m a r y W r i t e r (BmaryFile) ;

}
public void W r i t e B m a r y D a t a ()

{
Writer.Write ( 'a' ) ; Writer.Write (123) ; W r i t e r . W r i t e (45 6.7 8 S ) ; Writer.Write ("test string");

class

MamClass

{
static public void M a i n ( )

{
FileTestClass FileTest = new F il eT e s t C l a s s ();

FileTest . W n t e B i n a r y D a t a ( );

} } El cdigo del listado 2 5 . 4 tiene un diseo de clases igual al del listado 25 .3. El cdigo contiene una c l a s e M a i n C l a s s y una clase F i l e T e s t C l a s s . El c on s tructor de la clase F i l e T e s t C l a s s del listado 25.4 crea una secuencia de archivos y. a continuacin, un objeto B i n a r y W r i t e r . El const ructor del objeto B i n a r y W r i t e r . que establece la relacin entre el escritor binario y la s ec uen cia en la que escribe sus datos, recibe una referencia a la secuencia de archivos. En el listado 25.4. todos los datos escritos en el escritor binario terminan en la s ecuencia de archi vos est abl eci da en el const ructor. El mtodo W r i t e B i n a r y D a t a ( ) escribe un carcter, un nmero entero, uno doble y una cadena, en la secuencia subyacente. La clase B i n a r y W r i t e r implementa varias s obr e ca r gas de un mtodo llamado W r i t e ( ) . Las sobrecargas del mtodo W r i t e ( ) admiten la escritura en la clase escritora de los siguientes tipos de datos: Booleanos Bytes Matrices de bytes Caracteres Matrices de caracteres Valores decimales

571

Valores dobles

Valores enteros cortos con y sin firma Valores enteros con y sin firma Valores enteros ampliados con y sin firma Sbytes Valores de coma flotante C ad e n a s

Si compila y ejecuta el cdigo del listado 25.4. se crea un archivo llamado Puede ex a mi n ar los contenidos del nuevo archivo en un editor hexadecimal para co mp ro b ar que las representaciones binarias de los v alores se han escrito en el archivo.

test.dat

Cmo leer de secuencias con BinaryReader


El listado 25.5 agrega la clase BinaryReader al cdigo del listado 25.5. Esta clase vuelve a ens ambl ar los bytes de la secuencia convi ni ndol os a sus tipos de datos originales y devuelve los valores al mvocador.
Listado 25.5. Cmo trabajar con la clase BinaryReader i ,i i nq usiny c 1d s s Sys tc m ; o y s t e m .I O ; F 1 1e T e s tC 1 a s s

i
p 1 1 v a t e Binar y P e a d e r R e a e lc r ; p 1 1 v a te Binar y V /r 1 1 e r W n t e r ; p r iv ate F i lo S t r e am Binar y Filo; p ublic
i

F 1 1e T e stClass )

Binar yFile - new FileStreaml "test .dal:" , Fi leMode .Crcate , F 1 1 e Ac ce s s .P . e adWrite ) ; Writor - new BinaryWriter(BinaryFile); Peader - new BinaryReader(BinaryFile);

}
p u b 1 ic v o id PeadBinaryData ()

{
char PeadCharacter; double ReadDouble; int Readlnteger; string R e a d S t n n g ; BinaryFile .Seek (0, Se ek Or ig i n . B e g m ) ; PeadCharacter - R e a d e r .R e a d C h a r ();

572

Readlnteger = R e a d e r .Readlnt32 ( ); ReadDouble = Reader .ReadDouble (' ) R e a d S t n n g = Reader .ReadSt ring () Console.WriteLine ("Character : {0} " , ReadCharacter] ; Console.WriteLine("Integer: {0}", Readlnteger); Con s o l e . W n t e L m e ("Double : {0 } , ReadDouble) ; Console.WriteLine ("String: {0}", R e a d S t n n g ) ;

public

void WriteBinaryDat a () ( 'a' ) ; (123) ; (45 6. 78 S ) ; ("test string") ;

{
Writer.Write Writer.Write Writer.Write Writer.Write

class

MamClass public void M a i n ( ) ss FileTest - new F i le Te s t C l a s s (j ;

static

t .W r 1 1 e B in a r y D a t a () ; t .R e a d B in a r y D a t a () ;

A diferencia de la clase BinaryWriter. que contiene un mtodo s o br e c a r gado par a todas las operaciones, la clase BnaryReader contiene un mtodo de lectura distinto para cada tipo de datos. El codigo del listado 25.5 usa algunos de estos mtodos de lectura, como ReadChar () y P.ead Int3 ' (). para leer valores de la secuencia escrita en el mtodo Wr i teBinaryData (). Los valo res que se leen de la secuencia se env an a la consola. Al ejecutar el listado 25.5 se obtiene el siguiente resultado en la consola.
Integer: 123 Do ub 1e : 4 5 6.789 String: test strrng

Cmo escribir XML con un formato correcto mediante la secuencia XmlWriter


Las secuencias pueden hacer ms cosas apart e de leer y escribir datos en varias secuencias de datos. Tambie'n pueden agregar valor a los datos que se

573

envan a travs de la secuencia. Un buen ejemplo de esta tecnologa es la clase XmlWriter. que encapsul a en elementos X M L con formato correcto los datos que se envan a una secuencia. El resultado es un document o X M L con formato correcto con el que puede t raba jar cualquier procesador de documentos XML. como muest ra el listado 25.6.
Listado 25.6. Cmo escribir XML con la clase XmlW riter using using using class System; Syste m. 10; System.Xml; XMLStreamWritrelas.s XmlTextWriter void W n t e X M L () = new Xm lT ex tW riter(Console.O u t ); XmlWriter;

{
prvate public

{
XmlWriter

XmlWriter . W n t e S t a rt Document () ; XmlWriter.WriteComment("This XML document was autorna11 c a 11y generated by C# code.") ; XmlWriter . W n t e S t a r t E l ement (" BOOK " ) ; X m l W r i t e r .WriteElementString("TITLE", "C# Bible"); X m l W r i t e r . W n t e E l e m e n t S t r i n g ("AUTHOR", "Jeff Fergu so n" ); Xm lW ri te r.WriteElementString("PUBLISHER", "W iley"); XmlWriter.WriteEndElement () ; X m l W r i t e r . W r i t e E n d D o c u m e n t ();

} }
class MamClass void M a i n ( ) XMLStreamWriter = new

{
static public

{
XMLStreamWriterClass XMLStreamWriterClass ( );

XMLS t r e amWriter.Writ e X M L ( );

} } El codigo del listado 25.6 crea una nueva instancia de la clase XmlWriter y la asocia a la secuencia de salida de la consola. El cdigo simplemente llama a varios mtodos de la clase XmlWriter para producir datos y los mtodos ro dean a esos datos con nombres de elementos X M L que se especifican cuando se llama al mtodo. Observe la siguiente lnea del listado 25.6:
XmlWriter.WriteElementString("AU THOR", "Jeff F e rguson");

574

Esta llamada ordena a la clase XmlWriter que escriba un elemento XML llamado <AUTHOR.> cuyo valor es <Brian Pat.terson>. al dispositivo de salida de la secuencia. La implementacin del mtodo proporciona automticamente la etiqueta de cierre XML. Al compi lar y ejecutar el cdigo del listado 25.6. se enva el siguiente d o c u mento X ML con formato correcto a la consola de la aplicacin:
<?xml version="1.0" encoding="IBM437"?> <!--This XML document vas automatically <BOOK > <TITLE>C# B ib1e </TIT L E > :AUTHOR> J e f f Fer gus on- /A U T HO R> < P U B L IS H E R : V i1 1 e y /PUBLI SHER > < / B O O K >

generated

by C#

code.--

Resum en
Las secuencias proporcionan compatibilidad con la E S sincrnica y asincrnica en las aplicaciones de C#. Las secuencias trabaj an en el nivel de bytes y necesi tan que se lean y escriban bloques de bvtes. Los lectores y escritores encapsulan secuencias y proporcionan acceso a los datos en un nivel superior. Puede usar lectores y escritores para t rabaj ar con los tipos de datos estandar de ('#. lo que permite que los lectores v los escritores hagan conversiones entre los v alores de tipos de datos y sus representaciones de bv tes. Su codigo C# seguramente traba jara con lectores y escritores, ya que p r o p o r cionan compatibilidad para t rabaj ar con los tipos de datos est andar sin tener que ocuparse de realizar la conv ersin entre un valor de un tipo de dato y su represen tacin binaria. Sin embargo, las secuencias tambin estn disponibles si cree que necesita t rabaj ar con ellas directamente. Quizs tambin quiera t rab aj ar con se cuencias si los datos que est levendo estn en un formato propietario que no es compatible con las clases lectoras y escritoras est andar de N E T Framework. Tambi n puede considerar la posibilidad de crear sus propias clases lectoras, derivadas de las clases base TextReader o StreamReader y usarlas para leer la secuencia de formato propietario.

575

26 Cmo
dibujar con GDI+

En Wi ndows, el acceso mediante pro gr amaci n al s ubs is tema de grficos se consiguio por pri mera vez usando los API GDI disponibles desde Wi ndows 3.1. GDI ofreca a los prog ramad ore s la posibilidad de controlar cualquier tipo de elemento de mt erfaz de us uar io y esta funcin ha sido reconstruida desde cero en N E T Framework. GDI + ha reemplazado a GDI como el API que se usa par a acceder a los subsi stemas de grficos de Wi ndows. Con GDI + puede acceder a fuentes, ma ni pul ar cualquier tipo de imagen y t rab aj ar con formas en las apl i ca ciones de C#. Para conseguir una v isin global de cmo usar G DI + en sus a p l i ca ciones. debe comp re nd er el modo de empleo de los objetos Graphics. Pen. Brush y Color. Con estos cuatro objetos, puede conseguir casi cualquier cosa que necesite hacer con las GUI y las imgenes de N E T Este captulo estudia estos objetos y le familiariza con el uso de GDI + en C#. Las clases disponibles en G D I + podran llenar un libro de mil pginas, por lo que debe seguir usando SDK como referencia p ar a la ms compleja y menos u sad a funcionalidad grfi ca que no se t rata en este captulo.

Cm o trabajar con grficos


Al t rabaj ar con GDI + en NE T. el principal objeto con el que se debe trabaj ar es el objeto Graphics. Este objeto es la superficie real que se usa para pintar

577

formas, t raba jar con imgenes o mos trar texto. Visual Basic 6 y versiones ant e riores i ncorporaban una limitada compatibilidad par a t rabaj ar con grficos, lo que dificultaba a los progr amadores de VB la tarea de escribir aplicaciones gr fi cas personalizadas. Lo que VB haca era mantener un registro de cmo se dibujaban en pantalla los formularios y los objetos de los formularios. La propiedad AutoRedraw p e r m i ta que los formularios dejasen a Wi nd ows mantener un registro de lo que estaba en la parte superior de las dems ventanas y. en caso de necesidad, di buj ar de nuevo aut omt icame nte un formul ari o si otro est aba encima de l durante un cierto periodo de tiempo. No haca falta que se o c u pa r a del proceso real de d i b u jar el formulario. En N E T . sucede todo lo contrario. El objeto Graphics no recuerda cuando fue di bujado ni qu fue lo que dibuj. Por tanto, es necesario dibujar de nuevo los objetos tantas veces como resulte necesario si otras ventanas estn encima de una ventana concreta. Esto puede parecer pesado, pero la variable PaintEventArgs del evento Paint de un formulario puede controlar el proceso perfectamente Si el cdigo de dibujo se mantiene all, cada vez que Wi ndo ws pinte el formulario, los objetos se generarn correctamente. El siguiente fragmento de cdigo recibe una referencia a un objeto Graphics mediante la variable PaintEventArgs del evento Paint de un formulario:
prvate void Forml Paint (object. sender, S y s t e m .W i n d o w s .F o r m s .PaintEventArgs p)

{
Graphics g = p . G r a ph ic s;

} T a m b i n p u e d e c r e a r u n o b j e t o G r a p h i c s m e d i a n t e el m t o d o CreateGraphics de un control o formulario. El siguiente cdigo mues tra el mt odo CreateGraphics:


prvate void createManua1l y ( )

{
Graphics g ; g = t h i s .Cr ea teGraphics;

} El tercer y ltimo modo de cr ear un objeto Graphics es p as ar un archivo de imagen directamente al objeto al instanciarlo. como muest ra el siguiente cdigo al t omar una imagen de m ap a de bits del sistema de archivos:
prvate void createFromFi1e ()

{
Graphics g ; Bitmap b; b = new Bitmap (0 " C :\Enter pr is e.bmp" ) ; g - G r a p h i c s .Fromlmage(b);

578

Si ha estado agr egando estos fragment os a un formulario de Wi ndows, es obvio que no sucede n ada c ua ndo se ej ecut a al guno de estos cdigos. Para u npl ement ar realmente al guna funcionalidad, debe us ar mi embros de la clase Graphics par a hacer que sucedan cosas.

NOTA: Si crea un objeto Graphics mediante el mtodo CreateGraphics, debe llamar a Dispose ca ese objeto despus de usarle. As se asegura de que el objeto Graphics se eliminar de la memoria.
La tabla 26.1 enumer a las propiedades de la clase Graphics y la tabla 26.2 enu mer a los mtodos di sponibles de la clase Graphics. La clase Graphics se incluye en el espaci o de nombres S y s t e m .Drawing, que se agr ega c omo refe rencia por defecto cuando se crea una nueva aplicacin Wi ndows Forms. Esto no significa que no se puedan usar objetos Graphics en A S P . N E T ; de hecho, en A SP N E T se pueden escribir aplicaciones de proceso de imgenes e xt r e m a d a mente depu radas usan do objetos Graphics.
Tabla 26.1. P ropiedades de la clase Graphics

P rop ied ad

D escrip cin

Clip ClipBounds CompositingMode CompositingQuality

Obtiene o establece un objeto Regin que delimi ta la regin de dibujo de este objeto Graphics Obtiene la estructura RectangleF que delimita la regin de recorte de este objeto Graphics Obtiene un valor que especifica cmo se dibujan las imgenes compuestas en el objeto Graphics Obtiene o establece la calidad de la generacin de las imgenes compuestas que se dibujan en el ob jeto Graphics Obtiene la resolucin horizontal de este objeto
Graphi es

DpiX DpiY InterpolationMode IsClipEmpty IsVisibleClipEmpty

Obtiene la resolucin vertical de este objeto


Graphi es

Obtiene o establece el modo de interpolacin aso ciado al objeto Graphics Obtiene un valor que indica si la regin de recorte de este objeto Graphics est vaca Obtiene un valor que indica si la regin visible de recorte de este objeto Graphics est vaca

579

Propiedad

Descripcin

PageScale

Obtiene o establece la relacin de escala entre las unidades universales y las unidades de pgina de este objeto Gr aph ics Obtiene o establece la unidad de medida usada para las coordenadas de pgina de este objeto
G raphi es

PageUnit

PixelOffsetMode

Obtiene o establece un valor que especifica cmo se desplazan los pxeles durante el procesamiento de este objeto Gr a p h ic s Obtiene o establece el origen de la generacin de este objeto G ra ph i cs para la interpolacin y los pinceles de trama Obtiene o establece la calidad de la generacin del objeto Gr ap hi c s Obtiene o establece el valor de la correccin gamma para la generacin de texto Obtiene o establece el modo de generacin para el texto asociado a este objeto G r ap h i cs Obtiene o establece la transformacin universal de este objeto Gr a p h ic s Obtiene o establece el rectngulo delimitador de este objeto Gr a p h ic s

RenderingOrigin

SmoothingMode TextContrast TextRenderingHint Transform VisibleClipBounds

T a b la 26.2. M todos de la clase Graphics

M todo

D escrip cin

Add MetafileCom ment BeginContainer

Agrega un comentario al objeto M e t a f i l e actual Guarda un contenedor Gr a p h ic s con el estado ac tual de este objeto Gr ap h i c s y abre y usa un nue vo contenedor de grficos. Limpia toda la superficie de dibujo y la rellena con el color de fondo especificado Dibuja un arco que representa una porcin de una elipse especificada por un par de coordenadas, un valor de altura y un valor de anchura Dibuja una curva spline Bzier definida por cuatro estructuras Point

Clear DrawArc

DrawBezier

580

Mtodo

Descripcin

DrawBeziers DrawClosedCurve DrawCurve DrawEIlipse

Dibuja una serie de curvas spline Bzier a partir de una matriz de estructuras Poini Dibuja una curva spline cardinal cerrada definida por una matriz de estructuras Point Dibuja una curva spline cardinal mediante una matriz de estructuras Point especificada Dibuja una elipse definida por un rectngulo delimitador especificada por un par de coordena das, un valor de altura y un valor de anchura Dibuja la imagen representada por el objeto icn especificado en las coordenadas especificadas Dibuja la imagen representada por el objeto icn especificado sin escalar la imagen Dibuja el objeto image especificado en la posicin especificada y con el tamao original Dibuja el objeto image especificado con su tama o original en la posicin especificada por un par de coordenadas Dibuja una lnea que conecta los dos puntos espe cificados por pares de coordenadas Dibuja una serie de segmentos de lnea que conec tan una matriz de estructuras Point Dibuja un objeto GraphicsPath Dibuja una forma circular definida por una elipse especificada por un par de coordenadas, un valor de altura y un valor de anchura y dos lneas radiales Dibuja un polgono definido por una matriz de es tructuras Point Dibuja un rectngulo especificado por un par de coordenadas, un valor de alto y un valor de ancho Dibuja una serie de rectngulos especificados por estructuras Rectangle Dibuja la cadena de texto especificada en la posi cin especificada con los objetos Brush y Font especificados Cierra el contenedor de grficos activo y restaura el estado que tena este objeto Graphics al esta-

Drawlcon DrawlconUnstretched Drawlmage DrawlmageUnscaled

DrawLine DrawLines DrawPath DrawPie

DrawPolygon DrawRectangle DrawRectangles DrawString

EndContainer

581

Mtodo

Descripcin

do guardado por una llamada al mtodo Begin


Container

EnumerateMetafile

Enva los registros del objeto Metafiie especifi cado, de uno en uno, a un mtodo de devolucin de llamada para su presentacin en un punto de terminado Actualiza la regin de recorte de este objeto Graphics con el fin de excluir el rea especifica da por una estructura Rectan gle Rellena el interior de una curva spline cardinal ce rrada, definida por una matriz de estructuras Point Rellena el interior de una elipse definida por un rectngulo de delimitacin especificado por un par de coordenadas, un valor de altura y un valor de anchura Rellena el interior de un objeto GraphicsPath Rellena el interior de una seccin de grfico circu lar definida por una elipse, determinada por un par de coordenadas, unos valores de anchura y altura y dos lneas radiales Rellena el interior de un polgono definido por una matriz de puntos, especificados por estructuras
Point

ExcludeClip

FilICIosedCurve FillEllipse

FillPath FillPie

FillPolygon

FilIRectangle

Rellena el interior de un rectngulo especificado por un par de coordenadas, un valor de anchura y un valor de altura Rellena el interior de una serie de rectngulos es pecificados por estructuras Rectangle Rellena el interior de un objeto Regin Fuerza la ejecucin de todas las operaciones de grficos pendientes y devuelve inmediatamente el control sin esperar a que finalicen las operaciones Crea un nuevo objeto G r a p h i c s a partir del identificador especificado en un contexto de dispo sitivo Crea un nuevo objeto G r a p h i c s a partir del identificador especificado de una ventana Crea un nuevo objeto Graphics a partir del objeto image especificado

FilIRectangles FilIRegion Flush

FromHdc

FromHwnd Fromlmage

582

Mtodo

Descripcin

GetHalftonePalette GetHdc GetNearestColor IntersectClip

Obtiene un identificador de la paleta actual de semitonos de Windows Obtiene el identificador del contexto de dispositivo asociado a este objeto Graphics Obtiene el color ms prximo a la estructura c o lor especificada Actualiza la regin de recorte de este objeto Graphics como la interseccin de la regin de re corte actual y la estructura Rectangle especifica da Indica si el punto especificado por un par de coor denadas est contenido en la regin de recorte vi sible de este objeto Graphics

IsVisible

MeasureCharacterRanges Obtiene una matriz de objetos Regin, cada uno de los cuales delimita un intervalo de posiciones de caracteres dentro de la cadena especificada MeasureString MultipIyT ransform ReleaseHdc Mide la cadena especificada al dibujarla con el ob jeto Font especificado Multiplica la transformacin universal de este obje to Graphics y especificada en el objeto Matriz Libera un identificador de contexto de dispositivo obtenido mediante una llamada anterior al mtodo GetHdc de este objeto Graphics Restablece la regin de recorte de este objeto
Graphics en una regin infinita

ResetClip ResetTransform

Restablece la matriz de transformacin universal de este objeto Graphics en la matriz de identida des Restaura como estado de este objeto Graphics el estado representado por un objeto GraphicsState Aplica la rotacin especificada a la matriz de trans formacin de este objeto Graphics Guarda el estado actual de este objeto Graphics e identifica el estado guardado con un objeto
GraphicsState

Restore RotateT ransform Save

ScaleTransform

Aplica la operacin de cambio de escala especifi cada a la matriz de transformacin de este objeto Graphics, anteponindola a esta ltima

583

Mtodo

Descripcin

SetClip

Establece la regin de recorte de este objeto G r a p h i c s en la propiedad clip del objeto Graphics especificado Transforma una matriz de puntos de un espacio de coordenadas a otro utilizando las transformaciones universal y de pgina actuales de este objeto
Graphics

T ransformPoints

TranslateClip

Convierte la regin de recorte de este objeto Graphics usando las cantidades especificadas en las direcciones horizontal y vertical Antepone la conversin especificada a la matriz de transformacin de este objeto Graphics

T ranslateT ransform

Como puede ver. la clase Graphics pr opor ci ona todos los mtodos posibles que pueda necesitar p ar a t r aba jar con cualquier tipo de elemento GUI. El listado 26.1 usa muchos de los mtodos de la clase Graphics para producir el resulta do que se muestra en la figura 26.1.

NOTA: Como no hay una propiedad AutoRedraw, todava necesita un modo de volver a dibujar un formulario si se le asigna un nuevo tamao. Si se usa el mtodo SetStyles y se pasa el estilo Contr o l S t y l e s . ResizeRedraw correctamente, se llamar al mtodo Paint de un for mulario para corregir su estilo. Tras la llamada, el objeto InitializeComponent de su formulario debe escribir SetStyle (ControlStyles .Res i zeRedraw, true) para garantizar que se llamar al evento Paint cuando el formulario cambie de tamao. Busque SetStyle en .NET Framework SDK para aprender ms sobre lo que puede hacer con el mto do SetStyle.
Listado 26.1. C mo usar mtodos de la clase Graphics prvate void d r a w L m e () ser recuperado

(
/* crea un objeto Graphics que puede * para cada una de las muestras */ Graphics g; g = this. Cr ea te Gr ap hi cs ( ); // Use Pen p ; el objeto Pen para crear una linea

584

p = new Pen(Color.Red,

50);

/* D r a w L m e es un mtodo sobrecargado, + pasa las coordenadas x 1, yl, x 2, y2 g.DrawLine(p, // dibuje Icn i ; i = new // llame un 100F, 100F, 5 0UF, 10F);

+/

icono del

sistema de archivos

Icn (@ "C:\Desktop. ico") ; a Drawlcon y pasa 15); las coordenadas x e y

g .D r a w l c o n (r , 15 0, // dibuje un

rectngulo

Pen p 2 ; p2 = new P e n ( C ol or .PapayaWhip,

7); y,

/* drbu]e un rectngulo pasando x, * altura y anchura +/ g .Dr awRectanglep2, 50, 50, 100,

100);

} Si llama a este mtodo desde una aplicacin Wi ndows Forms. su resultado se parecera a lo que aparece en la figura 26.1.

Figura 26.1. Resultado del uso de miembros de la clase Graphics

La clase Gra phi cs no hace nada por s misma. Para crear lineas, rectngu los. imgenes y fuentes, debe us ar otros objetos junto al objeto Graph ies. Ll listado 2 6 . 1 crea un objeto Pen para usarlo en conjuncin con el objeto Graph ies par a dibujar una lnea roja en el formulario. Tambi n crea un objeto Icn, que es usado por el objeto Graphics par a dibujar el icono de escritorio en el fo rmu lario. Como ya se dijo antes, puede realizar numerosas tareas con GDI + : dibujar formas y lneas, mani pul ar imgenes y t rab aj ar con fuentes. Las siguientes sec ciones profundizan en este tema, describiendo cmo puede usar objetos como

585

Pen, B r u s h c I ma g e en combi nacin con mi embros de la clase G r a p h i c s p ar a apr ov echa r al mxi mo la inmensa coleccin de utilidades GDI + de N E T

Cmo trabajar con Image en GDI+


Si necesita procesar imgenes existentes en el sistema de archivos, la clase Image le brinda la posibilidad de pr oc es ar imgenes en superficies creadas con el ob|eto Grap h i c s. La clase I m a g e se incluye en el espacio de nombres Sy st e m. Drawi ng v es una clase ab st ra ct a que le ofrece toda la funcionalidad que necesita p ar a u s ar m ap as de bits, iconos y met ar chi vos con un objeto G r a p h i c s para procesar objetos I ma ge predefinidos en un formulario. Las i mgenes p roces adas pueden p roceder direct ament e del sistema de archivos o de una secuencia de memoria En cualquier caso, est t ratando con algn tipo de fuente de imagen. Las imgenes pueden ser de tipo JPG. ICO o BMP En el listado 26 2. se abre un archiv o JPG del disco local p ar a que apa rez ca en un formulario. Este ejemplo es ligeramente diferente del que vimos anteriormente. En c'Ste. se sob re carga el evento OnPaint, del formulario para que la imagen no sea eliminada si se sita otra ventana sobre la suya. Este ejemplo muest ra como implement ar l lamadas al mtodo D i s p o s e en el objeto G r a p h i c s que se usa p ar a pintar la imagen JPG cuando se destruye el formulario.
Listado 26.2. Cmo usar imgenes con GDI +

namespace HenderJPG

{
public class Forml : System. W i n d o w s .F o r m s .Form

{
prvate System.C omponentMode1 .Container components = nuil; // declara la variable de imagen prvate Image mg;
p u b 1 ic Forml ( )

{
In 1 1 1 a 1 1 z eC omponent ( );

// abre la imagen
img - new B i t m a p (0"C :\ m o n e y .jpg " ) ;

// }
protected override void D i s p o s e ( bool disposing )

{
if ( disposmg )

(
/ , / Llama a DISPOSE sobre el objeto Img

586

i m g .D i spos e ( );

//
if (components != null)

{
components.Dispose () ;

} }
b a s e . D i s p o s e ( disposing );

}
static void M a i n ( ) F o r m i ());

{
A p p l i c a t i o n .Run(new

}
// sobrecarga el evento OnPaint protected override void OnPaint (P am tE v e n t A i g s

p)

{
Graphics g = p.Graphics; g .D r a w Imag e (i m g , 0,0);

} } } Si sc ejecuta esta aplicacin se producir un resultado parecido al que aparece en la figura 26.2.

Figura 26.2. Resultado del listado 26.2 usando un JPG con GDI +

El mtodo DrawImage usado par a dibujar la imagen en el formulario tiene casi 20 constructores sobrecargados. Bsicamente, cada uno indica al mtodo cmo dibujar la imagen, como coordenadas o como al tura y anchura. Con un simple ca mb io en el mtodo Draw Image. puede rellenar todo el formul ari o con el mapa de bits. Si pasa la constante ClientRectangle a Draw Image. como muestra el fragmento de cdigo, obtendr un resultado con un aspecto simi lar al de la figura 26.3. con todo el mapa de bits rellenando la pantalla:
// sobrecarga del evento OnPaint protected override void OnPaint (PaintEventArgs p)

587

Graphics g = p.Graphics; g .Drawlmage ( m g , ClientRectangle) ;

Figura 26.3. La imagen rellena todo el formulario

Tambi n puede devolver propiedades a una imagen sin mostrarla. El siguiente evento L o a d ex ami na al gunas de las propi edades disponibles de la imagen m o n e y . j p q que abrimos antes:
prvate voici Forml Load (object sender, System. EventArgs e)

i
M e s s a g e B o x .Show (mg .PhysicalDimension .T o S t n n g () Me.ssaqeBox .Show (i m g .He i g h t .T o S t r i n g () ); M e s s a g e B o x .Show (mg.Width.ToStnngO ); Mes.sageBox .Show (i m g .Ra w F o r m a t .ToSt r i n g ( ) ); M e. ss a g e B o x .S h ow (mg.Size . T o S t n n g ( ) ); );

) La tabla 26.3 describe cada una de las propiedades disponibles para imgenes a travs de la clase I m a g e .
Tabla 26.3. P ropiedades de la clase Image

P ro p ied a d

D escrip cin

Flags Frame Di mensionsList Height

Obtiene indicadores de atributo para este objeto


Image

Obtiene una matriz GUID que representa las di mensiones de los marcos de este objeto image Obtiene la altura de este objeto image

588

P rop ied ad

D escrip cin

HorizontalResolution Palette PhysicalDimension PixelFormat PropertyldList Propertyltems RawFormat Size VerticalResolution Width

Obtiene la resolucin horizontal, en pxeles por pulgada, de este objeto image Obtiene o establece la paleta de colores de este objeto Image Obtiene la anchura y altura de este objeto image Obtiene el formato de pxeles de este objeto image Obtiene una matriz de los identificadores de pro piedad almacenados en este objeto image Obtiene una matriz de objetos Propertyitemque describe este objeto image Obtiene el formato de este objeto image Obtiene la anchura y altura de este objeto image Obtiene la resolucin vertical, en pxeles por pul gada, de este objeto image Obtiene el ancho de este objeto image

Tambi n puede usar varios mtodos de la clase Image. que le permite m an i pul ar imgenes de un modo prct icament e ilimitado. El siguiente codigo voltea la imagen 90 grados:
m g .R o t a t e F l i p ( R o t a t e F l p T y p e .Rot at e 9 0 F l i p Y ) ;

La e numer aci n RotateFlipType permite especificar como quiere girar o voltear una imagen sobre una superficie de grficos. La tabla 26.4 enumera los mtodos restantes de la clase Image que puede usar para manipular una imagen.

Tabla 26.4.
M todo

Mtodos de la clase Image

D escrip cin

Clone FromFile FromHbitmap FromStream

Crea una copia exacta de este objeto image Crea un objeto image a partir del archivo especifi cado Crea un objeto Bitmap a partir de un identificador de Windows Crea un objeto image a partir de la secuencia de datos especificada

589

Mtodo

Descripcin

GetBounds

Obtiene un rectngulo delimitador para este objeto image en las unidades especificadas

GetEncoderParameterList Devuelve informacin sobre los parmetros que admite el codificador de imgenes especificado GetFrameCount GetPixelFormatSize GetPropertyltem GetThumbnail Image IsAlphaPixelFormat IsCanonicalPixelFormat IsExtendedPixelFormat RemovePropertyltem RotateFlip Save SaveAdd Devuelve el nmero de marcos de la dimensin especificada Devuelve la profundidad de color (nmero de bits por pxel) del formato de pxel especificado Obtiene el elemento de propiedad especificado de este objeto Image Devuelve la vista en miniatura de este objeto image Devuelve un valor que indica si el formato de pxel de este objeto image contiene informacin alfa Devuelve un valor que indica si el formato de pxel es cannico Devuelve un valor que indica si el formato de pxel es extendido Quita el elemento de propiedad especificado de este objeto Image Este mtodo gira, voltea o gira y voltea el objeto
Image

Guarda este objeto image en el objeto st ream con el formato especificado Agrega la informacin del objeto image especifi cado a este objeto Image. El objeto Encoder P a r a m e t e r s especificado determina cmo se incorpora la nueva informacin a la imagen exis tente Selecciona el marco que especifica la dimensin y el ndice Establece el elemento de propiedad especificado en el valor especificado

SelectActiveFrame SetPropertyltem

C omo ha podido ver en esta seccin, la clase Image ofrece funciones muy slidas cuando se usan con un objeto Graphi cs. En la siguiente seccin a p r e n der a usar lpices y pinceles par a t raba jar con imgenes y dibujar formas y lneas

B T 1

Cmo trabajar con lpices y pinceles


Como vimos en la clase Image. el espacio de nombres System. Drawi ng ofrece todo lo que necesitamos p ar a t ra ba j ar con imgenes procedentes de una secuencia o del sistema de archivos. . NET F ramework tambie'n ofrece comp at i bi lidad integrada para t rab aj ar con formas, lneas e imgenes mediante las clases Pen y Brush. Esta seccin muest ra como t raba jar con las clases Pen y Brush par a mani pul ar formas, lneas e imgenes y lograr los efectos deseados.

Cmo usar la clase Pen


La clase Pen permite dibujar lineas y c u n a s sobre una superficie de grficos. El espacio de nombres que contiene las funciones que usan las clases Pen y Brush es el espacio de nombres System. Drawinq .Drawing2P. de modo que asegrese de agregarlo junto a la instruccin de uso de sus archivos de clase. Al establecer varias propiedades en una instancia de Pen. puede modificar la apari enci a de lo que muest ra el lpiz. Al invocar mtodos de la clase Graphi es. puede indicar el tipo de for ma que quiere mostrar. El siguiente codigo establece las propiedades Color y Das hS tyl e para crear una elipse similar a la que aparece en la figura 26 4
prvate void Forml Load(object System.EventArgs e) sender,

{
Pen p - new Pen (Color.Blue, 10) ; p.DashStyle - D a s h St yl e.DashDot Graphics g = t h i s. Cr ea te Gr ap hi cs (); g .Draw E11 ipse ( p , 10, 15, 105, 2 5 0);

Figura 26.4. Dibujo de una elipse usando las propiedades Color y DashStyle

591

La tabla 26.5 recoge los valores posibles de la enumeracin us ada p ar a e st a blecer el estilo de la linea discontinua de la elipse.
Tabla 26.5. E numeracin DashStyle

Custom Dash DashDot DashDotDot Dot Solid

Especifica un estilo de guin personalizado defini do por el usuario Especifica una lnea formada por guiones Especifica una lnea formada por un modelo de guin y punto que se repite Especifica una lnea formada por un modelo de guin, punto y punto que se repite Especifica una lnea formada por puntos Especifica una lnea continua

Tambin puede personalizar lneas con las propiedades StartCap y EndCap usan do la enumer aci n Lm e C a p . que tambin se i n cl u \ e en el espacio de n o m bres Sy s t e m .Drawing .Drawing2D. El listado 26.3 muestra algunas var ia ciones que usa la enumeraci n LineCap par a di buj ar diferentes tipos de lneas, cuyo resultado puede ver en la figura 26.5.
Listado 26.3. Cmo usar la enumeracin LineCap protected override void OnPaint(PaintEventArgs e)

{
Graphics g = e.Graphics; Pen p - new P e n (C o 1o r .B r o w n , 15); // establece la flecha p. StartCap = L i n e C a p .ArrowAnchor p. EndCap - L i n e C a p .ArrowAnchor g .D r awL i n e (p , 3 0 , 30, Width-50, 30); // extremos redondeados p. StartCap - L i n e C a p .Round ; p. EndCap - L i n e C a p .Round ; g.Drav/Line (p, 30, 8 0, Width-50,

80);

// delimitador ledondo p.Stait.Cap - L i n e C a p .RoundAnchoi ; p. EndCap - L i n e C a p .RoundAnchor ; g.LuawLine (p, 30 , 12 0, Width-50, 12 0); // triangulo

592

p.StartCap = L i n e C a p .Trangle ; p.EndCap = L i n e C a p .Triangle ; g .Dr awL in e (p , 3 O , 15 0, Wi d t h - 5 O , 150); // delimitador cuadrado p.StartCap = L i n e C a p .SquareAnchor ; p.EndCap = LineCap.SquareAnchor g . D r a w L m e (p, 30, 190, Width-50, 190);

) La figura 26.5 mues tra el resultado de la ejecucin del codigo anterior usando la e numer aci n LineCap.

Figura 26.5. Cmo usar la enumeracin LineCap

Cmo usar la clase Brush


El uso de la clase Brush en conjuncin con un objeto Graphics permite procesar imgenes y objetos slidos sobre una superficie de grficos. El siguiente cdigo mues tra cmo crear una elipse continua rellena:
protected overnde void OnPaint (P a m t E v e n t Args e

1
Graphics g = e .G ra ph i c s ; So 1dBrush sb = new So li dB rush(Color.Black) ; c j.F i i 1E1 1 1 p s e (s b , C1 entRectanglei ;

} Si se ejecuta el cdigo anterior se produce una imagen como la que aparece en la figura 26.6. Se pueden cr ear varios tipos de pincel. Un SolidBru.sh. el que se uso en el anterior ejemplo, rellena una forma con un color solido. El uso de un HatchBrush permite i mprovisar la apariencia de sus grficos. HatchBrush usa las en ume raciones HatchStyle y HatchFilI para most rar los diferentes tipos de p a trones. El listado 26.4 dibuja algunas de las variaciones de HatchBrush mediante la e numer aci n HatchStyle. Esta enumeraci n tiene mas de 40 miembros, de

593

modo que merece la pena buscarl a en el SDK de . NET Framework. Si alguna vez necesita crear algn tipo de patrn de dibujo, puede encontrar una ayuda vital.

Figure 26.6. Elipse slida creada con pincel

Listado 26.4. Cmo usar la clase HatchBrush con HatchStyles prot.ect.cd override void OnPaint (Paint EventArgs e)

I
Graphics g - e.Graphics;

H a t c h B ru s h h b new HatchBrush (Hat.chSty ]e .Plaid, C o l o r .A n t 1 queWh ite ,Color.Black) ; g .F 1 11 K .1 1 1 p s e (h b , 3 0 , 3 0, Wid t h - 5 0, 30); HatchBrush hb2 = new HatchBrush (Hat chStyle.LargeCheckerBoard, C o Ior.Antiqu eWhite ,Color.Black) ; g .Fi 1 1F 1 1 ips e (h b 2 , 3 0 , 8 0, Wi d t h - 50, 30); Hat chBrus h hb 3 = new HatchBrush (Hat.chSty 1e .Dashed Horizon t a l , Color.An tiqu eWhite ,Color.Black) ; g .F i 1]F 1 1 ip s e (h b 3, 3 0, 1 30, Width-50,

30);

H a t ch Brush h b 4 = new HatchBrush (H a t c h S t y 1e .Z ig Z a g , Col o r .A n t iqueWh ite ,Col o r .B l a c k ) ; g .F i 1 1F ,1 1ip s e (h b 4 , 3 0, 18 0, W id t h - 5 0 , 30);

594

Si se ejecuta el cdigo anterior se produce una imagen como la que aparece en la figura 26.7.

Figura 26.7. H atchBrush con diferentes HatchStyles

La tabla 26.6 describe cada uno de los tipos de lpiz disponibles en la e num e racin PenType que puede usar con la clase Brush. Ya hemos visto IlatchF ii i y SolidColor en funcionamiento. Basandose en sus descripciones, probablemente pueda imaginar los otros tipos de pincel sin verlos en funcionamiento.
Tabla 26.6. Enumeracin PenType

M iem b ro

D escrip cin

HatchFill LinearGradient PathGradient SolidColor TextureFill

Especifica un relleno de trama Especifica un relleno de degradado lineal Especifica un relleno de degradado del trazado Especifica un relleno slido Especifica un relleno de textura de mapa de bits

El trabajo con texto y fuentes tambin requiere emplear un objeto Brush j u n to con un objeto Graphics. Para usar texto, se crea una instancia de la clase Font. que se i n cl i ne en el espacio de nombre System. Drawi nq y establecer las propiedades aspecto, estilo y t amao de texto y luego se llama al mtodo DrawString desde el objeto Graphics que contendr el pincel. El listado 26.5 dibuja la frase C# is cool en el formulario en uso y produce algo parecido a la imagen de la figura 2 6 . X .

595

Listado 26.5. Cmo usar el mtodo DrawString protected override void O n P a i n t ( P a m t E v e n t A r g s e)

(
Graphics g = e.Graphics; e . G r a p h i c s .FillRectangle ( new SolidBrush(Color.White) , Client Rectangle) ; g . D r a w S t n n g C ' C # is cool", this. Font, new SolidBrush(Color.Black), 15, 15);

NOTA: En .NET, las fuentes que se usan en un objeto Form se heredan de la misma forma. En este ejemplo, la propiedad fuente del formulario recibe el valor 24, de modo que cuando se pasa el valor this .Font al mtodo DrawString, se usa el actual tamao de fuente de formulario.

.-Jai xj

C# is cool
Figura 26.8. Cmo usar el mtodo Drawst ring y la clase Font para producir texto

La tabla 26.7 enumera las propiedades disponibles de la clase F o n t . Al es ta blecer o recuperar estas propiedades en sus objetos F o n t . puede controlar c o m pletamente el aspecto del texto en la pantalla.
Tabla 26.7. Font Class Properties

P ro p ied a d

D escrip cin

Bold FontFamily GdiCharSet GdiVerticalFont Height Italic

Obtiene un valor que indica si este objeto Font est en negrita Obtiene el objeto Font F ami ly asociado a este ob jeto Font Obtiene un valor de bytes que especifica el conjun to de caracteres GDI que utiliza este objeto Font Valor booleano que indica si este objeto Font se deriva de una fuente vertical de GDI Devuelve la altura de este objeto Font Obtiene un valor que indica si este objeto Font est en cursiva

596

Propiedad

Descripcin

Name Size SizelnPoints Strikeout

Obtiene el nombre del tipo de letra de este objeto Fon t Obtiene el tamao eme de este objeto Font en unidades de diseo Obtiene el tamao, en puntos, de este objeto Font Obtiene un valor que indica si este objeto Font especifica una lnea horizontal de tachado de la fuente Obtiene la informacin de estilo de este objeto Font Obtiene un valor que indica si este objeto Font est subrayado Obtiene la unidad de medida de este objeto Font

Style Underline Unit

Resum en
GDI ~t ofrccc una consistente matriz de clases que le permite escribir cualquiet tipo de soporte grfico en sus aplicaciones. Este capitulo presento una vista gene ral de las funciones de GDI +. pero puede hacer muchas ms cosas con los e s p a cios de nombre System.Drawing y System.Drawing.Drawing2D que pueden explicarse en un slo captulo. Para mani pul ar o crear grficos usando GD +. primero debe crear un objeto Graphics que le proporci ona una superficie en la que pintar. Una vez creado el objeto Graphics, puede usar lpices, pinceles, mapas de bits o fuentes para proc es ar el tipo de imagen deseado.

597

E 71 Cmo 27 construir servicios Web

Los servicios Web son. probablemente, el rasgo mas innov ador y apasionant e de la iniciativa N E T de Microsoft y probablement e afecte al modo en que las empresas interactan mediante las aplicaciones de ordenador. Pero, que es e x a c tamente un servicio We b? A grandes rasgos, un servicio Web es simplemente un component e de serv idor que puede ser invocado en Internet. Este component e de servidor normal ment e realiza un servicio fundament al de negocios, como la autentificacion del usuario, la validacin de tarjetas de crdito, el calculo del precio de un seguro de derivados, la tramitacin de una solicitud de co mpr a de acciones o el clculo del precio de un envo el mismo dia. Obviamente, la lista de posibles servicios Web es tan variada como la lista de posibles oport uni dades de negocio. Los servicios Web permiten a las aplicaciones inv ocar servicios de negocios me diante un mecanismo bas ado en estndares (usando X ML y H T T P ) y como vera en este captulo, el modo de realizar esto supone un importante avance en la interoperabilidad de las aplicaciones. La mayora de los estndares usados para crear servicios Web se realizan con XML. Si no est familiarizado con XML. puede leer una brev e introduccin en el apndice de este libro. En este captulo se e studiar qu estndares de XML controlan la definicin y el uso de los serv icios Web. A continuacin crearemos un servicio Web mediante Visual Studio NET. Por ltimo, usaremos este serv icio Web en un segundo p r o vecto de Visual Studio N E T

599

Funcionamiento de los servicios Web


A i d cfinir los servicios Web hay que contar con dos tecnologas opcionales: el m ecanism o de descu brim ien to v la descripcin de servicio. Se pueden evitar estas dos tecnologas usando otros medios de comunicacin; por ejemplo, si hay comunicacin (llamadas de telefono) entre los p rogr amadore s del servicio We b y los pr og ramad or es del cliente que acceder al servicio Web. El mecani smo de descubrimiento usa un document o X M L de servidor par a permitir que las a p li ca ciones cliente detecten la existencia de un s e n icio Web y encuentren una des cri p cin detallada de ese servicio. Al principio. Microsoft propus o usar D I SC O (descubrimiento de servicios Web) par a este mecani smo de descubrimiento, pero desde entonces UDDI (Descripcin, descubrimiento e integracin universales) se ha convertido en el est ndar real p ar a los descubrimientos. Puede encontr ar mas informacin sobre UDDI en h t t p : / / www . u d d i . o r g . La descripcin de s er vicio describe las entradas y salidas del servicio Web. Las descripciones de servi cio usan el es tndar Lenguaje de descripcin de s e n icio Web ( WS DL ). descrito en este mismo captulo. UDDI (o DISCO, su despreciado predecesor ahora) y W S D L son partes esenciales que pueden usarse par a crear detallada d oc um en t a cin s obr e c om o i n vo c a r un s er vi ci o Web. C o m o es tas t e c no l o g a s est n estandarizadas, las descripciones tambin pueden ser ledas por aplicaciones. Sin embargo, despus de que se ha implementado un cliente, no hay necesidad de usar el meca ni smo de descubri mi ento ni de hacer referencia a la descripcin de s e n 1cio. El uso de estas tecnologas no es indispensable par a crear o usar servicios Web orientados a una aplicacin concreta. Fin la invocacin real de un servicio We b t oman parte tres tecnologas: el p ro tocolo de conexin, el form ato de mensaje x el m ecanism o de in v o c a c i n . Solo los dos primeros estn especificados en los servicios We b estndares. El protocolo de conexin es el mecani smo de t ransporte que se emplea p ar a e st abl e cer la comunicacin entre el cliente y el servidor. Por lo general, suele ser HTTP , el protocolo de Internet bas ado en TCP/ I P. El formato de mensaje es el formato que se emplea para inv ocar un s e n icio Web. Un s e n icio Web puede ser invocado mediante H T T P puro o con un mensaje X M L en un formato especfico llamado Protocolo de acceso simple a objetos (SOAP). La tercera tecnologa, que controla cmo se llaman a los componentes de servidor, no est especificada por los est ndares del servicio Web. Este es un detalle de implementacin que queda a la eleccin de la persona que implementa el servicio Web. En otras pal abras, el pr og ra ma dor que crea el servicio Web elige la tecnologa usada par a llamar al eodigo de negocio en el servidor: un p r og r am ad o r de Visual Basic puede usar C O M + para invocar un objeto COM. un pro gr amado r de Java puede usar RMI para invocar un objeto Java y as sucesivamente. Las dos partes de un servicio Web pueden describirse como el creador (cliente) v el c ons umi dor (servidor). El creador desarrolla el component e de servidor v

600

muestra este servicio a quien corresponda. Por ejemplo, una institucin financiera desarrolla un sistema de validacin de tarjetas de crdito \ lo muestra a los vende dores conectados. M o s tr ar un servicio Web significa publicar la URL que los usuarios necesitan par a invocar al servicio Web. L1 consumi dor puede usar el servicio expuesto enviando un mensaje de peticin S OA P a la URL publicada. Al recibir una peticin S O A P escrita en XML. el component e de servidor tras el servicio We b es invocado en el servidor del creador. Los resultados de esta invo cacin toman el formato de un mensaje de respuest a S OA P y se envan de vuelta al consumi dor del servicio. La figura 27.1 muest ra los distintos elementos que toman parte en un servicio Web.

Peticin SOAP (XML) Respuesta SOAP (XML) Consumidor de servicios Web

Peticin SOAP (XML) Respuesta SOAP (XML)

T~T

IH

Creador del servicio Web

Invocacin

Componente de servidor
Figura 27.1. Los servicios W e b constan dos partes: un consum idor y un creador

Los servicios Web usan un conjunto de estndares para definir cmo se realiza la interaccin entre cliente y serv idor. Estos es tndares definen el mecani smo de t ransporte que se va a usar y el formato y contenido de la interaccin. En el nivel de transporte, se usa el omnipresente protocolo de Internet HT TP . El servidor y el cliente se comuni can entre s mediante mensajes XML. El contenido de estos mensajes tambin esta est andari zado y debe cumplir las reglas de S OAP (mas adelante se explicaran estas reglas). La nat ural eza de los servicios disponibles en un servicio We b puede ser descrita en un archivo X M L cuno contenido cumpl a con las reglas del Lenguaje de descripcin de servicio Web ( WSDL ). Por ultimo, un cliente puede des cubri r di nmi cament e qu serv icios Web ests expuestos en un servidor r ecuperando el archivo X M L cuvo contenido cumple con las reglas de DI SC O Obs er ve que an no se ha menci onado ni nguna tecnologa especfica de c o m paas. En ninguna parte se ha pres upues to el sistema operativo del cliente o el serv idor, el lenguaje de p rog ramaci n usado p ar a escribir el component e del ser-

601

vidor o el mecani smo usado p ar a invocar el componente del servidor. Estas elec ciones no tienen i mportancia p ar a un servicio Web. Un cliente escrito en C# que se ejecuta en Wi ndows XP. por ejemplo, puede invocar un servicio Web escrito en Java ejecutndose en Sun Solaris. De hecho, un cliente no tiene modo de saber que tecnologas se usan par a mos trar el servicio Web. Las implicaciones de los serv icios Web son enormes. Microsoft comenz la prog ramaci n bas ada en componentes con la introduccin de los controles OLE (OCX), una versin depu rad a de los i nnovadores conceptos presentados por los Controles de Visual Basic (VBX). Los O C X se basan en el Modelo de objetos de componentes de Microsoft ( C OM ) y funciona perfectamente. Sin embargo. C O M y su con tra part i da distribuida, el Modelo de objetos de componentes distribuido de Microsoft ( DC O M) . tienen un alcance limitado. Apart e de la familia de siste mas operativos Wi ndows, muy pocos sistemas admiten C O M / D C O M . Ademas, aunque la familia Wi ndows tiene una ampl ia aceptacin par a aplicaciones de escritorio, en la modalidad de servidor se usan una gran variedad de sistemas operativos. Por ejemplo, muchas variedades del sistema operativo UNIX, como Solaris y Linux, tienen una importante presencia Los servicios We b eliminan la necesidad de decidir el sistema operat ivo que se ejecuta en el serv idor al integrar dos aplicaciones Web. Al usar serv icios Web puede e ns ambl ar aplicaciones Web usando componentes de otros serv idores. Por ejemplo, puede usar un serv icio Web de una compa a de tarjetas de par a v alidar tarjetas de crdito, un serv icio Web de una compa a di stribuidora par a determinar los gastos de envi v as sucesivamente. Esta es la esencia y la oferta de los servicios Web: la siguiente generacin de progr amaci n b as ad a en componentes p ar a la siguiente generacin de aplicaciones distribuidas.

Servicios Web y Visual Studio .NET


Si los servicios Web son independientes de la pl at af orma en la que se ejecutan, qu espera conseguir con esto Mi cr os o ft ? La respuest a es sencilla: Microsoft ha a nunc ia do pbl icament e que intentar hacer de Wi n do ws el mejor sistema o pe rativo par a h os pedar servicios We b y de Visual Studio N E T el mejor entorno de desarrollo par a crear servicios Web. C omo este libro t rata de C#. nuestro estudio de los servicios Web se va a centrar en C# y en su entorno de desarrollo integrado. En la seccin prct ica de este captulo podr j uzgar por s mi smo lo flexible y sencillo de u sar que es el entorno de desarrollo Visual Studio NET. Visual Studio N E T logra un fantstico t rabajo simplificando la creacin y consumo de servicios Web. La mayor parte de las t areas que odian los progr amadores (por ejemplo, crear document os X M L ) se realizan automt icamente, sin requerir un gran esfuerzo por parte del programador. Todo lo que tiene que hacer al p ro g ra ma r es declarar su intencin de most rar un fragmento de cdigo como un

602

servicio Web y la herramienta se encarga de casi todo el trabajo. De hecho, la herramienta hace un trabajo tan bueno que nunca vera XML al construir un serv i cio We b y un c on sumi dor de serv icio Web. De hecho, esto es exact ament e lo que v a a hacer en este captulo. Sin embargo, antes de empezar, observ e el concepto que hace posible toda esta automatizacin: la progr amaci n basada en atributos. La progr amaci n bas ada en atributos es un potente concepto que permite a Visual Studio . NET aut omat izar una gran cantidad de pesadas tareas de p ro gr a macin (como crear un document o W S D L par a un servicio Web) Simplemente tiene que m ar c ar un fragment o de cdigo, como una clase o un mtodo, de un modo especial para indicar lo que quiere hacer con el. Como resultado. Visual Studio N E T genera los archivos necesarios par a implementar su funcin Un breve ejemplo servir par a mos trar cmo funciona al t rans for mar una clase en un servicio Web. El listado 27.1 mues tra como puede implement ar un sencillo juego. De a c u e r do. este juego no es muy entretenido (el j u g ad o r siempre pierde), pero este c a pi tu lo trata sobre la programacin de servicios Web. no sobre programacin de juegos. Observ e los elementos necesarios par a conv ertir este fragment o de codigo en un servicio We b y lo que Visual Studio N E T genera durante este proceso. El pri nci pal objetivo de este ejercicio es que se haga una idea de la cantidad de trabajo necesario par a convertir un fragment o de codigo completo en un servicio Web usando Visual Studio NET.
Listado 27.1. Un sencillo juego namespace MyFirstWebServi ce ciass GameWS

{
public

{
// Ejemplo de un sencillo juego // El juego de ejemplo devuelve la cadena // lose!" // Para probar este juego, pulse F5 public string Play ( s t n n g opponentName) "Sorry, you

{
return "Sorry " + opponentName + ", you lose!";

} } } El primer paso p ar a convertir este fragment o de cdigo en un servicio We b es g u a r d a r el cdigo en un nuevo archivo llamado GameWS .asmx. A continuacin, realice estos cuatro pasos: l . Agregue un ttulo que indique tres cosas: que el archivo contiene un servi cio Web. el lenguaje que usa y la clase que contiene la implementacin:
< @ WebService La nguage="c # " Cl as s= "MyFirstWebService.Ga m e W S " >

603

2.

Agregue una directiva System. Web . Service inmedi at ament e debajo del titulo del servicio Web:
us in g S y s t em . Ieb .Se rv ic es ;

3.

Mar qu e la clase como serv icio We b y escoja el espacio de nombres X M L asociado al servicio Web:
[WebS e rvi ce (Namespace="h t t p : / / w w w .boutqun.cora/GameWS/ ") ] public class GameWS : S y s t e m. We b.Services.WebService

4.

Mar q ue los mtodos de la clase como accesibles desde la Web:


[WebMethod] public s t r m g Play (string opponentName)

El listado 27.2 muest ra el resultado final. Tambi n se han cambi ado los c o mentarios par a reflejar los cambios al cdigo original realizados.
Listado 27.2. Sencillo ju e go expuesto como servicio W eb < ' @ WebService Langua ge =" c # " Class = "MyFirstWebService .GameWS"

using

System.Web.Services; MyFirstWebService

namespace

{
WebServ ce (ame s p a c e - " h t t p ://w w w . b o u t q u i n . cora/G a m e W S / ") ] public class GameWS : S y s t e m .W e b .S e r v i c e s .WebService

(
// EJEMPLO DE SERVICIO WEB // El mtodo Play() devuelve la cadena "Sorry, // Para comprobar este servicio web, pulse F5 [WebMethod] public string Play(string opponentName) you lose!"

I
return "Sorry " t opponentName + ", you lose!";

} } Al c o n s t r u i r un p r o y e c t o de s e r v ic i os W e b en V i s ua l S tud io. se cr ea aut omt i came nt e un archivo de descripcin de servicio que describe el servicio Web. Este archivo es un dialecto X M L llamado Lenguaje de descripcin de servi cio We b (WSDL ). Un archivo W S D L tiene este aspecto:
<?xml vers io n= "1.0" encoding="UTF-8"?> <me thods h r e f - 'http: / /www2 2 . b n n k s t e r . com/boutquin/ G a m e W S .asmx ' > <'method ame-' Play' href = 'Play'> < re qu e s t >

604

<param dt = 'string' >opponentMame</paiam^ < / r e que st > < response dt = 'string' /> < /meth od > </methods >

W S D L describe las funciones que estn expuestas (el formato que se muestra es en realidad una simplificacin del formato real, pero los conceptos siguen siendo los mismos). P u e d e l l a m a r al s e r v i c i o m e d i a n t e una U R L (en est e c a s o. www22.

b r i n k s t e r .c o m /boutqu i n / G a m e W S .a s m x /Play ? oppo ne n tName =Pierre) o enviar un mensaje X M L con el formato a pr opia do a la URL (me diante una instruccin post o get HTTP ). Este mensaje X M L puede ser un
mensaje S O AP como el siguiente:
<?xml v e r s ion =" 1.0" e ncoding-"u t f -8 "?> < s o a p :E n v e 1ope x m l n s :x si = "ht t p ://w w w .w3.org/2001 /XMLS c h e m a -m s t a n c e " xmlns :x s d = "h 1 1 p ://w w w .w 3 .org/2001/XMLS c h e m a " x m l n s :soap="http: //s chema s .x m l s o a p .o r g / s o a p / e n v e l o p e / > < s o a p :Body> <Play xmlns = "http: / /www . b o u t q u m . com/GameWS / " > < o pp on en tN am e > P i e r r e < /opponentName > < /Play> < / s o a p :B o d y > < / s o a p :E n v e 1ope >

Al invocar el servicio, mediante la URL o enviando un mensaje SOAP, se produce una respuesta X M L como la siguiente:
<?xml ve r s i on= " 1 .0 " e n c o d m g = " U T F - 8 " ? > < s t r ing xmlns = "h t t p : //w w w .bout q u i n .com/G am eW S/">S or r y you lose !< / s t n n g > Pierre,

Las siguientes secciones examinan las bases de S OAP y W S D L . tras lo cual p as ar emo s a estudiar los detalles de la creacin e inv ocacin de servicios Web.

Lenguaje de descripcin de servicio Web (WSDL)


W S D L es el vocabulari o X M L usado p ar a describir serv icios Web. Esta des cripcin incluye informacin sobre cmo acceder a ellos. N E T F ramework se o cu p a de generar estos servicios We b por nosotros, de modo que no necesitamos saber demasiado sobre W S D L para us ar servicios Web. Para ver el aspecto de un W S D L p ar a un servicio puede aadir ?wsdl a su URL y ver el resultado en un nave gado r compatible con XML: por ejemplo, www2 2.brinkster.com/

b o u t q u i n / G a m e W S .asmx ?wsd1 .

605

Esta seccin hace una breve descripcin de este vocabulario XML. W S D L usa un e s p a c i o de n o m b r e p o r d e f e c t o . x m l n s = " h t t p : / / s c h e m a s . z m l s o a p . o r g / w s d l / . Usa un elemento raz llamado d e f i n i t i o n s v contiene varias secciones. Una de estas secciones es la seccin de servicio donde, evidentemente, se describen los servicios. El siguiente f r agment o es el esqueleto de un archivo WS D L . Un archivo W S D L real usa varias declaraciones de espacio de nombre, que aqu omitimos p or simplicidad.
<?xml ve rs i on= " 1 .O " e n c o d m g = "U TF - 8 " ?> <def m i t i o n s xmln.s =' http: / / s chemas .xmlsoap .org/wsdl / ' > <"service <!--El ame = "GameWS " > se describe aqu -->

servicio

< "/ s e r v c e > '/d e f i n 1 1 1 ons >

El pri mer at ri but o de una descripcin de servicio define la posicin desde la que se puede llamar al servicio. Esto se describe en el elemento a d d r e s s dentro de un elemento p o r t . (Elemento y at ri but o son trminos de XML. como puede ver en el apndice.) El siguiente ejemplo mues tra el at ri but o b i n d i n g :
<?;<ml ve r s ion= " 1 . " e n c o d m g = "UTF-8"?> definitions xm 1ns =' h t t p : //s c h e m a s .xmlsoap.org/wsdl/' > -''Service name = "GameWS" >

-'port name = "GameWS S oap " b m d m g = " s O :GameWS S oap " > 's o a p :address 1 ocation="h t t p ://www2 2 .brinkster.c o m / bo ut q ui n/ Ga me WS .a s m x " /p o r t > < / s e rv ic e > < /def m i t i ons)

/>

Si un servicio We b est expuesto mediante una instruccin p o s t o g e t de H T T P , su posicin se al mac ena en un elemento h t t p : a d d r e s s e l e m e n t :
<port name = "GameWSHt tpPos t ." b m d m g = "s O :GameWSHt t pPos t "> <'http: address location="http :/ /www2 2 .brinkster. com/bout qu in/ G a m e W S .asmx" /> < /port >

A continuacin, debe definir los par met ros de entrada y salida. Puede hacerlo medi ant e los elementos de mensaje. En este elemento, se concede un n ombre a cada mensaje; y en un mensaje, se describe ca da par met ro (nombre y tipo de datos);

606

<inessage part

ame

P Laylnput " e 1 ement = ' x sd :s t. rm q ' /

ame- " opponen t ame "

</mes s age> <message ame n ame =" P 1ayOutput" >

< part

Result ' t yp e = ''x s d :s t r in g "/

< "/mes s age'>

A continuacin puede asociar los mensajes con el punto final de destino u s a n do un elemento portType. En portType. se usa el nombre que asign a este punt o final de destino en el elemento port: y por cada uno de los serv icios Web. crea una etiqueta de operaci on que contiene un elemento input y output que el mensaje usa como atributo:
<portType name; ="GameWSSoap" > < o p e r a 1 1 o n n ame -"P 1 a y "> < m p u t mes s a ge - " P 1a y Input " / > <output message = "PlayOutput " / > < / op e ra 1 1 on > / por t T y p e >

Por ultimo, el elemento b ind ing describe los detalles especficos i mp o rt an tes del mecanismo de t ransporte usado. Un enlace SOAP. por ejemplo, debe es pe cificar la accin de SOAP:
c b i n d m g name-"GameWSSoap" type-"s :GameWSSoap" > < s o a p :b i n d i n g transpor t-"http: //s chemas .xmlsoap .org/.soap/http" st y1e = "docum en t" /> <operation name="Play"> <soap:operation s oapAction-"h t t p ://w w w .b o u t q u i n .com/ GameWS/Play" style="document" /> < input> <soap:body use="literal" /> < / input > < ou t p u t > <soap:body us e= " 1 1 1 e r a 1 " / .> < / output > < /o p e r a 1 1 o n > </bmding>

Cmo usar el Protocolo de acceso simple a objetos (SOAP)


S O A P es el dialecto de X M L usado por los servicios Web. Especifica qu acci n de ser vidor quiere i nvocar p a r a p a s a r la i nformaci n (es decir. los

607

p ar met ros ) al servicio Web. S OAP tambin especifica cmo se devuelve la in formacin desde el servicio Web (valores de devolucin y excepciones). Los mensajes S O AP siguen un formato estndar, un sobre externo que identi fica el mensaje como un mensaje SOAP . un cuerpo que contiene la principal carga til y un titulo opcional que ofrece informacin adicional sobre el mensaje Puede usar el ttulo par a p as ar informacin que no es una parte propiamente dicha de la invocacin del servidor. Por ejemplo, puede p as ar la fecha y hora de la solicitud o us ar autentificacion en este ttulo. El cuerpo contiene un elemento c u y o nombre co ncuerda con el nombre del mtodo del servidor que se esta invo cando. Los elementos s ecundari os de este elemento tienen nombres que concuerdan con los parmetros:
^?x mi versin-" 1 .0" encoclmg= "ut f - 8 " ? > < s o a p :E n v e 1ope x m l n s :x s i = " h 11 p :/ /w w w .w3.org/2001/XMLS c he ma - ins t a n e e " x m l n s :xsd =" h t t p :// w w w .w3.org/2001/XMLS c h e m a x m l n s :s o a p = " h t t p ://s chema s .x m l s o a p .o r g / s o ap /e nv e1o p e /">
'soap:Header>

- !- -La

informacin

adicional

se coloca

aqu

-->

^ / s o a p :H e a d e r > - s oap :Body Me t hodName > Pa r am 1ame >va le 1< / Pa r amlName >
P a r a m 2 a m e >va 1u e 2 < / P a r a m 2 N a m e > etc.

'/MethodlJame / s oap :Body." ' / s o a p :E n v e 1 o p e >

El mismo formato se usa para enviar una respuesta. Los nombres de parmetro (en este caso. P a r a m l N a m e y P a r a m 2 N a m e ) de la respuesta son. por s up u es to. los pa r m et ro s de salida; o "devolucin" cuando el mtodo slo dev uelve un valor (por ejemplo < re t ur n>v al ue < /return>). Cuand o se produce algn error, la i nformacin del error se enva de vuelta en una seccin de errores. La seccin de errores se encuent ra en el cuerpo SOAP:
' s o a p :Fault > 'faultcode>xOO</faultcode> < " fa u l t s t n n g > d e s c r i p t i o n < f a u l t s t r m g > 'ru n c o d e > Y e s < r u n c o d e >

'"/s oap : Fau 1 1 >

608

Cmo crear servicios Web con Visual Studio .NET


La operacin de crear (y. en la siguiente seccin, acceder a) un servicio Web usando Visual Studio N E T es aparent emente simple. Ni siquiera sera consciente de estar usando XML. El servicio Web que crearemos en esta seccin simplemente recuperara y mos t rara una lista de libros. Esto simula la funcin de catlogo de una pagina Web comercial, aunque en el mundo real probablement e deseara introducir categoras p ar a evitar que se devolviera una enorme lista de libros. Dado que el objetivo de este captulo es mo st rar los elementos necesarios par a construir un servicio Web. el aspect o comercial ha sido simplificado. El ejemplo que creamos aqu usa una tabla y un procedimiento almacenado. El codigo par a crearlos aparece en el siguiente ejemplo (quizs tambin quiera colo car algunos datos de mues tra en la tabla Books):
CREATE TABLE [Books] ( [ISBN] [char] (14) NOT NULL , [Title] [varchar] (150) NOT NULL [ Pn ce ] [money] NOT NULL

)
GO ALTER TABLE [dbo] . [Books] WITH NOCHECK ADD CONSTRAINT [PK Books] PRIMARY KEY CLUSTERED

(
[ISBN] ) ON [PRIMA RY ]

GO
CREATE PROCEDURE [pc g e t Boo ks ]

AS
SELECT [I S B N ] , [Title], [Pnce] EROM [Books] GO

Ya esta pre para do par a construir un sencillo servicio Web que devuelve una lista de libros usando el procedimiento almacenado: 1. 2. 3. Abra Visual Studio N E T y seleccione Archivo>Nuevo proyecto. Seleccione Servicio W eb ASP.NET como el tipo de provect o en el c u a dro de dilogo Nuevo proyecto. Escriba BookSeller como nombre del provecto (vase la figura 27.2).

609

Proyecto pata crear servicios Web XML que se van a utilizar desde otras aplicaciones. Nombre: Ubicacin: | Boolie lle r | http://localhost Examinar... |

El proyecto se crear en http://localhost/BookSeller. ^ Ms | J ^ ^ A c e p ta r^ ^ J Cancelar | Ayuda |

Figura 27.2. Un servicio W e b es un tipo de proyecto

4. 5.

Renombre el servicio We b de Servicel .asmx a Books .asmx. Cambi e a Vista de cdigo haciendo clic en la ficha Books .asmx .es y cambie todas las apariciones de Servicel a Books (figura 27.3).
B o o k s e lle r - M ic ro so ft Visual C # .NET [d is e a r ] * B o o k M s n w x f * Archivo oP* n ^er Proyecto X generar depurar Herramientas <P * I C.ebu, Ventana Ayyda ollbact. ^ x t >;

't e .=

A*

Bo o k i.a sm K .e s * | B n n,. -J |

: ;

Exploractor de soluciones i II [ ^ +

8...

n
BookSeller . 4 Pr-fefPin

.>

Solucion 'Bijuiieliei' i

1 pnjvec'ii

As-ieniblvlrih.'.!.-$j] Books.asmx

* 1 Book 3eller.vsdis..:c
i B n o f c .W l* ! v*] global, asa. '"Vet M.inhg

J l) i l 1 .'

..I.

-t C Ir . tift J i . . i-r L' V 1 L ' r . M'.'L --

t
Propiedades ^ x

I !! ; ; E

i t ;

'
i

1n i

f i

= t1 i

~e 1 ' 'inp'i'iierif: ( i ;

1 1 1
-

< 1
Listo

1 ! Ln 14

in Jj
Col 23 Car 20

!INS j

Figura 27.3. Puede cambiar el nombre del servicio por defecto a uno ms descriptivo

6.

Cambi e la seccin using p ar a que contenga lo siguiente:


us ing using S ys t em; S y s t em .W eb .Services ;

610

using using

System.Data; S ys te m . D a t a .OleDb;

7.

Agregue los siguientes m todos y propiedad a la clase Books:


private static string oleDbConnectionStrmg

{
get

{
// NOTA: Usar la cuenta sa en aplicaciones de p r oduc cion // es, obviamente, una practica muy desaconsejable. Ademas, dejar la // contrasea para la cuenta sa en blanco es igualmente m a d m i s ib le . return "Provider = SQLOLEDB. 1; " +"User ID=sa;Initial Cat alog-WebService_1_0_0;Data Source = localhost;

} }
// EJEMPLO DE SERVICIO WEB [WebMethod] public DataSet getList()

// Establece las cadenas de instruccin SQL string strSQLSelect = " [pc_getBooks ] " ; // Crea objetos OleDb OleDbConnection databaseConnection - new 01 eDbConne ct i on ( o le Db Co nn ec ti on St nn g) ; OleDbCommand selectCommand = new OleDbCommand(strSQLSelect, databaseCo n ne ct io n) ; OleDbDataAdapter dsCmd = new OleDbDataAdapter () ; DataSet resultDataSet = new DataSet ( ); // Estamos trabajando con un procedimiento almacenado (es decir, NO con un instruccin SQL) s e 1ectC o m m a n d .CommandType = C om ma n d T y p e .StoredProcedure ; try

{
// Establezca la conexin a la base de datos d a t a b a s e C o n n e c t i o n .Open () ; // Ejecute SQL Command d s C m d .SelectCommand = selectCommand; int numRows = d s C m d .F i l l (resultDataSet, "Books");

}
catch (Exception e)

611

Consol.WriteLine ("****** e.Message);

Caught

an

exception:\n{0) ",

}
f in a 11y

(
d a t a b a s e C o n n e c t i o n .C 1 ose ( );

1
return resultDataSet;

} La propiedad oleDbConnectionString contiene la cadena de c o nexin a la base de datos S QL Server. En cdigo de produccin, puede usar una cuenta con derechos de seguridad apr opiados (y una contrasea) en lugar de la t odopoderos a cuenta "sa". El mtodo getList ( ) abre una conexin a la base de datos SQL Server y recupera un conjunto de datos que contiene la lista de libros invocando al comando pe getBooks. Com o puede ver. us ar A D O . N E T es muy sencillo. 8. !Eso es todo! Tambi n puede agr egar a la clase una declaracin de espacio de nombre, como mues tr a el siguiente ejemplo:
[WebService(Namespace="h t t p :/ / m i c r o s o f t .co m/ we bs e r v i c e s / ")] public class Books : S y s t e m. We b.Services.WebService

Los espacios de nombre son un modo de evitar la duplicidad de nombres. Se usa un nico prefijo p ar a distinguir entre servicios We b con el mismo nombre. Por lo general, se usan direcciones URL como base p a r a estos nombres nicos. Esto est en concordancia con el modo en que se usan las URL en los espacios de nombre X ML . como se describe en el apndice. 9. Gua rde el provecto y pulse F5 p ar a c ompr oba r el servicio Web.

Ahora que ha creado un servicio Web. intente crear una aplicacin cliente que use este servicio Web.

Cmo usar Visual Studio .NET para acceder a un servicio Web


El siguiente ejemplo muest ra los pasos necesarios p ar a crear una aplicacin de servicio We b en C#: 1. 2. 3. Ab ra Visual Studio N E T y seleccione Archivo>N uevo proyecto. Seleccione Aplicacin W eb ASP.NET como el tipo de provecto. Dle al provecto el nombre BookRetailer.

612

4. 5.

Seleccione Proyecto>Agregar referencia Web. Ha g a clic en Referencias W eb en Servidor local para que Visual Studio N E T detecte a ut omt i came nt e los servicios We b disponibles en el servi dor local.

6 . Sel ecci one http: / / l o c a l h o s t / B o o k S e l l e r / B o o k S e l l e r .vsd iseo y haga clic en A g r e ga r referencia.


Ha importado la informacin necesaria p a r a llamar a este servicio Web. 7. En el modo Diseo, agregue un control Babel a la parte superior de la pgi na y un control DataGrid bajo de la etiqueta y cambie a la vista de cdigo. Agregue una declaracin using a la pgina AS P. NET: esto indica al compi lador que va a usar el cdigo del servicio Web.
using BookReta 1 1e r .1oc al ho st ;

8.

9.

Agregue el siguiente cdigo al mtodo Page Init. En este ejemplo, se establece el texto Labe! v luego se rellena el DataCirid de un modo rpido y sencillo (esta pgi na no g a n ar ningn premio por su apariencia):
prvate void Page Init(object sender, EventArgs e)

{ //
// CODEGEN: ASP.NET Windows // 11a m a d a . Form Designer necesita esta

//
Ini1 1 al izeComponent ( ); // Agregado por PGB Label'l.Text = "Available

Books";

Books books = new B o ok Re ta il er .l o c a lh os t.Books ( ); DataSet bookList = b o o k s .getList ( ); DataGridl.DataSource = b o o k L i s t . T a b l e s [ " B o o k s " ] .D e f a u l t V i e w ; DataGridl .D a t a B m d ( ); // Fin de la adicin PGB

} 10. Gu ar de y ejecute el proyect o (utilice F5 como tecla de mtodo abreviado). Aparecer una pantalla como la que se muest ra en la figura 27.4. Reflexionemos sobre lo que hemos logrado. Hemos creado un servicio Web (que puede ejecutarse en un servidor conectado a Internet). En esta seccin, cre una pgi na We b (que puede ejecutarse en un servidor diferente) que usa este servicio We b p a r a recuper ar una lista de libros del primer servidor.

613

_-J j5 ] x j Archivo Edicin Ver Favoritos * ] Herrarrtenfcas |'; Ayuda ' Favoritos Multimedia

'

Direccin | j

i h . j l . B r m l R e i i i e r A vu i r n la . p y h p a
- t if

Bsqueda

'

%
d a Vnculos

V i U U r P-. -I-

I . ' P H
9 1

T i t l e
m A i- t i'. 'ii 9

T ' n r r
_ -;9

9' J

r/.y

X M T .P vB i o m p l e

J4 99

1 i.ii .i -; 11 U l ' l v t f i l . . l i d i a n . 4 9 9 9

<1 - )

U 5 t 0

Intranet local

Figura 27.4. Un servicio W e b en funcionamiento, tras haber recuperado una lista de libros del proveedor de servicio W e b

Resum en
En este captulo ha estudiado los estndares X M L que hay tras los servicios Web. Vimos las dos tecnologas opcionales que toman parte en la definicin de servicios Web: UDDI par a el mecani smo de descubrimiento y W S D L par a la descripcin de servicio. Tambi n est udi amos el for mato de mensaje que se usa durante la invocacin real de un servicio Web: SOAP. Creamos un sencillo servi cio We b us ando Visual Studio. Por ltimo, creamos un segundo provecto que u sab a el servicio We b que haba construido anteriormente.

614

EE1 28 Cmo usar C# en ASP.NET

La llegada de Internet v las intranets corporat ivas han llevado al desarrollo de las aplicaciones distribuidas. Una aplicacin distribuida puede acceder a la infor macin de diferentes fuentes de datos que pueden estar dispersas en varias locali zaciones geogrficas. Visual Studio N E T lleva las aplicaciones distribuidas a nuevos niveles al permitirle us ar serv icios We b y clientes de servicios Web. Los servicios Web de A S P . N E T son servicios basados en X M L que estn expuestos en Internet y a los que tienen acceso otros servicios Web y los clientes de servicios Web. Un servicio Web muest ra mtodos Web a los que tienen acceso los clientes del servicio Web. que implementan la funcionalidad del servicio Web. Antes de Visual Studio NET. la progr amaci n ASP se realizaba usando V B S c n p t Sin embargo, con la llegada de Visual Studio .NET. puede usar dos lenguajes para la programaci n ASP: Visual C# y Visual Basic NE T Visual C# permite escribir codigo A S P . N E T par a servicios y aplicaciones Web. Por ltimo, aprender a implementar la aplicacin Web mediante Visual Studio N E T En este captulo, aprender a usar C# para crear aplicaciones AS P. NET. Em pezaremos creando un serv icio Web en Visual C#. Tras ello, crearemos un cliente de servicio Web en C#. que en realidad es una aplicacin Web que usa el servicio Web.

617

Cmo crear un servicio Web


En Visual Studio NET. los servicios We b se usan p ar a integrar las apl icaci o nes remotas con sus actuales soluciones comerciales. En lneas generales, los servicios Web presentan dos ventajas: Puede usar un servicio Web de otra organizacin p ar a crear una aplicacin personal izada par a su empresa. Por ejemplo, puede usar el servicio de autentificacion de Microsoft Passport par a incluir esa autentificacin en su pgi na Web. Puede beneficiarse de este provecto porque no necesita c r e a r la i n f r a e s t r u c t u r a n e c e s a r i a p a r a i m p l e m e n t a r a ut e n t i f i c a c i n personal izada en su pgina Web. Adems, su pgina podra atender a un may or numero de v isitantes porque todos los usuarios registrados con el servicio Passport (lo que incluye a todos los usuarios de Hotmail y M SN) podrn conectarse a su pgina Web. Tambi n puede utilizar los servicios We b p ar a comuni carse con sus c o m paeros de empresa. Por citar un ejemplo, imagine un vendedor de libros que tenga libros de varios editores. Si cada editor puede hospedar un servi cio We b que p ropor ci ona informacin sobre los ltimos libros que ha p u blicado. el vendedor puede desarrol lar un cliente de servicio We b que se conecte a estos servicios Web y recupere datos de estos libros. A continuacin vamos a crear un serv icio We b que usa una base de datos Por tanto, en el primer paso aprender a crear una base de datos p ar a el servicio Web. A continuacin, aprender a usar la base de datos y a crear el servicio Web

NOTA: Al crear el servicio Web de este ejemplo, nos concentraremos slo en las tareas necesarias para crearlo. Para aprender ms sobre los concep tos que intervienen en la implementacin de servicios Web, consulte un captulo anterior.

Cmo crear una base de datos para un servicio Web


Los servicios o aplicaciones Web suelen emplear una base de datos p ar a a l m a cenar sus datos pertenecientes a la aplicacin. En un entorno empresarial, las bases de datos, como Microsoft SQL Serv er y Oracle, estn muy preparadas para gestionar datos. En el servicio Web que creara en este captulo se usa una base de datos SQL Server. Antes de crear la base de datos de SQL Server y las tablas para el servicio Web. revise los conceptos mas importantes del Sistema de gestin de bases de datos relacinales ( R DB MS ) .

618

Conceptos del sistema de gestin de bases de datos relacinales


Un sistema de gestin de bases de datos relacinales ( R D B M S ) es adecuado par a las soluciones de negocios empresariales. Un R DB MS . como Microsoft SQL Server. Oracle o DB2. permite la creacin, actualizacin y administracin de bases de datos relacinales. Una base de datos relacional es una coleccin de datos organizados en forma de tablas. Las aplicaciones pueden acceder a los datos de las tablas usando instrucciones de lenguaje de consulta estructurado (SQL). En un R D BM S. puede acceder a datos y reorganizarlos sin reorganizar toda la base de datos. Esto mejora considerablemente el rendimiento de la base de datos. Ademas, puede apl icar fcilmente reglas de negocios, validaciones y res tricciones a los datos de las tablas de un R D BM S. Las reglas empresariales y las v alidaciones g ar ant izan la integridad de los datos. Por ejemplo, cuando se inscri be a un pasajero en un vuelo con el sistema de reservas de una comp a a aerea, debe existir el nmero de vuelo especificado. Puede det er minar el numero del v uelo estableciendo una regla de negocio y us ndol a al reserv ar el billete.

Tipos de datos de SQL Server


Los datos de una base de datos se al macena en tablas, como filas y columnas. Las columnas de una tabla al macenan informacin clasificada, como el numero de identificacin del producto, su nombre y el numero de unidades disponibles. Las filas de una tabla al macenan registros especficos. Cada columna de una tabla tiene un tipo de datos especfico. La tabla 28.1 describe algunos de los tipos de datos S QL Server mas comunes.

Tabla 28.1.
T ip o d e d a to
inte ger Fl.oat char (n )

S Q L D a ta T y p e s

D e sc rip ci n

Se usa para almacenar nmeros enteros. Se usa para almacenar nmeros decimales. Se usa para almacenar datos de caracteres que pue den ser alfabticos, numricos, caracteres especiales, como #, % o $, o una combinacin de letras y caracte res. Un tipo de dato char almacena un solo carcter. Para almacenar ms de un carcter se usa char m), donde n hace referencia al nmero de caracteres que se quieren almacenar. Se usa para almacenar datos de caracteres, donde n hace referencia al nmero de caracteres que se quie ren almacenar. Un tipo de dato v ar cha r es diferente de un tipo de datos char porque la memoria asignada

va rc h ar (ni

619

Tipo de dato

Descripcin

a un tipo de datos varchar depende del tamao de los datos, a diferencia de los tipos de datos char, en los que la memoria asignada est predefinida. Datetime
Money

Se usa para almacenar datos de fecha y hora. Se usa para almacenar datos monetarios que requie ren gran precisin.

TRUCO: Cada tabla debe tener al menos una columna que identifica unvocamente una fila (a la que llamaremos registr) de la tabla. Esta columna es la clave primaria de la tabla. Por ejemplo, la columna ProductlD de una tabla Products identifica cada fila unvocamente y por tanto es la clave primaria. No puede haber dos valores iguales en una clave primaria.

Cmo crear bases de datos y tablas


En Microsoft SQL Server, se pueden crear bases de datos, tablas, procedi mientos almacenados y consultas usando T r a n s a c t - S Q L (T-SQL).

TRUCO: Tambin puede usar SQL Server Enterprise Manager para crear una base de datos y tablas. SQL Server Enterprise Manager proporciona una interfaz grfica para realizar los mismos pasos que realizamos median te las instrucciones T-SQL.
Para crear una base de datos o una tabla mediante T -S QL. se emplea la ins truccin Create. Por ejemplo, par a crear una base de datos Sales, escriba el siguiente codigo en la ventana del a na li zador de consultas:
C rea t .e Datab a s e .Sales

Tras crear la base de datos, puede agregarle tablas. Agregue la tabla Products a la base de datos Sales mediante la siguiente sintaxis:
Create Table Products Key,

(
ProductlD VarChar (4) Primary ProductName VarChar (20), UnitPrrce Integer, QtyAvailable Integer

620

Cmo recuperar datos


Puede re cu per ar informacin al ma c en ad a en tablas usando la instruccin S e l e c t . Por ejemplo, p ar a recuper ar todos los registros de la tabla Products de la base de datos Sales, use las siguientes instrucciones: Use S a l e s
Select * From Products

Cmo insertar, actualizar y eliminar datos


Puede agregar, actual izar y eliminar datos de una base de datos de SQL Server siguiendo los pasos indicados a continuacin: Ag rega r un registro: Para agregar una nueva fila a una tabla SQL Server, use la instruccin Insert. Por ejemplo, para agr egar un nuevo registro a la tabla Products, se usa la siguiente instruccin:
Insert Into Products (ProductID, ProductName, QtyAvailablc) Values ( 'P 0 0 1 ' , 'Baby Food', 2.5, 12 0 0 0) Unit P n c e ,

ADVERTENCIA: Para que la insercin tenga xito, los valores de la co lumna deben proporcionarse en el mismo orden que las columnas de la tabla. Adems, si el tipo de datos de una columna es c h a r , v a r c h a r o d a t e t im e , debe especificar los valores entre comillas.
Modificar un registro: Para modificar un registro de una tabla SQL Serv er, use la instruccin Update:
Update Products Set U n i t P n c e = 75 Where ProductID="P 0 10 "

El anterior cdigo actualiza el precio por unidad del registro cuya identifi cacin de producto es P010 hasta 75. Eliminar un registro: Para eliminar un registro de una tabla, use la ins truccin De le te. Por ejemplo, p ar a eliminar un registro de la tabla Products con la identificacin de producto P01 1. puede especificar la si guiente instruccin:
Pelete From Products where ProductID="P 0 11"

Cmo usar procedimientos almacenados


Un pro ced im iento alm acena do es un conjunto de instrucciones SQL usadas par a realizar tareas especficas. Un procedimiento al macenado se aloja en un Servidor SQL y puede ser ejecutado por cualquier usuario que tenga los permisos

621

adecuados. Puede crear un procedimiento almac enado usan do la instruccin Create Procedure. Use el siguiente cdigo p ar a cr ear un procedimiento al macenado que acepte Product ID como p ar met ro y devuelva el precio por uni dad del registro que concuerde con el ProductID:
Create Procedure ProductPrrce (0id char (4))

As
Select U m t P r i c e From Products Where R eturn ProductID=@id

El procedimiento requiere un parmet ro. @id. en el moment o de la ejecucin. Los procedimientos al macenados son par ticularmente tiles cuando se necesi ta realizar varias tareas consecutivas en una base de datos. Por ejemplo, cuando quiere cancelar la reserva de un pasajero, querr calcular la tarifa que debe de volverse al cliente y b orr ar su reserva de la tabl a de reservas. Al mismo tiempo, tambin deber actual izar el estado de los otros pasajeros que puedan estar en lista de espera para entrar en la lista de pasajeros. En lugar de especificar cons ul tas de SQL cada vez que quiera cancelar una reserv a. puede us ar un procedimien to al macenado para cancelar la reserva de un pasajero.

ADVERTENCIA: Cada procedimiento almacenado debe terminar una ins truccin R etu rn .
Para ejecutar el procedimiento anterior para que muestre el precio del p r o du c to con la identificacin ID P010. use el siguiente cdigo:
E : :ecute ProductPrice "P010"

Cmo crear la estructura de la base de datos


En este captulo, necesitamos crear una base de datos Sales para nuestro servi cio Web. Tras crear la base de datos Sales, agregue una tabla Products a la base de datos. Para crear una base de datos Sales y aadirla la tabla Products, siga los siguientes pasos: 1. 2. Seleccione lnicio>Programas>M icrosoft SQL Server>Query Analyzer. Se abrira el cuadro de dialogo Connect to SQL Server. En el c ua dro de dialogo Connect to SQL Server, escriba el nombre del servidor SQL en el cuadro de texto SQL Server, especifique un nombre de cont act o en el cuadro de texto Login ame y especifique la c on tr as e a para el nombre de contacto en el cuadro de texto Password. Ha ga clic en OK para conectarse al SQL Serv er y a br a el editor de consul tas.

3.

622

4.

En el editor de consultas, introduzca las siguientes instrucciones para crear la base de datos Sales y agr egar la tabla Products a la base de datos:
Create database Sales

GO
Use Sales Create Table Products

(
ProductID VarChar (4) Prrmary Key, ProductName VarChar (20), UnitPrice Integer, QtyAvailable Integer

)
GO

5. Seleccione Q uery>Execute para ejecutar la consulta.


Tras ejecutar la consulta, la estructura de la base de datos esta creada. Ahora estamos listos para crear el servicio Web (la primera de las aplicaciones ASP.NHT que creara este captulo). El s e n icio Web que se crea en este captulo agrega registros a la tabla Products de la base de datos Sales que creamos anteriormente en esta mi sma seccin.

Cmo usar la plantilla Servicio Web ASP.NET


Debe usar la plantilla de provecto Servicio W eb ASP.NET para crear un servicio Web. Este prov ecto sirv e como plantilla basada en la Web para crear los componentes del serv icio Web. Para crear un serv icio Web. siga estos pasos:

1. Seleccione Archivo>Nuevo>Proyecto par a abrir el cuadro de dialogo Nuevo proyecto.

TRUCO: Puede pulsar simultneamente las teclas Control-Mays-N para abrir el cuadro de dilogo Nuevo Proyecto.
2. 3. 4. Seleccione Proyectos de Visual C# de la lista Tipos de proyecto. Seleccione Servicio W eb ASP.NET del cuadro de plantillas a la derecha del cua dro de dialogo En el cuadro Nombre, escriba OrdersWebService. En el cuadro U b i c a c i n . i n t r od u zc a el no mb re de su s er vi do r We b como htt.p:// <nornbredeservidor>. Haga clic en A c e p t a r .

TRUCO: Tambin puede escribir localhost en el cuadro Ubicacin si el servidor Web est instalado en el equipo en el que est creando el servicio Web.

623

NOTA: Puede que tenga que esperar bastante tiempo mientras Visual Studio .NET crea el servicio Web.
Una vez que Visual Studio N E T ha creado el serv icio Web. puede c onf igur ar lo par a que gestione datos en el servidor. Esto lo haremos en la siguiente seccin.

Cmo agregar controles de datos al servicio Web


Debe agr egar controles de datos al serv icio Web par a permitir la c om un i ca cin con la base de datos Sales que creo en el anterior apartado. Para comunicarse con la base de datos, debe agr egar los siguientes controles a su serv icio Web:

Sql DataAdapter: El control Sql DataAdapter se usa para t rans


ferir datos entre fuentes de datos.

SqlConncction y S q l D a taAdapter : Los controles SqlDataAdapter y SqlConnection se usan par a conectar con la origen de
datos.

5 1q 1Command: Tras establecer una conexin con el origen de datos, use el control OleDbCommand par a acceder a los datos. DataSet: Los datos se al macenan en un control Data Set.

Los pasos para agregar el control SqiDataAdapter son los siguientes: 1. 2. 3. 4. Seleccione Ver>Cuadro de herram ientas par a abrir el cuadro de her ra mientas. En el cuadro de herramientas, haga clic en Datos para activar la ficha

Datos.
Arrastre el control SqiDataAdapter desde el c ua dro de herrami ent as hasta el Diseador de componentes. Al ar r as tr ar el control SqiDataAdapter desde el c ua dro de h er r am ien tas. se inicia el asistente p ar a la configuracin del ad apt ad or de datos En la pantalla de bienvenida del asistente, haga clic en Sigui ente. Ap arece r el cuadro de dialogo Elegir la conexin de datos del as i st en te. como se ilustra en la figura 28.1. Haga clic en Nueva conexin para crear una nueva conexion usando el controlador OieDbDataAdapter. Se abr ir a el cuadro de dialogo Propiedades de vnculo de datos. Por defecto, este c ua dro de dilogo tiene seleccionada la ficha Conexin. Es pecifique el nombre del servidor SQL en el cuadro de dilogo Seleccione

6.

o escriba un nombre de servidor.

624

"tTS*
E l e r j i r Id r o n e x i n n d o d a t o s

a)

E 'a d a p ta d o rd ed a to se ie cu ta ra,w-i ilta s c a rg a r ya c tu a liz a rd a to ;.


Elegir en la lista de con ex io ne s de da to s que e s t n a c tu a lm e n te en el E xp lo ta d o r de s e rv id o re s o a g re g a r u n a n u e v a c o n e x i n si la qu e de s e a no ap a re ce en la lista

k
\

Qu conexin de d ato s d eb e ra u tiliza r el a d a p ta d o r de datos?

N ue va c o n e x i n ..,

C ancelar

= ; A tr s

Figura 28.1. El cuadro de dilogo Propiedades de vnculos de datos

7.

Seleccione el nombre de usuario y la cont rasea para conectarse al servi dor SQL Serv er y seleccione la base de datos Sales en la lista desplegable Seleccione la base de datos en el s ervidor La figura 2K.2 muestra la pantalla Propiedades de vnculos de datos completa. Haga clic en Aceptar
fe Propiedades de vinculo de
Proveedor Lonexion j A vanzadas | T odas |

x.

Especifique lo siguiente para conectarse a datos de SQL Server: 1. Seleccione o escriba un nom bie de servidor. | n PANDE Y D I 85 jj] Actualizar |

2. Escriba la informacin para iniciar sesin en el servidor: Usar la seguridad integrada de W indow s NT Usar un nombre de usuario y una contrasea especficos: Nombre de usuario. :a

W 3. (

Contrasea en blanco I' Permitir guardar contrasea

S eleccione la base de datos del servidor.

' A djuntar archivo de base de datos corno nombre.

J
Probar conexin

Aceptar

Cancelar

Ayuda

Figura 28.2. Conecte con el origen de datos usando el cuadro de dilogo Propiedades de vnculo de datos

625

8. l).

El a da pt ado r de datos que ha configurado apa rec er en el cuadro de di al o go Elegir la conexin de datos. Ha ga clic en Sigui ente para continuar. Se abrir el cuadro de dilogo Elegir la conexin de datos. Para usar una consulta SQL par a recuperar datos de la base de datos, mantenga la opcin por defecto. Usar instrucciones de S Q L y haga clic en S ig u ie n te

10 Se abr ir el cuadro de dialogo G enerar las instrucciones SQL. En este cuadro de dialogo, escriba la consulta Select * from Products y haga clic en Siguiente 1 1. Se abr ir el cuadro de dialogo Ver resultados del asistente. Este c u a dro de dilogo resume las opciones que ha seleccionado en los anteriores cuadros de dialogo del asistente. Ha ga clic en Finalizar para dar por fina lizado el asistente de configuracin del a da pt ado r de datos. Tras compl et ar el asistente de configuracin del ada pt ado r de datos, el control S q l D a t a A d a p t e r esta configurado par a su aplicacin. Como se puede a p r e ciar en la figura 28.3. los controles sq 1 D a t a Adapter 1 y sqlConnect i o n l se han agregado a su aplicacin.
46 OrderWebSenrice - Mcrosoft Vtaoal C# JCT [dtotMr] Archivo Edicin Ver Proyecto Generar Depurar Datos Ventana Ayuda

-ifli * i * i*
o:--'-

_ P
Datos

U&
^ S e rv ic e l.a s m K .c s [D is e o ]* ' Propiedades J s e r v ite l

- ?
' ]

Cuadro de herramientas

. .-ren'. '"-e t -~e;

I * ' L i n t e r . i
^ DataSet ^ ^ OleDbDataAdapter ijIeDhConnectinn OleDb'Iomrnand SqlDataAdapter SqlConnection

[: : > [m]-/
0
El (Mme) Serv e l

f; %

Q f DataView

Componentes Windows Forros Anillo del Portapapeles General Listo

datS.; , oler'bO jnnectionl

Figura 28.3. Los controles s q lD ataA da p te rl y sqlConnection 1 se han agregado a su aplicacin

A continuacin, agregue el control SqlComm and al s e n icio Web. El control Sq" Cornmarid se usa par a especificar comandos que necesitan ser ejecutados en

626

el origen de datos. Siga estos pasos p ar a agr egar un control SqlCommand a su aplicacin: 1. 2. Arrastre el control SqlCommand desde el cuadro de herramientas al di seador de componentes. Abra la ventana Propiedades y seleccione sqlConnect ionl para la propiedad de conexin del control SqlCommand.

A continuacin, debe generar un conjunto de datos para a lmac en ar los datos que recuperen los controles de datos:

1 . Para generar el conjunto de datos, seleccione el control SqlCommand 1


que ag r eg en los p a s os a nt er i or es y s el ecci one la o pci on de men

Datos>G enerar conjunto de datos


2. Se abrir el cuadro de dilogo G enerar conjunto de datos. En este cuadro de dialogo, va esta seleccionada la tabla Products de la base de dat os. S el ecc io ne la c as il l a A g re g a r este c o n ju n to de datos al diseador y haga clic en Ac eptar par a generar el conjunto de datos y agregarlo al diseador de componentes.

Los cuatro controles que ha agregado al servicio Web ahora son \ sibles para el di seador de componentes. Ahora necesita codificar los mtodos del servicio Web. como ver en la siguiente seccin.

Cmo codificar el servicio Web


Tra s agr egar los controles de datos al servicio Web. debe codificar los mt o dos del s e n icio Web. En este capitulo le enseamos a codificar un mtodo para agr egar productos a la base de datos Products mediante el servicio Web. Antes de proceder a codificar los mtodos del servicio Web. adales una descripcin y cambie el espacio de nombres por defecto del servicio Web. La descripcin y el espacio de nombres del servicio Web permiten al desarrollado!' del cliente del servicio Web entender el modo de empleo del s e n icio Web. Para agr egar una descripcin y ca mbi ar el espacio de nombres por defecto asociado al servicio Web. siga estos pasos: 1. 2. 3. Haga doble clic en el diseador de componentes para abr ir el editor de cdigo. En el editor de cdigo, localice la instruccin p u b l i c c 1 a s s S e r v i c e ! . Agregue el siguiente cdigo antes de la instruccin que localizo en el s e gundo paso:
|WebServico ( N a me s p a c e - "h t t p :/ / S e r v ic o U P .L . c o r u/p r o d u r r s / " , De s c r p t i 0 1 1 - "U s e t h e servicio We b t o acicl p r o d u c t o f n t h e
S a 1e s d a t a b a s e . ") ]

627

Tras introducir la linca de cdigo anterior, el espacio de nombres del servicio We b es http : //ServiceURL .com/products / y se ha agregado una d es cripcin al servicio Web. A continuacin, escriba el cdigo par a agregar productos a la tabla Products. Este codigo necesita escribirse justo debajo de la declaracin del serv icio Web. El codigo del mtodo Add Product, que agrega detalles del producto a la tabla Products, es el siguiente:
[ W e b M e t h o d (Description="Speci y the product ID, product name, unit price, and quantity to add it to the Sales catalog")] public string AddProduct(string PID, string ProductName, m t Price, m t Qty) t ry

{
P r o d u c t N ame = P r o d u c t N a me .T r 1 m () ; i P rice "i )) return "Please specify a valid value for price"; if (Qty 0 i return "Please specify a valid value for quantity"; s q 1C o n nect ion 1 .Open ( ); s q l c o m m a n d 1.CommandText = "INSERT INTO Products (Product ID, ProductName, UnitPrice, Qt yA varlable) VALUES ('" + PID f ProductName + + Price + + Qty

+ " ' )";


s q l C o m m a n d 1.E x e c u t e N o n Q u e r y (); s q 1C o n ner:t ion 1 .Close ( ); r e turn " Peco r c l updat ed successfully " ;

)
cato : h E c e p 1 1 on ei

I
return e.Message;

) ) El codigo anterior usa el control sqlConnectionl para agregar un regis tro a la tabla Products. Al agregar registros a un servicio Web. se usan los valores que la funcin AddProduct proporciona como parmetros. Mientras c o d i f i c a d mtodo Add Product del servicio Web. puede codificar otros mtodos par a recuperar detalles de producto de la base de datos Products o realizar otras acciones personalizadas. Para p robar el serv icio Web tras agregarle los mtodos, siga estos pasos:

1. Seleccione G enerar>G enerar solucin par a generar el servicio Web.


2. Para emp ez ar a depu rar el servicio Web. seleccione la opcion de menu

Depurar Hniciar.
El serv icio W'eb se abre en Internet Explorer. El primer cuadro de dilogo muestra los mtodos que codifico par a su servicio Web.

628

Para co mp ro b ar ci mtodo AddProduct. siga estos pasos: 1. 2. Ha g a clic en A d d P r o d u c t en el cuadro de dilogo Servicio We b Service 1. Se abrir el cuadro de dialogo AddProduct. como muestra la figura 28.4. En este cuadro de dialogo, puede invocar la funcin A d d P r o d u c t tras proporci onar los parmetros requeridos para p robar su resultado
...... ..................................................................................... .... Archivo Edicin Ver x Direccin 11 j ht> F avoritos Herram ientas ,

Ayuda

........

...
Multimedia i . " 1 zJ k J Ir

jo jis j

t*
Favoritos

Bsqueda

,J! *,> ir d tf. W e t> $ * v K * ^ e i7 -"1 .] i,v.

Vnculos B

Service 1
AddProduct
1e s t

^ :i

! "

I - v o l- e

; !

SOAP II-..-- t, <j * 1 r.,- .. .I -..11 !, - . IA F i.- .ju e c t l> 1<n f h n 1ci - r s -.

1 t

J
In tra n e t
local

Figura 28.4. Especifique los parmetros para la funcin AddProduct para co m p ro b arla

3.

Escriba P0 02. PDA. 100 v 2 00 como los p ar me tr os p ar a el P1D. Product Name. Price v Qty respectivamente y haga clic en I n v o k e para probar su resultado. C uando se logra agregar el registro al servicio W'eb. se consigue un resul tado como el que se muest ra en la figura 28.5.

4.

Tras p robar su servicio Web. puede crear un cliente de servicio W'eb para acceder al servicio Web.

Cmo crear un cliente de servicio Web


Un cliente de servicio Web de A S P . N E T es una aplicacin W'eb compuesta por uno o ms We bFor ms . En esta seccin, vamos a cr ear una aplicacin Web A S P . N E T que accede al servicio Web creado en la anterior seccin

629

h ltp ://n p a n d e y-d 1 8 5 /O id e iiW e b S e iv ic e /S e iv ic e 1 .a s a n /A d d P ra d llo t


Archivo Edicin Ver Favoritos Herram ientas Ayuda

g o .

>

'

m i vl 1 ,5 ,1 ^ _ J

f
, Favoritos % a r Multimedia >; jj] Ir Vnculos

- O

X j

Z)

Bsqueda

Direccin | t] hrfp //'npandey d 1 35/ rder:V/eb'i. er vic e / S ervie e l a : m x/AddProduc"'PICi=P00 j;< Produc tN a m e=: dl^Pric e=9&0 hr=3

1
' i;

Record u p d at e d successfully

* * In tra n e t local

Figura 28.5. Este resultado se consigue cuando se logra agregar un registro a un servicio W e b

Para crear un cliente de servicio We b solo tiene que seguir estos pasos: l 2. 3. C ree un nuevo provecto de Aplicacin Web A S P . NE T. Agregue una referencia We b a la aplicacin Web. Implemente los mtodos del servicio Web en la aplicacin Web.

La siguiente seccin estudia detenidamente cada uno de estos pasos.

Cmo crear un nuevo proyecto de aplicacin Web ASP.NET


Para crear un provecto de aplicacin Web. siga esto pasos:

1. Seleccione la opcin de men Archivo Nuevo>Proyecto. Se abrir el cua dr o de dialogo Nuevo proyecto.
2. 3. En el c ua dro de dialogo Nuevo proyecto, seleccione la plantilla de p r o vecto Aplicacin ASP.NET de la lista Provectos de Visual C#. Escriba O r d e r s W e b A p p 1 i c a t . i o n como nombre del provecto v haga clic en A c e p t a r para crear la aplicacin Web.

630

Cmo agregar una referencia Web


Tr as croar el servicio Web. necesita agr egar una referencia Web al serv icio Web que cre en la anterior seccin. Al a gr egar una referencia Web. el cliente de servicio Web descarga la descripcin del servicio We b y crea una clase de proxy par a el servicio Web. Una clase de proxy incluye funciones p a r a los mtodos del servicio Web. Para agr egar una referencia We b al servicio Web. siga estos pasos: 1. Seleccione el for mul ar io We b W e b F o r m l . asp:-: y a continuacin selec cione la opcin de men Proyecto>Agregar referencia Web. Se abrir la opcion de men Agregar referencia Web. En el cuadro de dialogo Agregar referencia W eb. haga clic en R e f e r e n cias W e b en el vnculo Servidor W eb local. Eos servicios Web disponi bles en el s e r v i d o r W e b local a p a r e c e r n en la lista R e feren cias disponibles, como muestra la figura 28.6. En el cuadro de dialogo Agregar referencia Web. seleccione el vinculo al serv icio We b O r d e r s W e b S e r v i c e v haga clic en A g r e g a r r e f e r e n cia para ag reg ar una referencia al servicio Web.
_*J
U] Direccin: |li> tp ://l" c * lh r .a /d e f* # .v d is c .:.

2.

3.

J
Referencias

disponibles: ....

..........
" h tt p . / / l o c a l h o s t

"
e h S e rv ic e 1 /W e h S e r v it

S ervicios W eb

/W

G iu p o s d e le l e i e n c i a v i n c u la d o s h t tp : //lo c a lh o s t/U m v e r s a ll o y u n /U n iv e r s i

h t t p : / / l o c a l h n s t / W e h C l i e n t / W e b C l i e n t .v s

h t tp ://lo c a lh o s t/W e b A u th e n tic a tio n /W e b

....... ' !' .:

h tt p

:/ / l o c a l h o s t / W

in d o w s A u t h e n t ic a t io n /

h ttp : //lc jc a lh o s t /U s e r R e g A p p /U s e r R e g A p i

h t tp //lo c a lh o s t /G e t Q u e ry D a ta /G e t Q u e ry

h t tp : //lo c a lh o s t/O r d e r s W e b S e r v ic e /O r d e

- J - V _d- ..

. : '. '

...........

' -

h t t p : / / l o c a l h o s t / O r d e r s W e h A p p lic a t io n /C

< 1

d !
| Cancelar Ayuda

J
|

Figura 28.6. Los servicios W e b disponibles se muestran en el cuadro de dilogo Agregar referencia W e b

La referencia al servicio Web que se agrega aparece en el expl orador de s o lu ciones. Por defecto, recibe el nombre l o c a l h o s t . Puede cambi ar el nombre del

B O

servicio Web por un nombre de su eleccin. En la figura 28.7. recibe el nombre OSI
E x p lo ra d o r de soluciones - O r d .,. 9 X

-J 3
+ -

! j
wj|

s
(1 p ro y e c to )

lu r n jn W e b S e r v in e l'

O rd e r W e b A p p lic a tio n

Pt'l'erenC'rr* W e b F le le re n c e :

- fc SEfl
^ U rd e rW e b O e rv ic e ] R e le ie n c e rnap e rv n :e l 'v :d l <J] A "em hlylnt " r : .v j] Lilub-ai a:a;-: id e r:\'/e lW .p p lir.ilii-iri v d i o J t W e b r ni ,hg Z l etiF 'nm 1 3: p>.

Figura 28.7. Las referencias a servicios W e b aparecen en el Explorador de soluciones

Cmo implementar los mtodos del servicio Web


Para implementar los mtodos del servicio Web. necesita disear un WebForm. El We bFo rm acepta informacin que debe aadirse a la base de datos Sales. El WebFor m diseado para la aplicacin Web aparece en la figura 28.8.
| L a b e lM e s s a g e

IE

Add a new produc

i T ' . i l i h i J i r i g
l lb !

L a b e lM e s s a g e

[' L IL d u l
E o rderLolor Border':,ti.'le f: ,-,r,iF-r- ',,drh L ..L I... F r,.ih le ,i

H ergili W h in ,Je

19px

Submit

248px

_ l
Figura 28.8. Diseo de un W e b F o rm que acepta informacin de los usuarios

Para disear el formulario, puede agr egar los controles que aparecen en la tabla 28 2 Tras disear el WebFor m. escriba el codigo para el exento Cl ick del boton S u b m i t . Cuando el usuario haga clic en el boton S u b m i t . el codigo del evento C ! i r- r; liara lo siguiente:

632

1. 2.

Creara una instancia del s e n icio Web. Ll amar a al mtodo A d d P r o d u c t del serv icio Web. p as a nd o como parmet ros al W e b F o r m los v alores introducidos por el usuario.

Tabla 28.2.

Controles de formularios W eb

Tipo de control
Label

P ro p ied ad es cam b iad as


Se ha agregado seis etiquetas: el encabezamiento principal de la pgina, Product ID, Product ame, Price, Quantity y Message, respectivamente. Se ha cambiado el Id. de la ltima etiqueta a LabelMessage y se ha limitado su texto.
I D = PI D ID=Productame ID=Price ID=Quantity T D= S ubmi t Text=Submit 1

T e tBo TextBox T ex tBox Text Box Button

3.

Mos t ra r el valor devuelto desde el mtodo A d d P r o a u c t en la etiqueta


LabelMessage.

A cont inuacin se mu es tra el cdigo del evento Clic)-: del botn Submit que cumple las tareas indicadas anteriormente:

TRUCO: Para introducir el cdigo del evento C l i c k del botn Submit, haga doble clic en el botn Submit en la vista diseo.
private void Submit Click (object sender, System. EventArgs e, )

{
OSi.Servicel Webl=new O S I .Serv cel ii ; L a b e l M e s s a g e .T e x t = W e b 1.AddProduct (P I D .Te x t , P r o d u c t N a m e .T e x t , Convert.ToInt32 (Pr i c e .T e x t ) , Convert.ToInt32 (Quantity.T e x t ));

4.

} Seleccione Depurar>lnicio para ejecutar el servicio Web. El resultado de la aplicacin Web aparece en la figura 28.9.

Especifique valores en los cuadros de texto Product ID. Product Name. Pricey Quantity y haga clic en Submit. La aplicacin Web agr egar la informacin

633

re qu er id a a la bas e de dat os Sales y a p a r e c e r un m en saj e en la et iq uet a LabelMessage. como muestra la figura 28.10.
I 1 h tU > :/ / n D a n d e v 'd 1 8 5 / O id e rs W e fa A p p lic a lio n / W e b F o n * 1 .a t M M ic ro so ft Edicin Ver Favoritos x "j pj Herramientas i / Ayuda Favoritos et > F : ri 1 a :p>: Multimedia

...
, T

- p i x i

Archivo

!
: i J

'

Bsqueda p-

Direccin J j hftp ATipa ru d e y-d lV lJd e r y e t

:1-,1

113fir.r-

11

ir

Vnculos d

Add a nerv product


I 'lv i ll L t I I ' | P t - ".ui.t L I i r [ I J U iU ltltV |

......
S u b m it

zi
I Intranet local I J j

Figura 28.9. Este W e b F o rm muestra el resultado de la aplicacin W e b


1

I 1

h i l o :/ / n o a n d w -d l8 5 / O i d e i s W e b A p p lic a tio n / W e tiF o n > . a * p * - M g m m K 1 l l I W l T i i l l l r r ' 1 I T 1 W Edicin Ver T htip Favoritos x ] 2, Herramientas | , Ayuda Favoritos Multimedia ^

^ J n jx J

Archivo

9*
3

j
Direccin |

Bsqueda

\
jd O

'npandev-dl OS/Qfdei :WehApplic ^hon/Vv'ebFrm1 a:p>:

Ir

Vnculos

Add a newproduct
T 'i :lui: t H | p ijiu P t v J u L t W iU n e P n r, |i. ell fjhfirie:. | W

^U iU ititv

j jrjfi

S u b m it

p e r - r i ii| 'l t r ' i sin: c r s s fu lly

<!

1
Intranet local

2 i^

Figura 28.10. Puede agregar un registro a la base de datos Sales mediante la aplicacin W e b

634

Cmo implementar la aplicacin


El ultimo paso p ar a integrar varias aplicaciones de Visual Studio N E T es implementar la aplicacin que ha construido. Para i mplemcntar la aplicacin, puede usar uno o ms proyectos proporci onados por Visual Studio N E T Las siguientes secciones estudian la implementacin de proyectos pro po rci onada por Visual Studio N E T y describen los pasos necesarios p ar a i mplementar una apl i cacin A S P . N E T

Implementacin de proyectos en Visual Studio .NET


Visual Studio N E T proporciona cuatro tipos de provectos de instalacin P r o vectos Cab, Provectos de mdulos de combinacin. Proyectos de instalacin y Provectos de pr ogr amas de instalacin Web. La siguiente lista describe estos tipos de provecto: Proyectos Cab: Puede crear un archivo contenedor ( CAB) p ar a e m p a qu e t ar controles ActiveX. C uando e mpaquet a un control ActiveX en un ar chi vo CAB. el control puede des carga rs e desde Internet. Proyectos de mdulos de combinacin: Puede crear un mdulo de combi nacin p ar a los componentes de aplicacin que quiera incluir en varias aplicaciones. Por ejemplo, un control de servidor que haya creado puede ser e mp aq u et ad o como un proyect o de mdul o de combi nacin que puede incluir en proyectos de instalacin p ar a sus aplicaciones de Windows. Proyectos de instalacin: Puede usar un provecto de instalacin para e mp aq ue t ar aplicaciones de Wi ndows. Un proyecto de aplicacin crea un archivo Microsoft Installer (MSI) que puede usarse para instalar una apl i cacin en el equipo de destino. Proyectos de pro gramas de instalacin Web: Puede usar la plantilla Prov ec to de p r o g r a m a de i nst al aci n W e b p a r a una apl i ca ci n We b A S P . N E T o p ar a un servicio.

La siguiente seccin describe cmo crear un proyecto de implementacin para una aplicacin Web A S P. NE T.

Cmo usar un proyecto de implementacin para implementar una aplicacin


Los pasos necesarios par a implemcntar una aplicacin A S P . N E T son los si guientes.

635

En el Explorador de soluciones, haga clic en la solucin OrdersWebAppl ication. Desde el men eme r ge nt e que a p a r ec e , selecci one Agregar>N uevo proyecto. En el c ua dro de dilogo Nuevo proyecto que se abre, seleccione Proyec tos de instalacin e im plem entacin en el c ua dro Tipos de proyecto En el cuadro Plantillas, seleccione Proyecto de programa de instala cin Web. Escriba como nombre del proyecto W ebSetupDeploy y haga clic en A c e p t a r El nuevo provecto se agregar a la ventana del explorador de soluciones Por defecto, se abre el Editor del sistema de archivos p ar a el provecto de implementacin. El Editor del sistema de archivos le ayu da a agr egar archivos al provecto de implementacin. En el Editor del sistema de archivos (el cuadro a la izquierda), selec cione Carpeta de aplicacin Web. Para agregar el resultado de OrderWebAppl ication al provecto de implementacin. seleccione Accin>Agregar>R esultados de proyec tos. Se abrir el cuadro de dilogo Agregar grupo de resultados del

proyecto
En el cuadro de dialogo Agregar grupo de resultados del proyecto. seleccione Or de rWe bApp li cat i on en la lista desplegable Provectos, si es necesario. Mant enga presionada la tecla C o n t r o l y seleccione Resultado principal v Archivos de contenido de la lista de archivos. Las opciones seleccio nadas aparecen en la figura 28.1 1.
Agregar grupo de resultados
Proyecto:
| '- 'f d e r W e b A p p lic a t io n

*J

"3

| A r c h iv o s d e d o c u m e n ta c i n

Resultado principal
R e c u rs o s a d a p ta d o s S m b o lo s d e d e p u r a c i n

Archivos de contenido
A r c h iv o s d e c o d ig o f u e n t e

Configuracin: Descripcin:

Aceptar

Cancelar

Ayuda

Figura 28.11. El cuadro de dilogo Agregar grupo de resultados del proyecto muestra las opciones que ha seleccionado

636

8. 9.

Ha ga clic en A c ep ta r par a cerrar el cuadro de dialogo Agregar grupo de

resultados del proyecto.


En la vent ana del editor del sistema de archivos, haga clic con el boton derecho del ratn en la Carpeta de aplicacin Web. En el men desplegable. seleccione la vent ana Propiedades para abrir la ventana Propie

dades.
10. Escriba Or de rWe bApp li cat i on como nombre del directorio v irtual en la propiedad Vi rt ual Di rect ory y cierre la v entana Propiedades. 1 1. Seleccione la opcin de men G e n e r ar > Ge ne ra r solucin. Se ha creado un archivo Microsoft Installer (MSI) par a su provecto Puede hacer doble clic en el archivo p ar a instalar su aplicacin en un equipo

Cmo implementar un proyecto usando la opcin Copiar proyecto


Si no quiere t omarse la molestia de cr ear un proyecto de implementacin para su aplicacin y us ar el provecto par a implementarla. tambin puede usar la o p cin Copiar proyecto de Visual Studio N E T par a copiar todos los archivos de su aplicacin en la carpet a de destino. La opcion Copiar proyecto es til cuando necesita implement ar un provecto en una red de comunicaciones. Sin embargo, esta opcin no funciona cuando quiere implementar su aplicacin en un equipo remoto que no tiene acceso a la red de comunicaciones. Para usar la opcin Copi ar provecto, siga estos pasos: 1. 2. 3. 4. Abra el proyecto que quiere copiar. Seleccione la opcin de men Proyecto>Copiar proyecto Se a b n r a el cuadro de dilogo Copiar proyecto. Especifique en el c ua dro de dilogo la Ca rp et a de prov ecto de destino, la ruta de destino en la que quiere copiar el proyecto. Seleccione los archivos del proyecto que quiere copiar y haga clic en Acep tar. Su proyecto se copiar en el destino que especific en el Paso 3. Tras copi ar el prov ecto, puede ejecutarlo desde la nueva ubicacin.

Resumen
El papel de C# en A S P . N E T es muy til par a los servicios y aplicaciones Web. Puede crear un servicio We b mediante la sintaxis del lenguaje C# en AS P. NET.

637

Tambi n puede crear una aplicacin Web que acceda al servicio Web y aproveche su funcionalidad. Cuando crea una aplicacin en A S P . N E T . primero disea la base de datos que debe usar la aplicacin. A continuacin, crea un nuevo provecto en A S P . N E T mediante la Aplicacin W eb de ASP.NET o las plantillas de provecto serv icio Web AS P. NET. Tras crear un prov ecto en A S P. NE T. use los controles de datos pr op or ci on a dos por Visual Studio N E T par a conectar con un origen de datos y utilizarlo. Si ha creado un serv icio Web. tambin puede crear una aplicacin Web para utilizar los mtodos We b proporci onados por el servicio Web.

638

FEl Cmo construir controles personalizados


En este captulo apr ender a crear controles personalizados. Estos controles pueden t omar la forma de un componente visible que puede agregarse a un f o r mu lario o simplemente ser un objeto de clase en caps ul ado en una DLL. En cada instancia, estos controles aprovechan su conocimiento de la reutilizacin de codigo cuando empieza a emp aq ue tar y distribuir la funcionalidad como un control que puede ser us ado una y otra vez.

Biblioteca de control de Windows


Una biblioteca de control de Wi nd ows es un prov ecto que permite la creacin de componentes iguales que los most rados en el cuadro de herramientas de Visual Studio. Elace aos, estos controles eran siempre objetos C'OM o controles ActiveX Ahora puede agregar componentes C O M al cuadro de herramientas o puede crear un control que tenga la forma de una biblioteca de vnculos dinmicos (DLL). Las anteriores versiones de Visual Studio tenan asistentes que a yuda ban en la creacin de controles y Visual Studio N E T no es diferente. Las tareas asociadas con la creacin de propiedades. me;todos y campos se han simplificado gracias a la inclusin de los asistentes.

641

Propiedades
Las propiedades se usan principalmente para establecer y recuperar parmetros de control Cuand o a las propiedades se le conceden los accesos de lectura y de lectura v escritura, se componen de dos funciones llamadas g e t y s e t . Dado que una propi edad debe llamar a un mtodo cuando se le asignan o se recuperan de ella valores, puede realizar clculos u otras funciones tiles inmediatamente. En este aspecto, son muy diferentes de los campos. Un ejemplo de propiedad puede ser la propiedad B a c k C o l o r . Al usar esta propiedad, puede especificar el color que se va a usar como color de fondo de un control o co mp ro ba r cual es el actual color de fondo. Las propiedades se i mplemcntan fcilmente en un proy ecto us ando el sencillo asistente de Visual Studio N E T En la ventana Vista de clases, haga clic con el botn derecho del ratn en la clase del control y escoja Agregar>Agregar clase. El asistente, que aparece en la figura 29.1. le permite establecer el tipo de acceso, el tipo de propiedad ( i n t . b o o l y similares), el nombre de la propiedad, los descriptores de acceso y los modificadores.
Asistente para propiedades de C #
-

CountDm m

H f ? 'S

A s is t e n t e p a r a a g r e g a r p r o p ie d a d e s d e C # F-,fe j i l e n t e : j i una prupiedad a la dase de

Acceso a la propiedad:

Tipo de propiedad

Nom bre de propiedad:

m
j
| A yu d a |

2^

d
Descriptores de acceso:

get

set

f*

get/set

Modificadores de la propiedad:

Ninguno

Static

Virtual

Com entario (n o ta c i n / / no requerida):

Finalizar

Cancelar

Figura 29.1. El asistente para agregar propiedades permite agregar una propiedad a su proyecto

Tr as t erminar con el asistente, ver el ar mazn de cdigo para la propiedad:


public int TestProperty

{ get {
return 0;

}
set

642

En este cdigo faltan algunos elementos bsicos. Cuando se establece el valor de una propiedad, la informacin no se al macena Debe crear antes una variable de clase privada que pueda ser usada por esta propiedad para almacenar y recupe rar el valor. En este caso, simplemente debe incluir la siguiente declaracin en la parte superior de su declaracin de clase:
prvate int m TestProperty;

Desde el mt odo set de su propiedad, puede asi gnar los datos de su variable privada usando la pal abr a clave valu:
S0t

1
m TestProperty = valu;

} Una vez que hemos a lmacenado el valor de la propiedad en la variable de clase privada, debe as egurars e de que el mtodo Get devuelve el valor correcto al ser usado. El siguiente cdigo logra esto; simplemente devuelve el valor de la var ia ble pri vada del bloque get. como muest ra el siguiente fragmento:
get

{
return m TestProperty

} Tambi n es til describir las propiedades de los componentes existentes en su control. Por ejemplo, imagine que ha creado un control que contiene una etiqueta. Su control debe contener una propiedad Font que obtenga y es tabl ezca la fuente del component e de la etiqueta de su control. Para permitir que el contenedor manipule la fuente de su etiqueta, simplemente cree una propiedad como la si guiente:
public Font CurrentFont

{
get

{
return l a b e l l .Font;

} set {
labell.Font = valu;

} } Este cdigo crea una propiedad llamada CurrentFont. que devuelve la fuente actual del control label cuando se le solicita. Cu and o el contenedor

643

desea cambi ar la fuente, simplemente tiene que asignar ese valor a la fuente actual del control de la etiqueta

Mtodos
Un mtodo se define como una funcin que forma parte de una clase. Los mtodos se implementan del mi smo modo que en muchos otros lenguajes, como C++. C. VB y similares. Los mtodos suelen usarse par a iniciar una accin den tro de un control. Un ejemplo podra ser el mtodo Start del control Timer. Puede agr egar un mtodo a un control de una de estas dos formas. Puede usar el asistente p a r a mtodos de C#. al que se puede a cceder mediante el Explorador de soluciones mientras se est en la Vista de clases o si mplemente ag regando una funcin pblica al provecto El asistente para mtodos de C#. que se muest ra en la figura 29.2. permite especificar el nombre del mtodo, el tipo devuelto, el mtodo de acceso y la infor macin de par met ro de una forma muy sencilla.
|Asistente I

para mtodos de C #

CountDown

:'; |

A s is te n te p a ra a g re g a r m to d o s d e C # F-.te .- r.r.fT ite .agrega un rnef.odu 3 la ra s e de

1
-s il Nom bre de m todo: 3 |

Acceso al mtodo; I

T.ipo de valor devuelto; H B B I J | HBffl om bre de parm etro; d

1
Lista de parm etros: |

Modificador: |n o J

Tipo de garm etro: | ffl

.......

............................ | Q uitar

~ |

A g re g ar Modificadores d d m todo: P Static f ~ I- * Virtual F E xte rn P

O ve rride P

N ew

11 Com entario (notacin

f j no

requerida):

1 1
Finalizar | Cancelar | A yu d a |

Figura 29.2. El asistente para mtodos de C# crea la estructura bsica del cdigo necesario para el mtodo

El inconveniente del asistente p ar a mtodos es que slo propor ci ona tipos simples de devolucin. Por ejemplo, imagine que quiere un mtodo que devuelva un valor de tipo Font. El cuadro combi nado Tipo de valor devuelto no ofrece el tipo Font como opcion. C uan do haga pruebas con el asistente a prender que puede introducir sus p r o pios tipos en estos cuadros; sus opciones no se limitan a las que le ofrecen los cuadros. Las opciones que presentan slo son los tipos ms usados par a que el p r o g r am ad o r inexperto no se confunda. Despus de todo, si el asistente most rara

644

todas las opciones posibles, t ardar amos mucho tiempo en despl azarnos por toda la lista en busca del tipo deseado. N E T Framework tambin apor ta a los mtodos algunas funcionalidades muy necesarias. Ahora los mtodos pueden s obrecargarse. Es decir, pueden tener el mismo nombre mientras su lista de p ar met ro s sea diferente

Campos
Los campos son simples variables publicas definidas en un control La a p l i ca cin cont enedora puede as ignar al ca mpo un valor determinado y recuperarlo. Como slo son variables, no pueden tener funciones asociadas a ellos. Los c a m pos no pueden realizar clculos ni llamar a mtodos cuando se les asigna un valor o se recupera de ellos un valor. Hay dos tipos de campos: de instancias y estticos. Un ca mpo es. por defecto, un ca mpo de instancia. Un campo de instancia puede contener sus propios datos en cada objeto que lo contenga. C uand o un ca mp o es declarado como esttico, contiene los mismos datos en todas las instancias del objeto. Un ca mpo esttico no suele ser aconsejable porque otras instancias del objeto pueden ca mbi ar el v alor y las instancias restantes no se p er cat ar n de ello. Los ca mpos pr opor ci onan elementos de cdigo de bajo nivel pero tambin estn limitadas en trminos de funcionalidad. Puede asi gnar y recuper ar los val o res de un campo, pero al hacerlo no puede des encadenar otras acciones dentro del control. Los campos son tiles cuando se necesita asi gnar par met ros de o p er a cin a un control.

Eventos
Para definir un evento, antes debe hacer una declaracin de clase publica, como la siguiente:
Public event EventHandler Expired;

Puede u sar eventos con controles de Wi ndo ws de uno de estos dos modos: puede hacer clic en el icono Event en la vent ana Propiedades y hacer doble clic en el evento par a agr egar el cont rol ador aut omt icame nte o puede crear un con trol ado r de eventos u sted mismo. Un evento bsico se declara como un tipo EventHandler. pero tiene m u chos ms tipos de evento entre los que elegir y cada uno tiene una firma nica. El p ar met ro de cada evento contiene una est ructur a System. EventArgs. Esta e st ructur a permite al control p a sa r informacin al evento, con lo que define m u chas aspectos, como qu desencadena el ev ento, qu control hace que se des enca dene el evento y aspect o similares. Antes de escoger un tipo de evento p ar a un control, asegrese de que conoce los diferentes tipos, adems de los par met ros que pas a cada uno.

645

Aprender con un ejemplo


Empecemos creando un control t empori zador de cuenta atrs. Este ejercicio le permitir est udi ar los entresijos de la creacin de controles.

Cmo crear un temporizador de cuenta atrs


Antes de empezar a crear el control t empori zador de cuenta atrs, debe decidir lo que har y lo que no har este control. Esto simplificar el proceso de crear el control. Siempre es bueno tenerlo todo bien planificado antes de e mpez ar un proy ecto de control, incluso mas que en cualquier proyecto de progr amaci n t pi co. Este control parti cular deber tener las siguientes caractersticas: El control deber ser un component e v isible que pueda colocarse en un formulario. Este control deber tener las propiedades habituales, como BackColor. Anchor, etc. El control deber recibir un valor que indique el numero de segundos desde los que empezar la cuenta atras. El control deber tener un mtodo Start ( ) y Stop ( ) par a empezar y terminar la cuenta atrs. Finalmente. El control deber des encadenar un evento cuando la cuenta atrs llegue a cero. Una vez definidos los requisitos, puede empezar a crear su control. Ab ra Visual Studio N E T y cree un nuevo proyecto de biblioteca de control de Wi ndows. Llame a este provecto CountDown. como muest ra la figura 29.3.

; P roye cto p ara crear controles que se v a n a utilizar en aplicaciones p ara W indow s. N om bre: Ubicacin: | C o u n tD o w n |C i s o C e rra r solucin u t u e E xa m in a r...

Ag re g a r a solucin

El p ro ye cto se cre a r en C:\source \Co u n tD ow n .

Ms_______ |

A ce p ta r

Cancelar

Ayuda

Figura 29.3. Cree un nuevo proyecto de biblioteca de control de W ind o w s

646

1.

Cuando Visual Studio haya creado la estructura basica de su control, se le mostrara un UserControl. Este ser la interfaz visual p ar a su control CountDown. Aqu es donde se coloca cualquier elemento visual que qui e ra que el usuario vea o con el que quiera que interacte.2. Lo primero que debe hacer es colocar un control Label en UserControl. como m u e s tra la figura 29.4. Cambi e la propiedad Anchor de este control Label a Top.Left. Bottom.Right . Esto as egura que cuando el control cambie de tamao, la etiqueta tambin lo haga. Debe tener mucho cuidado cuando agregue componentes existentes a un control porque muchos elementos pueden c a m biar de aspecto cuando el usuario coloca un control en el formulario. Ahora debe agr egar un control T i m e r al provecto (desde el cuadro de herramientas). El control Timer permite cont ar un segundo cada vez h as ta que crea que el tiempo se ha agotado. El aspecto externo del control ya est completo. Ahora debe agr egar el cdigo que apoye a este control.
CountDown - Microsoft Visual C# J i T [disear] - UserControll.es

3.

4.

Archivo op -

Edicin

Ver y

Proyecto

Generar

Depurar

Datos

Herramientas O m

Ventana ~ ^ m

Avyda L* | | | | | | ^ Q Propiedades | IJs p iT o n tr o ll.V s t-'n nn.-- j. l.-. .jH / ]

-3 -

Z*

wj

13 1

J ::[EM
Accin de genera Ojmpili i.:-r.

zi
j J

Accin de generacin
Cmo se relaciona el archivo con los procesos de generacin e impleme ...

UserControll.es [Diseo] I

Explorador de soluciones - C o u n .,. ?

iH H jj
. CountDown

^ P^r r n , e ,
3 UserControll.es

Listo

Ln 17

Col 1

Car 1

IN5

Figura 29.4. Coloque una etiqueta en UserControl

5.

En el listado 29.1 declar una variable de mi embro p ar a que contuv iese el numero de segundos desde los que el temporizador de cuenta atrs e mpez a ra a contar. Tambi n debe declarar un EventHandler par a que se dispare cuando el control llegue al final de la cuenta atrs. Coloque el siguiente cdigo inmedi at ament e debajo de la declaracin de clase de

UserControl:

647

Listado 29.1. M i e m b r o s p b l i c o s prvate m t m Seconds; public event EventHandler

Expired;

6.

La v a r i a b l e m Seconds no necesita estar expuesta al contenedor de c o n troles. sino solo al propio control, por lo vamos a declarar la variable como privada. Al declarar un EventHandler publico. Expired a p a rece en la ventana de eventos. De modo que puede p ro g r a m a r este evento con slo hacer doble clic en l. En el evento Tick del objeto Timer. debe restar un segundo del numero total de segundos. Luego puede c o mp r ob a r si el nmero total de segundos ha llegado a cero. En caso afirmativo, debe detener el t empori zador y des encade nar el evento Expired. Despus, puede actual izar el control Label par a que muestre el valor del control CountDown Timer en ese momento. En la ventana Propiedades, haga clic en el cuadro combi nado Selector de objeto y seleccione el control Timer. A continuacin haga clic en el botn Ev e n t o s de la bar ra de herramientas en la parte superior de la ventana Propiedades. Ver todos los eventos que muest ra el control T i mer . Ha ga doble clic en el evento Tick. Coloque el cdigo del listado 29.2 en el cont rol ador de eventos Tick del control Timer.
Listado 29.2. El evento Tick actualiza el control

7.

prvate

void

t i m e r 1 Tick(object

sender,

System.EventArgs

e)

I
m Seconds -= 1; f (m Seconds <= 0)

(
tme r l . S t o p ( ); Expired (this,e) ;

}
labell.Text = m S ec on ds .T o S t r i n g ( );

} K Su control tambin necesita un mtodo public ( ) que permite que el contenedor inicie el control para que empiece a contar segundos. El listado 29.3 define el intervalo del control Timer (en milisegundos) y luego inicia el control Timer. Una vez que el tempo ri za do r ha sido iniciado, debe actualizar el control Label porque no se ac tual izar hasta un segundo despus de que el t e mpo ri za dor desencadene el evento Tick por primera vez. Para a gr egar un mtodo al control, cambie la vista del expl orador de solu ciones a vista de clase haciendo clic en la ficha Vista de clase. Expanda la vista de clase hasta que encuentre las clases de controles. Haga clic con el botn derecho del ratn, seleccione Agregar y luego Agregar mto-

9.

648

dos. L1 Asistente para m todos de C# se abrir, como muestra la


figura 29.5.

A s is t e n te p a r a d jr e ijd r m to d o s d e ( #

Tipo de valor devuelto:

Nombre de mtodo:

U
Modificador: Tipo de parametro:

[ m

Nombre de parametro:

Lista de parmetros:

Modificadores dei mtodo:


f~

Static

r~ Virtual ~ Extern f ~ Override f -

New

cimentano (notacin // no requerida):

Finalizar

Cancelar

A yu d a

Figura 29.5. Asistente para mtodos de C#

10. Llame a este mtodo Start y asegrese de que es un mtodo publico. Puede dejar todos los otros valores que se ofrecen por defecto. I ras crear el nuevo mtodo, agregue el codigo del listado 29.3 al listado del codigo del mtodo.
Listado 29.3. Mtodo Start public void Start( )

{
t i m e r l .Interval - 10 00; t ime ri .Start ( ); label 1 .Text=m Seconds . T o S t n n g () ;

1 1. Un mtodo Stop ( ) complementa al mtodo Start ( ) . El mtodo Stop ( ) debe detener en pri mer lugar al control Timer para que el evento Ti ck no v uelva a desencadenarse. Tambi n debe asignar el v alor de la propiedad Seconds a la variable de m i e m b r o m Seconds. Esto gar ant iza que si el control se inicia de nuevo, lo har a desde el principio y no desde donde se enc ontr aba cuando fue detenido. Cree un nuevo mtodo llamado Stop (). del mismo modo que creo el mtodo Start ( ) . Agregue el codigo del listado 29.4 a este nuevo mtodo.
Listado 29.4. Mtodo Stop public void Stop()

649

time r 1.S t op () ; m Seconds = t h i s .S e c o n d s ;

An no ha creado la propiedad S e c o n d s . La propiedad S e c o n d s permite conseguir y establecer el numero total de segundos desde los que el control e mp e zar la cuenta atrs. Una propiedad se crea de una manera muy parecida a un mtodo. 1. Desde la vista de clase del Expl orador de soluciones, haga clic con el boton derecho y escoja Agregar y luego Agregar propiedad. El asistente para propiedades de C#. most rado en la figura 29.6. se abrir.
|Asistente para propiedades de

C #- CountDown

A s is t e n t e p a ra a g r e g a r p ro p ie d a d e s d e C #

t ; t e a s le n te agrega una propiedad a la clase d e :#.

Acceso a la propiedad:

Tipo de propiedad:

Nom bre de propiedad:

fput.hr
Descriptores de acceso:

VJ

| 50

get

set

get/set

Modificadores de a propiedad:

( *

Ninguno

Static

Virtual

C om entario (notacin // no requerida):

Finalizar

Cancelar

Ayuda

Figura 29.6. En el asistente para propiedades de C#, llame a esta propiedad Seconds. A segrese de que esta propiedad tenga acceso pblico y de que el tipo de la propiedad sea Int

2.

Queremos que la aplicacin contenedora de los controles pueda asi gnar un valor a esta propiedad o leer un valor de ella. Por tanto, queremos que el descri ptor de acceso sea g e t / s e t . Agregue el cdigo del listado 29.5 al codigo creado por el asistente par a propiedades de C#.
Listado 29.5. Propiedad Seconds

public

int

Seconds

{
ge t

{
return m Seconds;

} set {

650

m Seconds

= valu;

} } Preste especial atencin a la p al ab r a clave valu. Cuando se pasa un valor a una propiedad (por ejemplo, set), puede ser recuperado mediante la p al abr a clave valu. Hast a ahora, su control no es muy sofisticado, ni presenta buen aspecto, pero funciona. En este momento, puede crear el nuevo control seleccionando Generar solucin en el men Generar. Ahora genere una prue ba de carga que use este control y permita c omprobar todos los mtodos, propi edades y eventos del control.

Cmo crear una prueba de carga CountDown


Uno de los puntos fuertes de Visual Studio es que permite a gregar un prov ecto a un provecto existente, lo que es muy importante para probar controles Esta posibilidad permite crear una aplicacin de prue ba de carga que usa uno de los controles que ac a ba de crear. C uando encuentra algn error, no slo se interrum pe la aplicacin, sino que se i nterrumpe en el punt o del codigo donde el control funciono mal. Esto le aho rr ar tener que pasarse incontables horas depurando cdigo cuando empiece a cr ear controles complejos. Siga los siguientes pasos para crear una prueba de carga:

1. Desde el provect o de control CountDown. haga clic en el men Archivo y seleccione Nuevo>Proyecto. Se abrir la ventana Nuevo proyecto.
2. S e l e c c i o n e A p lic a c i n para W in d o w s y l lame a e st a a p l i c a c i n CDHarncss. En la parte inferior de esta ventana, asegrese de que el botn de opcin Agregar a solucin este seleccionado. Haga clic en A c e p tar 3. El Explorador de soluciones muest ra los dos provectos. Haga clic con el boton derecho del ratn en la aplicacin CDHarness en el Explorador de soluciones y seleccione Establecer como proyecto de inicio. A p ar tir de ahora, cuando ejecute la aplicacin, la prueba de carga sera la apli cacin principal que ejecuta y puede usar cualquier otro provecto que este abierto en ese moment o en el "grupo". Asegrese de que esta en el provecto CDHarness haciendo clic en el Explorador de soluciones. Haga clic con el boton derecho del ratn en el cuadro de herramientas y escoja Personalizar cuadro de herram ien

4.

tas.
5. Cuando se abra la v entana Personalizar cuadro de herramientas, haga clic en la ficha Com ponentes de .NET Framework. Ah es donde se agrega el nuevo control al prov ecto.

651

6.

H a g a clic en el bot n E x a m i n a r y b u s q u e el cont rol t e m p o r i z a d o r

CountDown. Cuand o lo encuentre, seleccinelo y mrquelo. Ha ga clic en


Aceptar 7. En la lista de controles, ver este control; marque el cuadro junto a l. Ah ora puede hacer clic en A cep tar en este formulario. En el Cuadro de herram ientas, ver el control tempori zador CountDown en la lista. Haga doble clic en el control par a agregarlo a su provecto. Mientras esta en el cuadro de herramientas, agregue tambin dos botones a su f o r m u l a rio. El primer botn se usa p ar a iniciar el t emporizador de cuenta atrs y el s egundo botn se usa par a detener el control Countdown. Alinee y e s t a blezca las propiedades de texto como se muest ra en la figura 29.7.
|g Countdow n _____ H E f E3

S|art

Figura 29.7. La interfaz principal de su aplicacin de carga C ountD ow n

Haga doble clic en el botn Start de su aplicacin para que pueda empezar a codificar. Agregue el cdigo del listado 29.6 al evento Click del botn Start
Listado 29.6. Inicia el control

pr vate

voicl buttonl Click (ob] ect

sender,

System. EventArgs

e)

{
c d T i m e r 1.Secn d s = o ; c d T i m e r 1.S t a r t ();

} 10. El boton Start sirve slo para una cosa: para preparar e iniciar el control CountDown. Para empezar, establezca en 60 el nmero de segundos y luego llame al mtodo Start del control. 1 1 Tambi n necesita un modo de detener el control Haga doble clic en el boton Stop para insertar cdigo en el evento Click de este botn. Inserte el siguiente codigo del listado 29.7 en el evento Click del boton Stop.
Listado 29.7. Detiene el control prvate void buttonZ Click (object sender, System.EventArgs e)

{
c d T i m e r l .S t o p !);

652

12. El evento Expired del control CountDown debe realizar al guna accin que le informe de que la cuenta atras ha llegado a cero. En la ventana Propiedades, haga clic en el botn E v e n t o s en la b ar r a de herramientas. A continuacin, haga doble clic en el exento Expired. Es en este cdigo en el que debe codificar esa accin especial. No intente nada extrav agante; simplemente vamos a ca mbi a r el ttulo de su formulario a Done. Inserte el cdigo del listado 2 9 . K en el evento Expired del control CountDown.
Listado 29.8. C digo del evento Expired prvate voxd cdTimerl E x p i r e d (object sender, System.EventArgs e)

{
this.Text="Done !" ;

} Su control y su aplicacin de prueba ya estn listos par a ser ejecutados. Pulse F5 para ejecutar la aplicacin. C uando se abra la aplicacin, haga clic en el boton S t a r t para iniciar la cuenta atrs. Su aplicacin de prueba deber empezar a contar hacia atras. Cuando la cuenta atrs llegue a cero, el ttulo del formulario deber cambiar, gracias al evento Expired.

Cmo usar una biblioteca de clases


Una biblioteca de clases es un modo eficiente de reutilizar y distribuir el codigo reutilizable. Las bibliotecas de clases se al macenan en las DLL. pero no es necesario envolver el cdigo con instrucciones y declaraciones como en otros lenguajes, como C++. Como con cualquier componente reutilizable. las bibliotecas de clase p r o p o r cionan constructores y destructores de clase p ar a la imcializacin y la limpieza, pero estos elementos no son realmente imprescindibles. Para empezar su viaje por las bibliotecas de clase, cree una sencillo DLL con al gunos mtodos pblicos de prueba. A continuacin, cree el control con algunos atributos adicionales.

Cmo crear una clase para calcular el efecto de viento


La biblioteca de clases de clculo del efecto de viento no slo p roporciona una funcin par a calcular la t emper at ura del aire, si que tambin proporci ona f uncio nes par a diferenciar los grados Celsius de los grados Fahrenheit y viceversa. Como las operaciones que v a a realizar en esta biblioteca de clases pertenecen a dos categoras distintas, conversin y clculo, debe incluir dos clases s e p a r a das. Cree un nuevo provecto de biblioteca de clases y llmelo Temperat ure. Vi-

653

sual Studio crear el cdigo que ser la est ructur a bsi ca mostrado en el listado 29.9.
Listado 29.9. Cdigo creado para una biblioteca de clases por Visual Studio using System; Temperature

amespace

{
///
/ / / / / /

< summary>
D e sc rip c i n '/suitim ary) cla ss C la ssl breve de C la ssl.

p u b lic

{
publie Classl( )

{ //
// TODO: Agregar aqu la lgica del constructor

//

Visual Studio ha creado un espacio de nombres, una clase y un const ructor de clase. La clase y el constructor de clase son pblicos. Esto no es una coincidencia. Cual qui er aplicacin que use esta biblioteca necesita acceder tanto a la clase como a los mi embros especficos dentro de la clase. 1. Para empezar nuestro ejemplo, elimine la clase y el const ructor de clase v reemplcelos por el codigo del listado 29.10.
Listado 29.10. La clase y el c o nstructor Cale public class Cale

{
publ i c C a le (i

{ } } 2. La clase C a l e es donde colocar el mc'todo de clculo del efecto de viento. De esta forma, estamos seguros de que nuestro calculo del efecto de viento queda separado de los mtodos de conversin que pronto agregara. Inserte el cdigo del listado 29.1 1 en la clase C a l e .
Listado 29.11. Clculo del efecto de viento actual
p u b lic double W i n d C h i 1 1 (d o u b l e DegreesF, double WindSpeedMPH'

{
doub le W m d P a ise d ; . S y s t e m . M a t h . Pow ( W i n d S p e e d M P H , . l e ) ; W m d P a ise d

654

return 35.74 + (.6215 * DegreesF) (.4275 * DegreesF * W m d R a i s e d ) ;

(35.75

* WmdRaised)

} } 3. Tambi n agr egar emos al gunos mtodos que no son clculos, sino c onve r siones. Por tanto, deber aadir una nueva clase. Esta nueva clase se lla mar C o n v e r s i n , como se puede ver en el listado 29.12. Agregue la nueva clase y const ructor de clase al provecto.
Listado 29.12. Agregar una segunda clase a la biblioteca de clases public class Conversin

I
public Conversioni)

4.

Inicie la nuev a clase con una funcin que calcule la t emper at ura en grados Falirenheit a partir de la t emper at ura en grados Celsius. Es poco probable que el valor devuelto o el p ar m et ro sean valores enteros, de modo que es importante que ambos sean valores double. El listado 29 . 13 contiene el l i s t a d o c o m p l e t o de la f u n c i n . A g r e g u e e s t e c o d i g o a la c l a s e

Conversin.
Listado 29.13. Conversin de Celsius a Fahrenheit public double (9/5) CelcToFahr(double * (Celsius C el s i u s )

{
return + 32) ;

} 5.

Como ha incluido una funcin de conversin de Celsius a Fahrenheit. es lgico incluir la conversin inv ersa. Agregue el mtodo del listado 2 9 . 1 4 a la clase Conversin.
Listado 29.14. Conversin de Fahrenheit a Celsius

public

double (5/9)

FahrToCelc(double * (Fahrenhert

Fahrenheit)

{
return - 32) ;

} Con esto finaliza la funcionalidad que queremos incluir en el objeto biblioteca de clases, de modo que ya puede crear la D LL seleccionando G enerar solucin en el men Generar. Una vez que todo est en su sitio, observ e como se utilizan los mtodos pblicos que hay en su interior. I. Cree un nuevo provecto de aplicacin de consola y llmelo DLLTest . En el men Proyecto, seleccione Agregar referencia y a continuacin haga

655

clic en el boton E x a m i n a r Busque la DLL que ac aba de crear \ haga doble clic sobre el la I. Ya puede hacer clic en A c e p t a r para salir de la ventana Agregar referencia. 2. Tra s agr egar una referencia, puede simplemente crear una nueva variable del tipo adecuado y hacer referencia al mtodo que prefiera. L1 listado 29. 15 contiene el listado completo del codigo de la aplicacin DLLTest.
Listado 29.15. Cdigo fuente de la aplicacin DLLTest i!;jin g , r Jy s t e m ;
11ame spa ce

DLLT est

/// ' summa ry /// Descripcin /// /. sumira ry cas s C 1 a s s 1 breve de C ias s 1 .

1
stat ic v o id Main (string[] a r g s )

{
Temperature.Calc WCMethod = new T e m p e r a t u r e .C a 1c (); T e m p e r a t u r e .Convers ion ConvMethod = new T em perature.Conversion () ; Console.WriteLine("Wind chill at 50 degrees with 35 MPH D eg re es ",W C M e t h o d .WindChi 1 1 (50 ,35) ) ; Consol . W n t e L i n e ("32 Degrees Fahrenheit t .o Celsius : D eg re e s " ,C o n v M e t h o d .FahrToCelc (32) ) ; C o n s o l . W n t e L i n e ("0 Degrees Celsius to Fahrenheit : D e g r e e s " ,C o n v M e t h o d .CelcToFahr (0) ) ;

{0}

{0 } {0}

} )
1

El acceso a los mtodos es una tarea muy sencilla: cree nuevas v ariables del tipo T e m p e r a t u r e . C o n v e r s i o n y T e m p e r a t u r e . C a l e v luego acceda a sus mtodos pblicos. Esta aplicacin de ejemplo calcula el efecto del v iento con una t emp er at ura de 50 grados y una velocidad del viento de 35 millas por hora: a continuacin calcula la t emper at ura en grados Celsius y Fahrenheit El resultado de esta aplicacin se muest ra en la figura 29.8.

Resum en
N E T presenta algunas innovaciones en la forma de construir controles ex tr e madamente importantes. A medida que cree controles par a sus propios provectos o para implementar en la Web. ira descubriendo algunos av ances en la p r o g r a m a cin. como el objeto S t a t e , que le aho rrar n grandes cantidades de tiempo.

656

c a

C:\WINDOWS\System32\cmd.exe

:\Source\DLLTest\bin\Debug>dlltest ind chill at 50 degrees with 35 MPH : 41.425231535302 Degrees 32 Degrees Fahrenheit to Celcius : 0 Degrees 0 Degrees Celcius to Fahrenheit : 32 Degrees C:\Source\DLLTestSbinSDebug>_

Figura 29.8. D LLTest le ensea a usar un control de biblioteca de clases

657

Cmo construir aplicaciones mviles


E li]
Las aplicaciones We b mviles son un gru po de t ecnologas emergentes que permiten que el contenido Web sea accesible a un nmero mayo r de publico que el que puede ofrecer Internet actualmente. Puede crear aplicaciones de Intranet cor porat iva para los empleados que se mueven entre los edificios de la compa a o para los que se desplazan entre continentes durante sus viajes de negocios. Este captulo describe varios apart ados de las aplicaciones Web mviles.

La red inalm brica


El concepto de acceso a Internet mediante dispositivos mv iles lleva mucho tiempo entre nosotros pero ha t ardado en ser aceptado. Las herramientas a de c ua das para crear contenido Web han sido bastante escasas. N ET Framework. junto con el Mobile Internet Toolkit de Microsoft, permite crear emocionantes a p l i ca ciones Web que se pueden usar en distintos tipos de dispositiv os mov iles. Estos dispositivos mviles incluyen dispositivos Wi ndows CE. dispositivos Pocket PC y muchos telfonos mviles. Evidentemente, la may ora de los disposi tivos mv iles estn muy limitados en comparacin con los navegadores Web a los que estamos a cos tumbrados . No es solo que los dispositivos mviles di spongan

659

de menos espaci o par a el contenido, muchos de estos dispositivos carecen de color o. en alguna otra forma, de la capaci dad para most rar grficos. Este capitulo empieza est udi ando el soft ware que necesita, j u nt o con los emuladores adecuados que puede us ar p ar a pr oba r su cdigo, en caso de que no tenga acceso a un dispositivo mvil con acceso a Internet.

Introduccin al Mobile Internet Toolkit


El Mobile Internet Toolkit de Microsoft permite a Visual Studio crear a pl i ca ciones We b seleccionndolo como proyecto en el men Nuevo proyecto. Este conjunto de her rami ent as no se incluye en el mi smo paquete que Visual Studio NET. por lo que debe ser descargado de for ma s epa rada desde la pgina W eb de Microsoft. El Mobile Internet Toolkit actual mente se encuentra en la versin 1 0 v se puede d es cargar desde http :/ /msdn .microsoft.com/download. Cua nd o llegue a esta pagina, debe seleccionar Soft war e Developmcnt Kits en el marc o a la izquierda de su navegador We b y luego seleccionar Microsoft Mobile Internet Toolkit El Software Developmcnt Kit (S DK) actual o cu pa algo ms de 4 M B y contie ne varios controles A S P . N E T p ar a generar Lenguaje de marcado inalmbrico ( W M L ) v varios detalles de H T M L , adems del mdulo que se aade a Visual Studio NE T. document aci n y ejemplos de aplicaciones. Asegrese de que al instalar el SDK. todos los procesos de Visual Studio estn cerrados.

Emuladores
Los emuladores permiten escribir aplicaciones par a dispositivos y probarl as sin tener que c o mp ra r realmente uno de los dispositivos. Hay emuladores para telefonos mviles. PDA. equipos de escritorio y dispositivos intermedios. Los siguientes ap art ados t ratan sobre algunos de los emuladores ms populares, que puede descargar y empezar a escribir aplicaciones p ar a ellos.

Nokia
En la pgina Web de Nokia ( http://www.nokia.com) , puede de sc a r garse un emul ador de telfono Nokia par a pr ob ar sus aplicaciones We b para telefonos mviles. Esta d es carga es de casi 2 2 M B y requiere el entorno de ej ecu cin Java, lo que aade otros 5MB a su descarga. El emul ador Nokia actualmente le permite elegir entre uno de los tres diferentes modelos Nokia que ofrece para que realice sus pruebas. Esta aplicacin es un valioso recurso para pr oba r sus aplicaciones.

Pocket PC
El emulador de Pocket PC se inclu\ e en el Microsoft Embedded Devices Toolkit Es un excelente e mul ador por si no posee un Pocket PC ya que Pocket Internet

660

Explorer admite muchas mas funcionalidades que la mayora de los dispositivos mviles del mercado actual. Tenga en cuenta que el t amao real de este conjunto de herramientas es superior a los 3 00MB. Si no posee una conexin a Internet de alta v elocidad, es mejor que use Microsoft Mobile Explorer, del que le hablamos en la siguiente seccin.

Microsoft Mobile Explorer


Microsoft Mobile Explorer es una descarga de solo 3MB y se usa principal mente p ar a integrarse con Visual Studio. Cu ando pruebe sus aplicaciones, es ta blezca M M E como su navegador por defecto.

Cmo crear un calculador de edades


Tras instalar el Mobile Internet Toolkit de Microsoft, cree un nuev o provecto de C#. Apreciar una nuev a opcion llamada Mobile Web Application, como mues tra la figura 30.1.
Nuevo proyecto

A p ro je c t fo r c r e a tin g a n a p p lic a tio n v ie w a b le o n P D A s, c e llp h o n e s , a n d o th e r m obile d ev ic es

N o m b re : U b ica cin :

|" | BtBW JB B W H n B U B T O f fiB B Exan

El p ro y e c to se c r e a r e n h t tp :/ /p o w e r h o u s e /Y o u r A g e ,

M s

A c e p ta r

C a n c e la r

Ayuda

Figura 30.1. La nueva opcin Mobile W e b Application se agreg cuando instal Mobile Internet Toolkit.

Esta aplicacin de ejemplo toma su ao de nacimiento p ar a calcul ar cual es su edad actual (o la que debera ser). 1. Llame al prov ecto YourAge y cuando Visual Studio cree la estructura de su aplicacin, ver un formulario We b Mobile en blanco llamado Forml. 2. Ha ga clic con el botn derecho del ratn en este formul ari o y seleccione C o p i a r . Ah ora haga clic con el boton derecho del ratn debajo del f o r m u lario y seleccione P e g a r. Est a a p li ca c i n n eces it a dos for mul ar i os:

661

uno que adquiere la informacin del usuario y otro que muest ra los resul tados. 3. Una vez que tenga los dos formularios, coloque un control B u t t o n . un L a b e l y un T e z t B o x en F o r m l y coloque un control L a b e l v un L i n k L a b e l en F o r m 2 . Coloque estos controles como se muest ra en la figura 30.2.

Una vez situados los controles, debe asi gnar todas las propiedades adecuadas. La tabla 30.1 contiene las propiedades de cada control. Colquelas a d ec uada me n te antes de seguir adelante.
' .r.-jrtf'-gfMobileWebFormlaspx* | M eM eV..'>hF.:.:r,-,1 3:p- c :

Forml I 1 ate of Birth 1 Show Age

Form2 [lblLurrentAge] Ti y i-vuii I

Figura 30.2. Estos formularios son necesarios para la aplicacin Y o u r A g e

Tabla 30.1. Propiedades del control YourA ge

F o r m u la r io

C o n tro l

P r o p ie d a d N a m e

P r o p ie d a d T ex t

Formi Formi Formi Form2 Form2

Label Text Box Button Label Link Label

Labell txtDOB Commandl IbICurrentAge Li nk 1

Year of Birth <Empty> Show Age <Empty> Try Again

Debe es tablecer una propiedad antes de empez ar a codificar. Seleccione el control L i n k L a b e l y asigne la propiedad N a v i g a t e L J r i a F o r m l . Esto asegura que. cuando se hace elc en el vnculo, el usuario es en\ lado de vuelta al F o r m l del p r o y e c t o . Antes de empezar con el codigo necesario para su progr ama, examine el codigo oculto de estos formularios We b Mobile. En la parte inferior del di seador de formularios hay dos botones con la etiqueta D iseo y H TM L. Haga clic en el

662

botn H TM L p ar a mos trar el cdigo H T M L oculto de estos formularios, que debe ser igual que el codigo del listado 30.1.
Listado 30.1. C d i g o H T M L o c u l t o d e los f o r m u l a r i o s W e b Y o u r A g e
< @ R e g iste r T a g P r e f i x = "m o b i1 e " Ve r s i on= 1 . . 3 3 0 0 . 0
b ,

Na me s p a c e = " S y s t e m . W e b . U I . M o b i l e C o n t r o l s " As s embl y = "Syst. e m .W e b .M o b i l e , C u ltu re ^ n e u tra l, @ Page languaqe = "c#" Pub 1 1 cKe y T o k e n - b O 3 f f
"1 f

1 1 d5 0 a 3 a "

C o d e b e h i n d - "Mob i 1 e W e b F o r m 1 . a s p x . c s "

I n h e i i t s - " You r A g e . M o b i l e W e b F o r m l " A u t o E v e n t W i r e u p = " f a 1 s e " <m eta n a m e = "GENERATOR" c o n t e n t = " M i c r o s o f t V i s u a l S tu d io 7.0 " -meta :- m e t a "b o d y name-"COt)E LANGUAGE" con t ent = "C # " > c o n t e n t = "ht tp : / / name- " v s _ t a r g e t S c h e m a "

s chema s . m i c r o s o f t . c o m / M o b il e / P a g e " ,' Xml n s : m ob i l e = " h t t p : / / s c h e m a s . mi c r os o f t . c o m / M o b i l e / id ="F o rm l" runat="server" > r u n a t = " s e r v e r " . Y e a r runat = "server" / Age- /
o

W c b F o r m " ;<m o b i l e : Form < mobi 1 e : Labe 1 m o b ile : L a b e l> mo b i l e : T e x t B o x -> < m o b i 1 e : Command mo b 1 1 e : C o m m a n d > '. / m o b i 1 e : F o r m> -. m o b i l e : F o r m i d - " F o r m2" runat = "ser ver " r una t - " s e r ve r " / .mobi 1 e : L a b e 1 mob l i e : I, a loe 1 -.mobi 1 e : L i n k v/mob i l e : F o r m > /body. id - " lb lC u r r entAge " i d= L i n k I i d = " Command 1 " r u n a t - " s e r v e r " .'Show id = "L a b e ll" Bi rf h :* /

mo b i ] e : T e x t . B o x

id = " txtDOB"

runat = "s e r v e r " /m obi le : I.m k -

N a v i g a t elJ r 1 = " # F o r m l " > T r y

A g a in !

Este codigo es el es tand ar de H T M L c ombi nado con al gunos elementos que estn definidos por el espacio de nombres M o b i l e C o n t r o ] s . Esta union de la pagina H T M L y la clase N E T M o b i l e C o n t r o l s puede apr eci ar se en la linea que sigue a N a m e s p a c e . Cuand o empiece a codificar, observe que varios e s p a cios de nombres ya lian sido a gr egados al proyecto por este motivo. Ahora esta listo para empezar a codificar su aplicacin Web mvil. Este p ro yecto necesita que haya codigo en un lugar. Haga doble clic en el boton que ant er iorment e col ocamos en F o r m l . El listado 30.2 contiene el codigo que debe insertar tras el evento clic de este boton.
Listado 30.2. C m o c a l cul ar la e d a d en el e v e n t o C l i c k
p riva te vo id lDOB = Command 1 C lic k (o bject sender, S yste m .E v e n tArgs e)

{
in t i nt if S y s t e m . C o n v e r t . T o l n t '16 ( t x t D O B . T e x t ) ; Y e arsO ld ; (iDOB > 1 0 00)

663

Y e a r s 0 1 ci c 1s
._

3 0 2

iD O B ;

i > v -.i i

..'ici

1 c1

i I.'

2 ;

! ! ; 1' i ; : : - -1: ' A i . r\ 1: :*

e a i s l d . T o S t. r i n q ( i

"

years

F : n esta parte del codigo. deber realizar algunas tareas. F.n primer lugar, debe convertir en un valor entero el ao que se introduce mediante la clase C o n v e r t A continuacin, dependiendo del tamao de ese ao (dos o cuatro dgitos), calcule la edad en consecuencia, usando como ao actual 2 0 0 2 . Una vez que se ha calculado la edad, asigne la edad y una cadena a su etiqueta i;r r ^ n t . nqrr. Su aplicacin ya es funcional, pero aunque ha asignado el resultado a la etiqueta adecuada, todava no se muestra la pantalla que contiene la informacin. Hn la ultima linea del listado 30.2. asigne ActiveForm a ForrC. Esto carga Form2 en el nav egador del usuario para mos trar los resultados. Puede ejecutar esta aplicacin pul sando F5 y si todo el codigo se ha realizado correctamente, se abrir el navegador Web que tenga por defecto. Para ver esta aplicacin en un dispositivo mvil, ejecute su emul ador preferido e introduzca la URL adecuada. La figura 30.3 muestra la aplicacin ejecutndose en un emulador de Pocket PC
3 In te rn e t Explorer 9 :4 Ip

|http://power iou; e / VourAge / (yt g t ||Go | rear ofEnith: I1973.

Show Age

View Tools

B |*

Figura 30.3. E j e c u c i n d e Y o u r A g e en un e m u l a d o r d e P o c k e t P C

Tras introducir su ao de nacimiento, haga clic en el botn S h o w Age v se le mos trara el Form2. como muestra la figura 30.4. Felicidades por su primera aplicacin Web mvil. Aquellos que usaron Internet Fxplorer o el emul ador de Pocket PC para hacer su prueba, se estarn p re gu nt an do como se mos trara la aplicacin Web en un telfono mvil. La figura 30.5 muestra la misma aplicacin ejecutndose en el emulador de telefono mvil Nokia.

664

3 I n t e r n e t E xplorer
h t t p :// pow er house,/ Yout A ge/ (ytgt 29 year; old

9 :4 2 p
-]|tio|

T r; A ijdin

View Tools N-1

[]

B |*

Figura 30.4. R e s u l t a d o d e Y o u r A g e en un P o c k e t P C

Figura 30.5. N o k i a 7 1 1 0 e j e c u t a n d o la a p l i c a c i n Y o u r A g e

Como puede ver. la pagina presenta un aspect o muy parecido al que mostraba en los anteriores emuladores, excepto en algunos detalles de desplazamiento entre opciones. Como los Pocket PC son dispositivos en los que se seala y se hace clic, el despl azami ent o se realiza mucho mas suavemente. El telefono mvil, por otra parte, realiza todos sus desplazamientos entre opciones usando sus. a pr o x i m a d a mente. 20 botones. Es decir, no puede simplemente hacer clic en un botn o un vnculo par a avanzar; debe usar los botones par a desplazarse hacia arriba o abajo y seleccionar los vnculos antes de poder seguirlos.

665

Funciones de los dispositivos mviles


La clasc System .Web .Mobile .MobileCapabi lities contiene x a n a s docenas de propiedades que se usan par a detectar las funciones de un d is po sitivo mvil. Por ejemplo, puede c on sul t ar la resolucin de pant al la de un dispositivo, c o mp ro b ar si es de color o de blanco y negro y consul tar si el di sp o sitivo es ca paz de mandar correo, por no mb rar solo algunas. Al crear aplicaciones We b mviles, es importante tener en cuenta los distintos tipos de dispositivo que pueden acceder a la aplicacin. A diferencia de los navegadores convencionales, cuya funcionalidad varia muy ligeramente, puede haber enormes diferencias entre ver una pgina en un telfono mvil o. por ejem plo. en un PDA que utiliza Wi ndows CE. Debe as egurars e de que sus paginas sern procesadas adecuadament e por cada dispositivo. Empiece usando la clase De vi ce para co mp ro ba r el numero de caracteres mximos, horizontal v verticalmente, que admite la pantalla de su dispositivo mvil. Abra la aplicacin YourAge que cre en el listado 30.2 y agregue dos controles Labe! a Form2. Cambi e las propiedades ame de estas etiquetas a ]b.i Height v iblWidth. Ahora debe modificar el cdigo fuente original par a llenar estas etiquetas des pus de que se muestre Form2. El listado 30.3 contiene el codigo que debe aadir (en negrita) para que la nuev a funcionalidad surta efecto.
Listado 30.3. C m o m o s t r a r las f u n c i o n e s d e un d i s po s i t i vo prvate void Command l_Cli ck (ob j ect sender, System. EventArgs e ' i

{
mt int f iDOE = Syst em .C on ve rt .T o l n t 16(t x t D O B .T e x t ); YearsO 1d ;

!i DOB iGuO) YearsOld = 2 002 - i D O B ; e 1s e YearsOld = 100 - iDOB + 2; lblCur re nt Ag e.Text = Y e a r s O l d .T o S t r i n g () + " years od." ; Ib 1H e i g h t .Text = "Height: " + D e v i c e .Se r e e n C h ar ac te rs He ig ht ; IblWi dt h.Text = "Width: " + D e v i c e .ScreenCharactersWidth; ActiveForm = For m 2 ;

} En un Pocket PC. puede conseguir 17 x 34 caracteres, mientras que en un telefono mv il Nokia 7110 slo puede conseguir 4 x 22. como muest ra la figura 30.6. No todas las propiedades de esta clase funcionan en todos los dispositivos. El archivo de avuda de Mobile Internet Toolkit de Microsoft contiene una tabla de

666

funciones de los dispositivos que define qu propiedades funcionaran n ormal men te con HT M L. c H T M L y con W M L .

Figura 30.6. A l t u r a y a n c h u r a d e pant al l a e n un e m u l a d o r d e N o k i a

El cuadro de herrami ent as de Visual Studio N E T tambic'n tiene un control llamado DeviceSpecific que puede ser situado en un formulario par a que realice ciertas tareas (dependiendo del dispositivo con el que se este c om u n i c a n do). Esto se consigue mediante filtros y reduce considerablemente el esfuerzo que sera necesario p ar a codificar todos los distintos contextos posibles.

Funcionamiento de los controles mviles


Los controles We b mviles deben ser muy verstiles a la hora de mostrar interfaces v isuales. Algunos controles necesitan mas espacio del disponible en la may ora de los dispositivos mviles. C uando esto sucede, el control debe determi nar como manej ar la situacin. Las siguientes secciones estudian dos de estos controles. Calendar e Image. v cmo modifican sus interfaces visuales c u a n do es necesario.

Cmo usar el control Calendar


El control Calendar permite mos trar un completo calendario en su pagina Web mvil. Para co mpro ba r lo verstil que es este control, cree una nueva aplica-

667

cion Web mvil y coloque un control Calendar en el Forml del proyecto. Cuand o ejecute esta nueva aplicacin mediante su navegador por defecto o m e diante el emul ador de Pocket PC. ver un calendario mensual completo que per mite hacer clic en cualquier da de la semana. En la figura 30.7 se muestra esta aplicacin ejecutndose en un Pocket PC.
1 3 in ternet Explorer 10:G3p -|jGo|

h ttp ://po w e r house/schedule/ (g go . January 2001' _ Sun Mon Tue Wed Thu Fri Sat

n
10 20

^ 14 21

S 10i 22

9
lu 20

10 11 12 17 10 in 04 20 2n

View Tools 4 [?|

f^~|

H |*

Figura 30.7. A p l i c a c i n d e p r u e b a d e C a l e n d a r e j e c u t n d o s e en un e m u l a d o r d e
Pocket P C

(,Como puede mostrarse este calendario en un dispositivo mucho ms pequeo, como por ejemplo un telefono mvil? El control Calendar sabe en qu tipo de dispositivo va a ser mostrado y cambia su interfaz de usuario en consecuencia. La figura 3 0 . X muest ra esta mi sma aplicacin Web ejecutndose en un emul ador de telefono mvil. Ya no ve el calendario, sino que ve la fecha actual seguida de dos opciones. Estas opciones le permiten introducir directamente una fecha o b u s c a r la semana a semana y luego por cada da de la semana. Este tipo de c omport ami ent o no exige ningn tipo de pr ogr amaci n, lo que libera al p ro gr amado r de mucho trabajo.

Cmo usar el control Image


El control Image es otro control nico muy parecido al control Calendar. Le permite mos trar una imagen en varios tipos de dispositivos mviles con poca o ni nguna programacin. Cree una nuev a aplicacin Web mv il de C# y coloque un control Image en Form I . Proporcione a la ImageUr 1 de este control Image la ruta de la imagen que desea mostrar. Esta imagen puede ser un m ap a de bits (brnp). una imagen J P EG (jpg) o alguno de los otros tipos que acepta. Para el ejemplo, escoja una imagen en color jpg . Al ejecutar esta imagen en un Pocket PC se muest ra la imagen correctamente, como muest ra la figura 3 0 .

668

Figura 30.8. Aplicacin de prueba de Calendar ejecutndose en un emulador de Nokia

| m] In ternet Explorer

10:17p

h ttp ://pow erhouse/S lidebhow /furpi r ||Go|

View Tool*

(?]

Q]

Figura 30.9. P ocket PC muestra la imagen sin problemas aparentes

Si intenta ver esta mi sma pagi na con el emul ador de telfono mvil Nokia, recibir un mensaje de error indicando que no se pudo cargar la pgina. Esto obviamente es debido a que la pgina no es de un tipo que se pueda ver en una pantalla en blanco y negro de un t amao tan pequeo. Sin embargo, se puede solventar este problema. Puede convertir su imagen J PG en una imagen de m ap a de bits de dos colores (blanco y negro), tambin conocido como de mapa i/e bits inalm brico ( W B M P ) . que el dispositivo mm/1

669

puede procesar. En el evento Page Load del Forml. puede comp rob ar la propi edad Device .PreferredRenderingType par a ver qu imagen debe ser cargada. Si esta propi edad devuelve wmlll. debe a j u st ar la propi edad ImageUrl del control Image a WBMP picture; en caso contrario, puede m os trar el original.

Paginacin en dispositivos mviles


La p a g in a ci n es la capaci dad de un dispositivo mvil de dividir grandes cantidades de contenido en varias pginas de informacin. Esto sucede, por ejem plo. cuando se muestra una larga lista de contactos en un formulario Web mvil y el dispositivo concreto no puede most rarl o entero en su pequea pantalla. Le al egrara saber que puede p ro g ra ma r este tipo de comport ami ent o par a que su formul ari o Web mvil lo controle a ut omt icame nte con slo c amb ia r dos p r o piedades. La propiedad Pagnate, cuando es True. divide aut omt i came nt e todo el contenido en v arias pgi nas de informacin, dependiendo de las posi bi li d a d e s de su d i s p o s i t i v o r e m o t o . T a m b i n d e b e a s i g n a r la p r o p i e d a d ItemsPerPage a un control det erminado (por ejemplo, el control List) para forzar la paginacin de un determinado nmero de elementos. Sin embargo, por lo general esto no es necesario ya que el nmero por defecto, siete, suele ser dar buen resultado. Puede c o m p r o b a r l o c r e a n d o un a n u ev a a p l i c a c i n W e b mvil l l a ma d a Contacts. Asigne a la propiedad Paginate de Forml el valor True y agregue un control List a la pgina. Dle a la propiedad ItemsPerPage del control Li st el valor 7. Ahora debe agr egar al gunos elementos a este control List, como muest ra el siguiente codigo:
L i s t 1 .1t e m s .Add("Kim Pac k ") ; L i s t 1 .I t e m s . A d d ("Timothy H y d e " ) ; T iis t 1 .11 ems .Add ("Donna Ma lone " ) ; I ,is t 1 .11 ems .Add ("Joshua Truebl ood " ) ; List] .Items .Add ("Staci S p r m g e r " ) ; L is t 1 .11 ems .Add I" C h n s S t ephens " ) ; List J .I t e m s . A d d ("Amy Sherman") ; Listl.lt e m s .Add("Steve M i l l i o n " ) ; Lis 1 1. I t e m s .Ad d("Jim Mattingly") ; Listl.lt e m s .A d d ("Ryan B o yl es ") ; Listl.lt e m s .A d d ("S c ott Leathe r s ") ;

Estos 1 1 elementos se agregan a su lista. Por tanto, deberia de ver siete ele mentos en la pri mera pagina, junto a un v inculo Next a una segunda pgina que contiene cuatro elementos. Ejecute la aplicacin en el dispositivo mvil preferido. C omo se esperaba, sus primeros siete elementos aparecen en la pri mera pgina, junto a un v nculo hacia la siguiente pagina, como muest ra la figura 30.10.

670

! iPAQ

l-| n | x | : Tools Help

File

Zoom

'
s

(http: / 'pow e i hcuj


Kim PacTimothv Hycie Donna Malone

e /' . o n ta ct s/ (u - urt

-I

Joshua Ti ueblood Staci Springet Chus Stephens Amy Slier man

View Tools 0

3 'J i

\2

E J| -

Figura 30.10. Los siete primeros elementos de la lista

El usuario puede hacer clic en el boton Ne::t para ver la segunda pagina. En la segunda pgina, no tiene cuatro elementos, como se esperaba, sino siete ele mentos. debido a que el control List envolvi los contenidos de la primera pagina en la segunda, como muest ra la figura 3 0 . 1 l .
i ...... i

iPAQ File Zoom

m m m

Tools

Help

m
V 1 h ttp :// power house/ Lont:acts/ (U ur t 1 C Steve Million Jim Mattingly

Scott Leathers t im Pack Timothy Hyde Donna Malone

View Tools < - 0 { 3

H |-

Figura 30.11. Los elementos de la lista restantes se muestran en la segunda pgina.

Como a cabamo s de demostrar, cuando la paginacin esta activada, se pueden aprov echar varias propiedades, como Page. que le permite especificar un n um e ro de ndice de la pgina que va a ver.

671

Resum en
Hn este captulo, liemos estudiado los diferentes rasgos de Mobile Internet Toolkit. que le permite implement ar contenido Web en dispositivos mviles. He mos construido x a n a s aplicaciones que demuest ran como los controles We b m viles ca mb ia n di nmi cament e su modo de present aci n en tiempo de ejecucin, dependiendo del dispositivo mvil en el que se estn ejecutando. Tamb in hemos repasado los modos de detectar las funciones del dispositivo par a apr ovech ar las caracter st icas de varios dispositivos mviles. Aunque el captulo solo ha explicado brev emente algunas de estas caractersti cas. ya dispone de un excelente punto de partida para crear contenido Web muy dinmico para ser i mplementado en dispositivos mviles.

672

Parte V

C# y.NET Framework

673

EY1 31 Cmo trabajar con ensamblados

El codigo creado par a apr ovechar las ventajas de N E T Framevvork se compila en una unidad de empaquet ado llamada e n s a m b la d o . Los ensambl ados son el corazon de la implementacin del cdigo y una estrategia de seguridad par a NE T Framevvork. de modo que es importante entender lo que son y su modo de c om po r tamiento. En este capitulo, estudiaremos los ensambl ados y como escribir codigo C# par a t raba jar con informacin en ellos. N E T Framevvork contiene una clase lla m ad a As sembl y que hace que t raba jar con ensamblados sea algo muy sencillo y este captulo le presenta los entresijos de la clase Assembly.

Ensamblados
Los ensamblados pueden contener cdigo, recursos o una combinacin de a m bos. El cdigo de un ens amb la do debe contener las instrucciones reales del Len guaje intermedio de Microsoft ( MS IL) que pueden ser ejecutadas por el Entorno comn de ejecucin ( C LR ) y un m anifiesto que descri ba el contenido del cdigo. Los manifiestos contienen tipos y ms informacin descriptiva que describen el cdigo al CLR. Los ensamblados tambin forman los lmites del cdigo encerrado entre ellos. Los ensamblados forman los lmites de tipos, en los que cualquier tipo

675

que pueda usarse en cualquier cdigo . NET procede de un slo e ns ambl ado y los tipos con el mismo nombre procedentes de diferentes ensambl ados son. de hecho, tipos diferentes. Los ensambl ados tambin forman un lmite de seguridad, por medio del cual todo el codigo del ensambl ado tiene el mismo conjunto de informa cin de seguridad, restricciones y permisos. Los ens amb la do s se empaqu et an mediante el archivo ejecutable portable de Win32 v pueden ser empaquet ados como DLL o EXE. Cualquier codigo generado por un compilador compatible con el C'LR y compilado en un ejecutable de cons o la. un ejecutable Wi ndows o una biblioteca es emp aq ue tad o en un ensamblado. Este paquete forma una unidad de implementacin par a un conjunto de tipos de un ensambl ado. No piense que solo se considera ens ambl ado al codigo N ET basado en DLL. Cualquier paquete de codigo NET. recurso o metadato que tenga como objetivo un ejecutable o una biblioteca es un ensambl ado, incluso si el paquete tiene la forma de un ejecutable. Las aplicaciones WinForms. por ejemplo, son ensambl ados N E T vlidos, igual que las bibliotecas de clase b as adas en DLL. Tenga en cuenta que el c ompi lador de C# tambin puede generar mdulos, pero esos mdulos no son ensamblados. Los mdulos son fragmentos de codigo (y p robablement e recursos) compilados que se convertirn en un e ns ambl ado mas tarde. Los mdulos pueden contener M S IL y met adatos que describen los tipos que se encontraron en el modulo, pero no contienen un manifiesto. El C L R no puede abrir ni ejecutar modulos y por tanto, stos no pueden ser considerados ensamblados.

Cmo encontrar ensamblados cargados


Empez aremos a est udi ar el concepto de ens ambl ad o escribiendo una pequea aplicacin de consola que escribe un poco de informacin sobre los ensambl ados cargados en un proceso. Si la informacin de tipo procede de los ensambl ados, el C L R debe ca r ga r la informacin del ens amb la do en el espacio de proceso de un fragment o de cdigo N E T que se est ejecutando. Por cada tipo al que se hace referencia en una aplicacin, el C L R debe r ecuper ar informacin del ensamblado que contiene el tipo, de modo que pueda usar el tipo adecuadamente. Estos e ns am blados reciben el nombre de ensam bla dos referenciados, porque otro en s am blado N E T les hace referencia. La operacin de descubri r la lista de ensambl ados a los que se hace referencia es un proceso sencillo. Observe la sencilla aplicacin de consola del listado 31.1.
Listado 31.1. Cmo recuperar una lista de ensam blados referenciados using using public System; System.Reflection; ciass MamClass

676

static void M a i n ( )

{
Assembly EntryAssembly;

EntryAssembl y = Assembly .GetEntryAssemb l . y () ; toreach(AssemblyName Name in Enti yAs s e m b l y .GetReferencedAssemblies ( )) Consolp.WriteT,ine ("Name: {0 }" , Name .ToStri ng ( ) ;

El listado 3 1.1 presenta muchos conceptos importantes. En primer lugar, p re senta una clase N E T llamada Assembly. que se incluye en el espacio de 110111bres Systom .Rcf lcction de.NET. La clase Assembly es la clase mediante la cual cualquier codigo N E T puede exami nar v t rabaj ar con los contenidos de un ensambl ado NET. Si necesita t rabaj ar con un ensamblado NET. debe usar la clase Assembly par a ex ami na r los contenidos del ensamblado. El segundo concepto importante del listado 31.1 es el de ensam blado de entra da. El e ns ambl ado de entrada es el ens amb la do que se ejecuta en primer lugar en el proceso. Para ejecutables, como el ejecutable de consola creado por el listado 3 1.1. el ens ambl ado de entrada es el ensambl ado que contiene el punt o de entrada de la funcin. Normalmente, el punto de entrada recibe el nombre Ma i n ( ) en los ensambl ados basados en ejecutables, aunque en C# se puede c a mb ia r mediante el ar gume nt o / m a i n y especificando otro punto de ent rada par a el ensamblado. El acceso al e ns ambl ado de ent rada se realiza mediante un mtodo esttico de la clase Assembly ll amado GetEntryAssembly ( ) . Este mtodo devuelve una instancia de un objeto Assembly que hace referencia al ens ambl ado de entrada. El tercer concepto importante del listado 31.1 es el de que un ensambl ado puede contener ensambl ados a los que se hace referencia. La informacin de los ens ambl ados a los que se hace referencia se obtiene mediante una llamada a un mtodo de e ns ambl ado llamado GetReferencedAssemblies (). Este m todo devuelve una mat ri z de objetos de una clase l lamada Assembl yName. Los objetos de AssemblyName describen compl et ament e el nombre de un e n s a m blado o se pueden convertir en una sencilla cadena mediante el conocido mtodo ToString (). Obt ener una representacin de cadena de un nombre de e n s a m blado facilita el que las aplicaciones muestren informacin del nombre del e ns am blado en las interfaces de usuario. Con esta informacin, resulta sencillo adivinar lo que hace el listado 31.1. El cdigo obtiene una referencia al ens amb la do de ent rada y enva los nombres de los ensambl ados a los que se hace referencia a la consola. Si se compila y ejecuta el cdigo del listado 31.1, se enva la siguiente informacin a la consola:
ame: mscorlib, V er si o n = 1.0.3300.0 , Culture = n eu t r a l , PublicKeyTo ken = b77a5c561934e089

Cmo sabe N E T Framevvork que el listado 31.1 hace referencia al e ns a mb l a do mscorlib: Esa informacin se al mac en a en el manifiesto del ens ambl ado

677

del Listado 31.1. Para ver esta informacin, inicie la her rami ent a I LD A SM de N E T Fr amewor k y abr a el ensambl ado del listado 31.1 en ella. Ha g a doble clic en la e nt rada del manifiesto en el rbol que apa r ec e r y se mo st rar el manifiesto p ar a el ens ambl ado en una ventana distinta, como muest ra la figura 31.1.

.assembly extern nscorlib

<
.publickeytoken = (B7 7 f l SC 56 19 34 E0 89 ) .uer 1:0:3300:0

// .z\U.4..

>
.assembly 'Listing31 1' .custom .custom .custom .custom .custom .custom .custom instance instance instance instance instance instance instance uoid uoid uoid uoid uoid uoid uoid [mscorlib [mscorlib [mscorlib [mscorlib [mscorlib [mscorlib [mscorlib ]System.Reflection. ]System.Reflection. ]System.Reflection, ]System.Reflection. ]System.Reflection. ]System.Reflection, ]System.Reflection flssemblyKeyNameflttribute: :,ctor(stt OssemblyKeyfileAttribute::,ctor(stf flssemblyDelaySignflttribute: :.ctor(t AssemblyTrademarkAttribute::.ctor(! AssemblyCopyrightflttribute: : .ctor(< flssemblyProductflttribute::,ctor(sti fssemblyCompanyfittribute::.ctor(sti

iL

________I
Figura 31.1. Referencias a un ensamblado externo de un manifiesto

2f

El manifiesto contiene una entrada con la etiqueta . assembly extern. Esa ent rada del manifiesto describe un ens ambl ado externo del que depende el e ns ambl ado que contiene el manifiesto. Esta ent rada registra que el ensambl ado que contiene este manifiesto depende de la versin l . 0.3300. 0 de un ens ambl ado externo l l a m a d o mscor 1 ib. N E T Framework debe leer este manifiesto y cargar los e ns amb la dos dependientes en el espaci o de p roces o que se est e jecutando en ese momento.

NOTA: El ensamblado mscorlib contiene informacin vital para clases como System. Object y siempre se la hace referencia sin ningn argu mento especial de compilados. El resto de ensamblados pueden referenciarse usando la opcin / r para el compilador de lneas de comando de C# o con el elemento de men Agregar referencias de Visual Studio NET.

Nombres seguros de ensamblado


El resultado del listado 31.1 puede parecer un poco confuso al principio, ya que mues tra algo mas que el simple nombre del ensambl ado, que en este caso se llama mscor 1 ib. Este resultado en realidad define cuatr o fragmentos de informacin par a el nombre del ensamblado: El nombre en si (mscorlib) Un numero de versin (1.0.3300.0)

678

Informacin de referencia cultural ( n e u t r a l ) Un smbolo de clave publica (b 7 7 a 5 c 5 6 1 9 3 4 e 0 8 9) Como mnimo, todos los ensambl ados contienen un nombre, una versin y una referencia cultural. Sin embargo, los ensambl ados pueden contener una clave publica. Un ensambl ado que contiene los cuatro fragmentos de informacin tiene un nombre seguro. Solo los que contienen nombres seguros pueden al mac enar se en la cache de ensambl ados local. La cache de ensambl ados global ( GAC) es una coleccin b a sada en disco de ensambl ados N E T a los que puede acceder cualquier fragment de codig . NET del equipo que contiene el GAC. N E T F ramework busca un ens ambl ado en el directorio del ens ambl ado de entrada cuando debe ca r ga r un ensambl ado. Este esquema de i mplementacion es sencillo; sin embargo, puede crear \ arias copias de un ens ambl ado en un \ o l u me n de disco para los e ns a m b l a dos mas utilizados, ya que cada ensambl ado necesita ser c opiado en cada e n s a m blado de entrada que necesite el e ns ambl ado al que se hace referencia. NE T Framework incluye la GAC par a simplificar las cosas, de modo que los e n s a m blados mas utilizados, como los ensambl ados incluidos en N E T Framework. pueden ser colocados en un equipo una vez y ser referenciados v a n a s \eees. .NET Framework co mp rue ba la GAC' cuando busca un ensamblado. Cuando . NET Framework se instala en un equipo, el proceso de configuracin nstala una extensin de interprete de comandos del Exp lo rado r de Window s que hace que la GAC ap arez ca como una carpet a de Wi ndo ws estndar. El directorio base de Windows, que es C :\WINDOWS en casi todos los equipos, contiene un ens ambl ado de llamada a carpet as en los equipos que tienen instalado NE T Framework. Esta carpet a muest ra los contenidos de la GAC. con informacin de nombre seguro en las columnas, como muestra la figura 3 1.2 Puede colocar e nsambl ados con diferentes nombres seguros uno junto al otro en la cache de en sambl ados global, aunque los nombres de segmento coincidan. Por ejemplo, la versin 1. ( ) . ( ) . ( )de un ensambl ado llamado assemb 1y .d 11 p ue de estar instalada en la cach de ensambl ados global j unt o a la versin 2 .().().() de un ens amb la do tambin llamado assembly. dll. El codigo que hace referen cia a un ens ambl ad o con nombre seguro tiene el nombre seguro del ensambl ado escrito en el manifiesto y siempre se enlaza al ensamblado con ese nombre seguro, aunque otros ensamblados con algunos componentes del nombre seguro sean igua les. Si un e n s a m b l a d o de e n t r a d a hace r ef er enci a a la ver sin 1.0.0.0 de assembly.dll, por ejemplo. . NET Framework siempre carga la versin 1.0.0.0 de assembly .dll en el espacio de proceso del ens ambl ad o de entrada, aunque existan otras versiones de assembly .dll en la GAC. La operacin de asignar la informacin que compone un nombre seguro es tan sencilla como agregar a l gu nos atributos a uno de los archivos de cdigo fuente par a un proyecto. Estos atributos pueden agregarse a un archivo fuente que contenga cdigo C# o p u e den agregarse a un archivo distinto que slo contenga los atributos en s.

679

f e a s s e m b ly Ai chivo l A t r s D ireccin] Edicin * Ver ^ Favoritos. Herramientas Bsqueda Ayuda Gat petas ^ 3 j Tipo J i Vnculos

'

i 'IN [" -v .'i = ,^rnt.i--

[ Nombre del ensamblado global

Version l ; ,|||; I

R efe ren da cultural

Simbolo (token) d ... j ! i i V ; i n ^ [ l d r .L ia jj

:i|A [ "

'[ !:
l . ii. ii. m -..-i.tb p a 1.' . ' I p ! ii '4

: J1 r ...-'.L ili '" I-.I- '11 1 r

n'f-. l f "_]ii

-.i ,1 1

; : i

- ,i! ,i .ir--, .'.i,;',

- -r-t.

:i|

' ' vt.

;;

; r; 1

: I 1 rfli, nM ]r; .r, i ....... 1-1 .:n tin ,fi r : :.jr !i.;

L r' : tr ' > 1l.y If; .

i'i : - nr 11

i ! i m . -' 1 1 . ii . 1 1 , 1

Figura

3 1 . 2 .

Vista de la GAC corno una carpeta de W in do w s

NOTA: VS.NET aade un archivo fuente llamado A s s e m b ly l n f o . e s a los nuevos proyectos de C# y coloca los atributos necesarios para los ensamblados de nombre seguro de ese archivo fuente. El nombre de archivo puede cambiarse una vez que se ha creado y seguir funcionando, siempre que el archivo renombrado siga siendo parte de la creacin del proyecto.

Cmo asignar la informacin de versin


Puede e st abl ecer la versin del e ns a m b l a d o u s a n do un a t r ib ut o ll amado

AssemblyVersion. Este atributo recibe una cadena que describe el numero


de versin del ensamblado, que es una serie de c uatro nmeros enteros. El primer numero entero es el numero de versin principal, el segundo es el numero de v ersin secundaria, el tercero es el nmero de compilacin y el cuart o es el n u m e ro de revisin. Puede especificar los cuatro nmeros par a un ensambl ado usando el atributo

AssemblyVers ion:
[asse mb 1y : AssemblyVersion (" 1 .0 .0 .0 " ) ]

Para hacerlo ms sencillo, el compi lador de C# genera un nmero de revisin aut omt i came nt e si se usa un asterisco en lugar de un nmero de revisin:
[asse mb 1y : A s s e m b 1 yVersion ("1.0.0. *") ]

680

Esta sintaxis indica al compi lador de CU que debe asi gnar el numero de r e\i sion que prefiera al ensamblado El compilador de CU calcula el numero de segun dos entre la medi anoche v la hora en que compilo su codigo. d u i d e el numero entre dos y usa el resto de la divisin como base para generar un numero de revisin nico. (A esto se le llama operacin mdulo 2. ya que una operacin de modulo calcula el resto de la divisin entre los dos operandos.) Esto permite generar un numero de \ er si on nico para cada compilacin. Para facilitar aun mas las cosas, el compi lador de CU genera automt icamente un numero de compilacin v un numero de revisin si se usa un asterisco como numero de compilacin:
Ta s s e i n b l y : A s s emb 1 y V c r s i on ( " 1 . 0 . * " )

Esta sintaxis ndica al compi lador de CU que debe asi gnar el numero de c o m pilacin y el numero de revisin que prefiera al ensamblado. Ademas del calculo aut omt ico del numero de revisin descrito, el compi lador de CU tambin calcula un numero de compilacin usando el numero de dias entre el 1 de enero del 20 0 0 \ el dia en que se produjo la compilacin.

Cmo asignar la informacin de referencia cultural


La informacin de referencia cultural especifica la referencia cultural para la que esta diseado el ensamblado. La informacin de referencia cultural se especi fica mediante un atributo llamado A s s e m b l y C u 1 t u r e . El atributo de referen cia cultural recibe una cadena que describe la referencia cultural para la que se diseo el ensamblado. La cadena puede especificarse mediante una cadena vaca que informa a N E T F ramcwork de que la referencia cultural del ens ambl ado es neutral y no contiene cdigo o recursos de una cultura especfica:
[a s s e m b 1 y : As s e m b 1yCu I t u r e ("") ]

La cadena tambin puede especificar el idioma y el pas par a los que se ha diseado el ensamblado. El formato de la cadena que especifica la informacin del idioma y el pas debe estar registrado en Internet RFC' 1766. que tiene la forma idioma-pas:
[assembly: A s s e m b l y C u l t ur e (" en-US " , )j

TRUCO: El estndar RFC 1766 recibe el nombre de "Etiquetas para la identificacin de idiomas" y est disponible en la direccin de Internet en h t t p :/ / w w w .ietf.org/rfc/rfcl766.txt.

Slo los ensambl ados bas ados en DLL deben especificar la informacin de referencia cultural. Los ensamblados basados en EXE deben usar una cadena vaca par a la informacin de referencia cultural. Si se especifica informacin de

681

referencia cultural par a un ensambl ado basado en EXE se produce un error del compi lador de C#.

Cmo asignar la informacin de clave


N E T Framework incluye una utilidad de lnea de comando llamada la utilidad nombre seguro o. para abreviar, sn. que ayuda a crear nombres seguros par a los ensambl ados NET. Una de sus caractersticas ms usadas permite la creacin de un nuevo conjunto de claves de firma digital que pueden instalarse en un e n s a m blado y ser usadas como parte de un nombre seguro en un ensamblado. Las claves estn escritas en un archivo binario cuno nombre se especifica a la utilidad sn mediante el ar gu me nt o -k. como se puede apr eci ar en la siguiente lnea de c o mando:
o
11

y k ri i r . s i " ik

Esta lnea de comando indica a la utilidad sn que debe generar un nuevo par de claves de firma digital y enviar las claves a un archivo binario llamado Kc: y F v . t :r .snk. Este archivo es nombrado como un argument o para un atributo llamado Assc.-rnb i y K e y F i ^ c :
[ a s s e- m b I y : A .s s . rnl) 1 y K y r x l o " F e- y F a i r . s n k " ) 1

La extensin . snk. no es imprescindible. Se puede usar cualquier extensin par a el archivo clave generado por la utilidad nombre seguro.

Cmo trabajar con la clase Assembly


Una vez que conoce la clase Assembly. puede estudiarla mas atentamente. Las siguientes secciones describen como puede usar sus propiedades y mtodos.

Cmo encontrar la informacin de ubicacin del ensamblado


La clase Assembly contiene propi edades que describen la ubicacin de un ensamblado. Una propiedad Locat ion especifica la ubicacin del archivo que contiene el manifiesto p ar a el ensamblado. Una propiedad CodeBase especifica la ubicacin de un ensamblado como un Identificado!' de recursos uniforme (URI). La propiedad relacionada EscapedCodeBase especifica el URI del e ns a m b l a do. con caracteres especiales reempl azados por los cdigos de escape equi val en tes (por ejemplo, los espacios en los valores CodeBase se sustituyen por la s ecuencia de escape 2 0 en la propiedad EscapedCodeBase). La propiedad GlobalAssemb 1 yCache es un bool eano que devuelve True si el e ns a m b l a do se ha ca rg ad o desde la GAC y Pal se en caso contrario. El listado 3 1.2 muest ra una sencilla aplicacin de consola que obtiene una referencia p ar a el e ns ambl ado de entrada de la aplicacin y enva su informacin de ubicacin a la consola.

682

Listado 31.2. Cmo examinar la inform acin de ubicacin using System; using System.Reflection; public class MainClass void Main() EntryAss em bl y;

{
static

{
Assembly

EntryAssembly = A s s e m b l y .G e t E n t r y A s s e m b l y (); Console.WriteLine ("L oc at io n: {0 }" , E n t r y A s s e m b l y .Location) ; Console.WriteLine ("Code Base: {0}", E nt r y A s s e m b l y . C o d e B a s e ) ; Console.WriteLine("Escaped Code Base: (0)", Ent ryAssembly.EscapedCodeBase) ; Console.WriteLine ("Loaded from GAC : {0}", Ent r yAs s e m b l y .GlobalAss emblyCache) ;

} } Si sc compila y ejecuta el cdigo del listado 3 l .2 se enva la siguiente i nforma cin a la consola:

Location: C : \ D o c u m e n t s and Settings\User\My Do c u ments\ L i s t i n g 3 1 - 2 \ b i n\Debug\Lis ting31-2.exe Code Base: f i l e :/ / / C :/Documents and Settings/User/ My Documents/Listing31-2/bin/Debug/Listing31-2.exe Escaped Code Base: f lie : / // C : / D o c u m e n t s 2 a n d 20 Settings/User/My: 20Documents/Listing31-2/bin/Debug/ Listing31-2.exe Loaded from GAC: False

La informacin de la ruta vara segn la ubicacin real del cdigo cuando se ejecuta, pero los resultados son bsicamente los mismos: La propiedad Location hace referencia a una posicin en el disco y las propi edades CodeBase y EscapedCodeBase hacen referencia a la ubicacin del ensambl ado como URL

Cmo encontrar puntos de entrada del ensamblado


Algunos ens ambl ados tienen pun to s de entrada. Imagine un punto de ent ra da como el "mtodo inicial" de un ensamblado. El ejemplo ms obvio de punto de ent rada de un ens amb la do es el mtodo Main ( ) de los ejecutables basados en C#. El C L R carga un ejecutable, busca un punto de entrada al ensamblado y empieza a ejecutarse con ese mtodo de punto de entrada.

683

Los ensamblados basados en DLL. en cambio, no suelen tener puntos de ent ra da. Estos ensambl ados generalmente contienen recursos o tipos usados por otros fragmentos de cdigo y son pasivos, en el sentido de que esperan a ser llamados antes de que se ejecute algn cdigo del ensamblado. La clase A s s e m b l y contiene una propiedad l lamada E n t r y P o i n t . La pro piedad E n t r y P o i n t es un valor de un tipo llamado M e t h o d l n f o . que se incluye en el espaci o de no mbres S y s t e m . R e f l e c t i o n NET. La clase M e t h o d l n f o describe los detalles especficos de un mtodo y al ll amar a T o S t r i n q ( ) sobre un objeto de tipo M e t h o d l n f o se devuelve una cadena que describe el tipo devuelto, el nombre y los par met ros del mtodo. La p r op i e dad E n t r y P o i n t es nula si la referencia del ens ambl ado no tiene un punto de entrada o un objeto M e t h o d l n f o vlido si la referencia del ensambl ado tiene un punto de entrada, como se aprecia en el listado 31.3.
Listado 31.3. Cmo trabajar con un punto de entrada de un ensamblado

u s ii ic j S y s t em ; usinq System.Reflection; public class M a m C l a s s

{
static voici Main (st.nng[ args)

{
Assembly EntryAssembly;

EntryAssembly = Assembly.GetEntryAssembly( ); f(EntryAssembly.EntryPoint == nuil) Consol . W n t e L m e ("The assembly has no entry pomt.") ; e 1 se
ConsoLe.WriteLine (Entr yAs s e m b l y .E n t r y P o i n t . T o S t r i n g ( ) );

I } Si se compila y ejecuta el listado 31.3 se enva la siguiente informacin a la consola:


V o id Main (System. S t r m g [])

En el sencillo ejemplo del listado 3 1.3. la propi edad E n t r y P o i n t nunca es nula, pero siempre conviene c o m pr o ba r la posibilidad de que se p ro du zca un v alor nulo, especialmente con fragmentos de cdigo ms complicados.

Cmo cargar ensamblados


En muchas aplicaciones, a los ensambl ados que contienen los tipos necesarios para una aplicacin se les hace referencia cuando se crea la aplicacin. Sin e m bargo. tambin es posible ca rgar los ensambl ados mediante programaci n. Hay varios modos de c ar ga r un e ns ambl ado dinmi cament e y ca da una de estas tcni

684

cas de carga devuelve un objeto A s s e m b l y que hace referencia a un ensambl ado cargado. La pri mera tcnica de carga de ens amb la do usa un mtodo de ensambl ado esttico llamado L o a d ( ) . El mtodo L o a d ( ) recibe una cadena que pr op or ci o na el nombre del ensambl ado que se va a cargar. Si no se encuentra el ensamblado nombrado, el mtodo L o a d ( ) inicia una excepcin. En ca mbi o, el mtodo L o a d W i t h P a r t i a l N a m e ( ) bu sca el directorio de la aplicacin y la GAC del e ns ambl ado especificado, usando toda la informacin de nombre disponible para el invocador. El listado 3 1.4 muest ra la diferencia entre estos dos mtodos.
Listado 31.4. C mo cargar ensamblados dinmicam ente con Load() y L o ad W ith P a rtia lN a m e () using using using public System; System.Reflection; System.10; class AssemblyLoader LoadedAssembly; L oa dedAssemblyName, bool

i
prvate Assembly

public AssemblyLoader (string Pa r t i a l N a m e )

{
t ry

{
----------------------- ") ; Consol . W r i t e L m e ("h Consol . W n t e L i n e (" Loading Assembly {0}", LoadedAssemblyName); Consol . W r i t e L m e (" H ----------------------- " ) ; f(PartialName == truel LoadedAssembly = As s e m b 1y .LoadW ithPartialName (LoadedAs s e m b l y N a m e ) ; e 1s e LoadedAssembly = Assembly.Load(LoadedAssemblyName ); WritePropertiesToConsoleO ;

}
catch(FileNotFoundException)

{
Consol . W r i t e L m e ("EXCEPTION: Cannot load assembly.") ;

private

void

W r i tePropert ie sT o C o n s o l e ( )

{
Console . W r i t e L m e ("Full Name: {0}", L oa de dA s s e m b 1y .F u i l N a m e ) ; Console . W r i t e L m e ("Location: {0} ", L o a d e d A s s e m b l y .Location) ; Console . W r i t e L m e ("Code Base: {0}", L o a d e d A s s e m b l y .CodeBase ) ;

685

Console . W r i t e L m e ("Escaped Code Base: {0}", L oa de d A s se m b 1y .EscapedCodeBase) ; C o n s o l e .W r i t e L i n e ("Loaded from G A C : {0}", L o a d e d A s s e m b l y .GlobalAssemblyCache ) ;

} }
public class MainClass void M a i n (s t r i n g [] args) Loader;

{
static

{
A s s e m b 1yLoader

Loader = new AssemblyLoader("System.Xml, V e r s i o n = l .0.3 300 .0, Culture=neutral, PubiicKeyToken = b 77a 5c 561934e 089 " , false) ; Loader = new AssemblyLoader("System.Xml", Loader = new A s s e m b l y L o a d e r ("System.Xml",

f a ls e) ; t r ue );

} } El listado 31.4 muestra una clase llamada AssemblyLoader. cuyo c on s tructor recibe un nombre de ensambl ado y un indicador boolcano que especifica si el ensambl ado n ombrado debe cargar se usando un nombre parcial. El constructor carga el ensambl ado y a continuacin llama a un mtodo privado par a escribir algunas de las propiedades de designacin y de ubicacin del ensamblado cargado en la consola. El m t o d o M a i n ( ) del l i s t a d o 3 1.4 c r e a n u e v o s o b j e t o s de la c l as e A s s e m b l y L o a d e r e i ntenta c a r g a r el e n s a m b l a d o de N E T F r a m e w o r k System. XML. que se encuentra en la GAC . de varios modos. Si se ejecuta el listado 3 1 .4 se escribe la siguiente informacin en la consola: H ------------------------------------I Loading Assembly System.Xml, Culture=neutral, PublicKeyTok en=b77a5c5 6 1934e089 V e rs ion =1.0.3300 .0 ,

h ------------------------------------Full Name: System.Xml, V e r s i o n = l .0 .3300.0, Culture = n e u t r a l , PublicKeyToken=b7 7a5 c 5 6 19 34e 0 8 9 Location: c :\w i n d o w s \as s em bly\gac\system, xml \ 1 .0.3300.0 b 7 7 a 5 c 5 c 1 9 34 e 0 8 9 \ s y s t .e m .x m l .dll Code Base: fi 1e :/// c :/windows/assembly/gac/system.xml/ 1.0.3300.0 b77a5c5 619 34e0 8 9 /sy st em .x m l .dll Escaped Code Base: f 1 1 e :///c :/windows/as sembly/gac/sy s t e m .x m l / 1.0.3300.0 b77a5c 5 1934e 0 89/s y.stem.xml .dll Loaded from GAC: True

+------------------------------------

686

Lo a d ing A s s e m b l y S yst em . X m l

X C E P T I O N : Cannot Loading Assembly


Fu ll ame:

load

asse mb 1y

Syst:e m .Xml
Ve r s i o n - 1 . 0 . 3 3 0 0 .0 , C u ltu ie -n e iitra l ,

System . X m l,

Pub 1 1 c K e y T o k e n = b 7 7 a 5 c5 : 1 9 34e 089

Location:
b
1

c :\windows\as sembly\gac\sys t em .xml \ 1 .0 . i 3 U( ;.U

7 a 5 c 5 6 1 9 3 4c 0 8 9 \ s y s t em 1 1 o : / / / c : / w 1 1 1 d ow s / a s s b77a5cr j.-: 1 9 3 4 e 0 m 1 . d 1.1


e

. x m l.d ll 1 od e Ba s e : I . m . 3 3 0n . 8 r- / s y s t e m . mb 1 y / g a <': / s y s t e rn . rn i /

1 3s a p e ; ' i Code
8 1f 8 8

Base : file :///c :/Vv'indov/s/.issrinbi y/'-IM 'Vsyst . ' m.xml /

/ s y s t em . xml . d 1 8
:

i . a 8: ed

ti um GAC

Ti

Obs cr \ e con atcncion lo que se esta produciendo. En el segundo caso, el nietodo Ma i n ; especifica el nombre seguro para el ensambl ado 8 y - d - 1- 1 . 3 1 :8 . incliiN endo su nombre. c l a \ e publica, i nformacin de \ er si on \ detalles espec fi cos de su referencia cultural. Como el ensambl ado Sy s s< m. . X ri i esta en la GAC. no se al macena en el directorio de la aplicacin y el mtodo Lo v i no puede encontr ar el e ns ambl ado en el directorio que contiene el ejecutable del listado 3 1.4. Sin embargo, como se especifico el nombre seguro para el e ns ambl a do. el mtodo L o a d ( ; tiene suficiente informacin para buscar el ensamblado en la GAC. 14 mtodo l . o a d ; ) puede encontrar el ensambl ado en la GAC \ la operacin de carga se completa con xito. Kn el segundo caso, el mtodo Ma i n ) solo especifica el nombre base del ens amb la do S y s t e m . Xm^. C omo el e n s a m blado S y s t e m . Xml esta en la GAC. no se al macena en el directorio de la a pl i cacin \ el mtodo L o a d ( ) no puede encontr ar el ens ambl ado en el directorio que contiene el ejecutable del listado 3 1.4. Ademas, el mtodo L o a d ( ) no tiene suficiente informacin para ubicar el ensambl ado en la GAC. ya que pueden existir muchas instancias de S y s t e m . Xml en la GAC con diferentes nmeros de versin o claves publicas, por lo que la carga falla. En el tercer y ltimo caso, el mtodo M a i n ( ) solo especifica el nombre base del ens ambl ado S y s t e m . Xml e indica al cargador que encuentre un ensamblado usando solo un nombre parcial. De nuevo, como el ens ambl ado S y s t e m . Xml esta en la GAC. no se al macena en el directorio de la aplicacin y el mtodo Lo a d W1 1 h P a r t i a 1 ame ( ) no puede encontr ar el e ns ambl ado en el d irect o rio que c o n t i en e el e j e c u t a b l e del l i s ta d o 3 1.4. Sin e m b a r g o , el m t o do Loa d W i t h P a r t i a 1 a me ( ) recibe el nombre par cialmente p ropor ci onado e intenta hacer coincidir el nombre con un ens ambl ado de la GAC. C omo se ha propor ci onado un nombre parcial de S y s t e m. Xml y hay un ens ambl ado con el n ombre S y s t e m . Xml en la GAC. la operacin de carga se completa con xito.

687

ADVERTENCIA: N o se recomienda utilizar LoadWithPartialName ( ) .


Si el ensamblado parcialmente nombrado tiene varias copias en la GAC (quizs con diferentes nmeros de versin, referencias culturales o claves pblicas) la instancia realmente cargada puede no ser la versin esperada. Adems, la instancia cargada puede ser una versin diferente de la que pretenda cargar despus de que se hayan cargado versiones ms moder nas en la GAC. Use Load () en lugar de LoadWithPartialName ( ) siempre que pueda.

Cmo trabajar con informacin de tipo de ensamblado


Los ensambl ados pueden contener tipos, recursos o una combinacin de a m bos. Tras cargar un ensamblado, se puede obtener informacin sobre los tipos que se encuentran en el ensamblado. Ademas, se pueden crear instancias de los tipos mediante programacin. Ll listado 3 1.5 muestra estos conceptos.
Listado 31.5. Cmo encontrar y crear tipos de ensamblado us i i ig System; using System.Pelection ; p u b 1 1 c c 1 a s s M a i n C 1ass

I
sta1 1 c v o i .e l M a m (string[ ] a rg s )

{
As s e m b 1y XML A s s e m b 1y ; T y p e [] X M L T y p e s ; XMLAssembly = A s s e m b l y . L o a d ("System.Xml, V ecsi o n - 1 .0 . 3? > ; u . , Cultur e = neut r a l , P u b 1 ic Y e y T o k e r .- b 7 7 a b c b r r. 1C l. 34 e 0 8 9 " ) ; XMLType.s = XMI.Assembl y. GetExportedTypes ( ); foreach (Type XMLType in XMLTypes ! f ob]ecr NewObiect.; t ry

i
C :on s ole. W rite fXMLTyp e .ToSt ring () ) ; Nev/Ob iect. = XMLAssemb 1y.Creatcnst. anee XMLType .ToString ( ) ; i f (IlewGb ' je c t . !- nu 11 ) Con so 1e .Write Line !" - Crcation succe s s f u 1" i ; e 1s e c :on s o 1e .Wi 1 1 e Ll ne !" - CPEATTON ERROR") ;

}
c a t ch ( ' E x cept ion e) {U )" , e .Message i ;

{
( . onso ie .Wr itel, ine ( " - EXCEPTIQN:

688

F1 cdigo del listado 3 1.5 carga el ens ambl ado y s t i r n.: : r r , desde la (AC y llama a un mtodo en la clase Assorr.b 1y llamado Ce t .i x a e . ,r 1 ; Ty para conseguir una matriz de objetos de tipo que representan los tipos que se encuentran en el ensa mbl ado \ pueden ser utilizados o exportados al exterior del ensamblado. H1 eodigo recorre cada tipo de la matriz devuelta e invoca a otro mtodo de en sa mb l ad o llamado C r e a r e l n s t a n e ( para crear una instancia de objeto del tipo nombrado. Si la creacin se realiza con xito, el mtodo C r e a t e l n s t a n e e ( } devuelve una referencia de objeto vlida. Si la creacin no tiene xito. Creat elnst anee ( ) devuelve una referencia de objeto nula o inicia una excepcin, dependiendo de la nat ural eza del error. A continuacin tiene v a n a s lineas de resultado del listado 3 1.5:
- E X "EPTTOIJ : C o n s t n e l u re, s t e m Xm 1 . X P a t h . X P a t h N a v i g a t o r Sy s t e n i . X m l . I H a s X m l No ele - E X C E P T T O N : C on.st.ru ; t. o r -jr. t. yo.* S y .st e n i . X m l . I H a s X m l N o d e n o t found. type S y s t e ni. X m l . X P a t h . X P a t h N o d e I t e : r a t o r EXoEPTIG i; : o j / s t e m . Xni 1 . X P a t h . X P a t h N o d e T t e r a t. o r ii o t. o Linci . o y s t e n i . Xml . E n 1 1 t y H a n d l . i n g C r e a t i o n s 11 o C O S S f Li I type S y s t e m . X m l . I Xm ! L i n e T r . f o S y s t e rn . X ml . I Xm 1 1, i n e l n o
H

S y s t e n i . X m 1. . X P a t h . X P a t h N a v i g a t c o r

I n i ct

EX. 0 E P T T O N : f ound . E XC EP T TO IJ : found.

C on st r u

_ t

oi

on on

t ype type

not not

y ,s t e n i . Xml . X m i N a m e T a b l e -

C o r .s t i i i c t o r

S y s t e 111 . Xml . X m l M a m e T a b 1 e S y s t. em. X ml . N a m e T a b l e S y s t e m . X ml . R e a el S t a t e

C r e a t i on C r e a t i on

succ -ss ful su ccies s f u 1

- Creatio n S y s t e m . Xm i. . V a 1 i d a t i o n T y p e successful S y s t e m . Xm 1 . W h i t e s p a c e H a n d l m g C r e a l i on s u e c o s s f u 1

Las excepciones se producen porque no todos los tipos exportados tienen cons t ructores v con CreateInstanee ( ) solo se pueden crear tipos de referencia con constructores adecuados.

TRUCO: Tras obtener una referencia a un objeto Type, se puede encon trar una referencia al ensamblado que contiene el tipo en la propiedad Assembly del objeto Type. Esto permite al cdigo descubrir el ensam blado que hace referencia a un tipo.

Cmo generar cdigo nativo para ensamblados


C uan do el CLR necesita ejecutar cdigo en un ensamblado, pasa el eodigo a trav s de un compi lador j us to a tiempo (JIT) y dev uelv e el MSIL a un codigo

689

ilativo que puede ser ejecutado por la CPU del equipo. La ventaja del diseo JIT es que es posible enviar cdigo MSIL sin tener que p reocupar se por opt imi zar el codigo para el procesador al que esta destinado. N E T Framcwork probablemente sera exportado a una gran variedad de arquitecturas de CPU de una gran variedad de dispositivos, desde equipos de sobremesa hasta sistemas porttiles e intentar escribir codigo para cada una de estos procesadores podra ser una tarea i mpre sionante. Este t rabajo no es necesario porque cada mplementacion de N E T Framcwork tiene un compi lador JIT que convierte las instrucciones MSIL en instrucciones ptimas para la CPU de destino. Si la principal preocupacin de su aplicacin es el rendimiento, puede c onve r tir el codigo MSIL en codigo especifico par a la C PU de un equipo mediante un proceso conocido como genera cin de imagen nal/va. Durante este proceso, las instrucciones MSIL de un ens ambl ado se convierten en instrucciones especficas de una CPU', que pueden ser escritas en disco. Despus de compl et ar esta gene racin de imgenes nativas, el C LR puede usar este cdigo y puede omitir el paso JIT que normal ment e se emplea en los ensamblados. .NET Framcwork incluye una herramienta llamada G enerador de im ge nes nativas, que genera una imagen nativa para un ensamblado. Esta her rami en ta de linea de comando se encuentra en un ejecutable llamado r v e n . e:-:e \ recibe como entrada un nombre de ensamblado:

La imagen nativa se coloca en una cache de imgenes nativas para e ns a m b l a dos Tenga en cuenta que n j- r, debe ejecutarse en el dispositivo que ejecuta el eodigo generado. Por ejemplo, no puede c onst rui r ensambl ados como parte de .su proceso de compilacin, ejecutar n q e n sobre esos ensambl ados y enviar esas imgenes nativas a sus clientes. El equipo en el que se compi la puede per fectamente tener una CPU diferente de la de los equipos de sus clientes y n q e n genera codigo para la C PU en la que r; ; n se esta ejecutando. Si para sus clientes es importante tener imgenes n a tivas para sus ensamblados, debe ejecutar n q e n en los equipos de sus clientes como parte del proceso de instalacin. Tambi n es importante tener en cuenta que los ensambl ados N E T originales deben estar disponibles en todo momento, aunque el codigo ilativo este disponible en la cache de imagen nativa. Las imgenes nativ as son archivos Ejecutable portables (PE) \Vin32 estndar y carecen de los metadatos existentes en un ens ambl ado NET. Si el codigo carga su e ns ambl ado de imagen nativa y ejecuta cdigo que obliga a N E T Framcwork a ex ami na r met adatos (por ejemplo, usando reflexin par a obtener informacin para el ensamblado), entonces el ensambl ado N E T original debe estar disponible para que el C L R pueda consultar sus metadatos. Los metadatos no pueden ser transportados junto a la imagen nativa.

690

Resumen
En este captulo, se ha exami nado el concepto de ensambl ado N E T desde la perspect iva de las aplicaciones de C# que pueden acceder a la informacin de los ensambl ados. El acceso a la informacin de los ens ambl ados se realiza mediante la clase Assembly. La clase Assembly mues tra la informacin de nombre p ar a el ens ambl ado y permite que los en sambl ados se carguen dinmicamente. Los tipos gestionados por el ens ambl ado pueden ser creados al instante. Puede aplicar los conceptos mos trados en este captulo en la construccin de potentes aplicaciones NET. Algunas de las herramientas que incorpora NE T Framework. como la herramienta ILDASM. usan una combinacin de mtodos de la clase A s s e m b l y y o t ra s cl ases en el e s p a c i o de n o m b re s System. Reflection p ar a pr opo rci onar una vista con todos los detalles de los e n s a m blados ya compilados. Se puede obtener una gran cantidad de informacin de los ensambl ados, usando los mtodos de la clase Assembly y otras clases de re flexin. aunque el cdigo fuente us ado p ar a construir el e ns ambl ado no est di s ponible.

691

32 Reflexin

Una importante caracterstica de N E T Framework es su capaci dad para des cubr ir informacin de tipo en tiempo de ejecucin. En concreto, puede usar el espaci o de nombres r e f l e c t i o n p ar a ver la informacin de tipo que contienen los ensambl ados que. ms tarde, podr enlazar a objetos e incluso puede usar este espacio de nombres par a generar cdigo en tiempo de ejecucin. Esta tecnologa se extiende a la tecnologa de au tomat izaci n C'OM. ya conocida por muchos de los lectores. C omo progr amador, segurament e necesite us ar a menudo un objeto sin c o m prender del todo lo que hace ese objeto. La reflexin permite t omar un objeto y e xami nar sus propiedades, mtodos, eventos, ca mpos y constructores. C omo la reflexin gira en torno a System. Type. puede exami nar un ensambl ado y usar mtodos, como GetMethods ( ) v GetProperties ( ) . para devolver infor macin de mi embro desde el ensamblado. C on esta informacin, puede empezar us ando el mtodo Methodlnfo () para devolver listas de parmet ros e incluso l lamar a mtodos en el en sa mb la do con un mtodo llamado Invoke. En este captulo, aprendera a us ar el espacio de nombres R e f 1 e c t i on para exa mi na r objetos en tiempo de ejecucin. Tambi n aprendera a enlazar t a r d a mente los objetos y a u sar mtodos y propiedades en estos objetos enlazados tardamente.

693

La clase Type
La clase Type ac t a como una vent ana al API de reflexin, lo que permite el acceso a metadatos. La clase abst ract a System. Type representa un tipo del Sistema completo de tipos (CTS). Este sistema completo de tipos es lo que p er mi te exa mi na r objetos en todos los lenguajes de la familia N E T Como cada objeto usa el mi smo entorno, tiempo de ejecucin y sistema de tipos, la informacin de objeto y de tipo se consigue fcilmente. Una de las mayores ventajas de las clases Type es su capacidad par a crear objetos di nmi cament e y usarlos en tiempo de ejecucin.

Cmo recuperar informacin de tipo


La informacin de tipo puede ser recu per ada de los objetos mediante varios mtodos. Las siguientes secciones describen cmo hacer esto de tres maneras diferentes: usando un nombre de tipo, usando un nombre de proceso o especifi cando un nombre de ens ambl ado par a re cuper ar la informacin. Aunque todas estas implementaciones realizan prct icament e la mi sma tarea, cada una es til a su manera. Dependiendo de los requisitos de su aplicacin, slo necesitar us ar una de las formas de las funciones recolcctoras de tipos.

Cmo recuperar tipos mediante el nombre


Simplemente especificando el nombre de un tipo, puede cons ul tar casi todos los aspectos del objeto. Puede det erminar si el objeto es una clase, de qu tipo es su sistema base y muchas otras propiedades. Para comprobarlo, puede crear una sencilla aplicacin par a ver algunas pro piedades de la clase S y s t e m .Str ing. como muest ra el listado 32.1.
Listado 32.1. Cmo consultar inform acin de tipo mediante el nombre using using class System; System.Reflection; NameType static voicl M a m ()

{
public

{
Type t = T y p e .G e t T y p e ("System.String"); Consol . W r i t e L m e ("ame : {0 } " ,t .ame ) ; Co n s o l . W r i t e L i n e ("Underlying System Type : {0 ( " , t .U n d e r l y i n g S y s t e m T y p e ) ; Consol.WriteLine ("Is Class : (0) ",t .IsClass) ;

} }

694

La figura 32.1 indica que System. S t r m q es el tipo de sistema base > que el objeto es. sin lugar a dudas, una clase. Se estara preguntando qu utilidad tiene esta informacin. Imagine que esta creando una aplicacin que necesita generar instrucciones i ns* r t para introdu cir informacin en SQL Server. Escribir una gran cantidad de informacin re quiere una gran cantidad de tiempo. Usando la reflexin y la clase Typo. puede exami nar el tipo subyacente de cada fragmento de informacin que quiera insertar en SQL. Server \ describir estos tipos a un tipo de datos SQL Server v alido Esto simplifica mucho el proceso de generar mediante progr amaci n las instrucciones insert que necesita.
a C:\WINDOWS\System32\cnxLeMe C:\>NaneType.exe Name : String Underlying System Type Is Class : True

: System.String

Figura 32.1. Informacin de tipo de consulta mediante un nombre de objeto

Cmo recuperar tipos mediante instancias


En lugar de usar el nombre de un tipo, puede simplemente usar una instancia de un objeto que quiera examinar. El listado 32.2 representa un ejemplo igual que el anterior.
Listado 32.2. Informacin de tipo de consulta usando una instancia de un objeto us m g us m g c 1ass S y stem ; S ystem.Ref 1e c ;1 1 on ; Tnst ancoType voi d Ma in ()

{
pub 1 ic static

I
S t n n g myV a r = " B n a n Patt eison" ; Ty'pe t = myVa r .GetType ); Console.WriteLine ("ame : |0 ) ",t .Mame ;

695

l:n este ejemplo, en lugar de especificar que quiere ver la informacin de tipo de r' /. t :n. ; - r : n j. se crea una instancia de una \ a n a b l e de cadena sobre la que. a continuacin, llama al mtodo G e t T y p e ( ) . 1.a informacin obtenida aqu es la misma que la que se obtuvo en el ejemplo anterior, la diferencia esta en que no tiene que saber el tipo antes de tiempo Simplemente llame al mtodo G~+ -.Typ-v: , \ asgnelo a un objeto T y p e . al que puede consul tar el nombre, el tipo de sistema subyacente y similares.

Cmo recuperar tipos en un ensamblado


A menudo, querr exa mi na r los tipos que contiene un ensamblado. Este en s ambl ado puede ser un ejecutable o incluso una biblioteca de vnculos dinmicos contenida en el sistema. El listado 32.3 contiene el codigo necesario para e xa mi nar la informacin de tipo del propio ejecutable.
Listado 32.3. Cmo examinar un proceso en ejecucin para obtener informacin de tipo
us inq
11 s i n q
jys t em;
!

j y s t e m . P e f l e c t i on ;

nsinq
1a s s

r,

y s tem. I v i a qn o s t io s ;

AssernType

puh 1 i s t a V : r. v o i '1 Ma i n
t

s trin q []

a r q s 'i

I
1 r c ^ s s p - Fror:ess.GetCurrentProces,3 ! i ; str: nq a s s emb 1y Iame - p .Proce.ssManie + " .exe" ; 1: ' ii si , 1 . V /r it- .= I, i e a:ni n in q : {0}", a s s emb 1 y Na me ') ; A.s.sf-ib !y a As s emb 1y . I ,na d F rom (a s s embl yName ; Type ! j t-ypes - a .Get.Types i) ; o r ^ - h 'Typ- r m fype.s )

i
: :, r . s 1 .W r i t ^ I ,i r.e <" \p.Typr
11

( } " ,f .Ful lMame : ;


:

. n x. s o i ri . V :Ti i t p

ine

1i i

i'! 1 a s s

1i ; " , t . R a . s f T y p . c . F i ; i i L i n - i ;

i I i El codigo anterior presenta algunos elementos nuevos. El tipo p r o o e s s se usa para ex ami nar procesos que se estn ejecutando. En este contexto, se emplea

para conseguir el nombre de su progr ama y luego agrega . al final del n o m bre para que pueda ex ami nar el ensamblado. Puede igualmente escribir en el eodigo el nombre de su aplicacin, pero este mtodo garantiza que funcionara, sin que importe como llame a su aplicacin . La figura 32.2 muestra el resultado de esta aplicacin No es un resultado mu\ espectacular, ya que su p rogr ama solo contiene una clase
ca

C:\WINDOWS\System32\cmAfiftt ,

,n j

X .

C:\>AssemblyTypes.exe Examining : AssemblyTypes.exe Type : AssemType Base class : System.Object

Figura 32.2. inform acin de proceso obtenida mediante el API Reflection

Como puede ver en el figura 32 2. hemos exami nado el proceso en curso y la misma aplicacin que esta ejecutando v hemos mostrado todas sus clases internas y sus tipos. Para experimentar, intente agregar algunas clases nulas a este provec to y luego vuelva a ejecutar la aplicacin. Debera ver una lista de todas las clases que all se contienen y sus tipos.

Cmo interrogar a objetos


El listado 32.4 contiene el codio fuente de la aplicacin R e l e e t o n T c s t . que examina una clase y proporciona detalles sobre ella. Esta aplicacin en un congl omer ado de todo lo que ha aprendido sobre la reflexin hasta el momento.
Listado 32.4. Los objetos de clase proporcionan fcilmente la informacin de miembro namespace

{
using .System ; using Sy s t e m .Re f1ec 1 1 on public class Classi

697

p u b lic

at a L ie t -

m t

M ain

) )

{
Type Lypeof ( aU setu lC la ss

CfJiisr-le .WnteLiiic ' ' . ' i i ! ! I .V 7r it e L m e C o 11 s t ru e t o r Inf o f ]

( "Type of class: " t t i ; "Namespace: " + t ..Namespace c 1 - t . G e t C o n s t r u c t o rs f i ;


)

C o n s o l e . W r i t e L i n e i " -----------------------------------*: c n s o i e . W r i t e L i n e ! toreach> "Constructors 1 in ci

---------------------------

are: " )

Const ructor Info

!
t Pr :o p e rt y I n fo ; ]
p i - t .GetPiopcrties i ) ; C or. s r, 1 e . W r 1 1. e L i n e ! " ---------------------------------------- ---------------"P ro p e rties r i in ) pi are :" )

- - - -

- --------

C o n s o 1 e . W r 1 1: e L i n e ( foreaoh'

P r o p e rt.ylnf o

(
C o n s o l e . Wr i t e l m e (

1
M e t h o d l n t o []

mi

- t . GetM ethods( )
- - - -

C o n s o l p . W r i t e L i n e i " ------------------------------------------------------- (' : o n s s i e . W r i t e l m e ( foreach i Me t. h o cl I n f o " M e t h o cl s i i n mi ar e : " i " + l . N am e ) )

C o n s o 1 e . Wr i t e L i n e !
P a ra m e t e r l n f o [ J pif

"N ame:
=

i .G e t P a r a m e t e r s

( !

f o r t . d eh 1
[jaram eter

! Parameterlnto p

in pif

) a

C o n s o 1e . Wr r t e L m e i"T y p e : n a m e : " + p . N am e )

" + p . Paramet erType

return

}
pub 1 1 c c la ss aU s e fu lC la s s

1 publrc rnt publnteger private m t privValue; public a U s e f u l C l a s s ( )

public

aUsefulClass

( mt

IntegerValueIn ;

{
publnteger = IntegerValue In

698

publxc

int AddlO

( int

IntegerValueln

) )

{
Consol.WriteLine ( IntegerValueln return IntegerValueln + 10 ;

}
public int TestProperty

{
get

{
return pri vV a1u e

}
set

{
privValue = valu ;

} }

Aqu hemos creado dos clases. Cas si v aUseful Class. Cas si c o n tiene el principal punto de entrada a su aplicacin (void M a m ) . mientras que la otra clase solo existe par a ser examinada. Para examinar la clase aUsefulClass. realice los siguientes pasos en el procedimiento principal: en pri mer lugar, declare un objeto Type y. mediante la pal abra clave typeof. dirjalo hacia aUsefulClass. A continuacin, m u es tra la clase Type y el espacio de nombre. Despus, use GetConstructors par a recuperar una lista de los c ons truc tores de la clase. A continuacin, aplique un bucle a lo largo de los constructores y m u s t r e l o s en la p a n t a l l a . Al i g u a l q u e co n los c o n s t r u c t o r e s , use GetProperties p ar a recuperar una lista de todas las propiedades de modo que puede iterar a lo largo de la lista y de las propiedades fuera de la ventana de consola. GetMethods r ecupera todos los mtodos, ademas de los mtodos que c o m ponen los descriptores de acceso get y set de sus propiedades. A continuacin, se itera a lo largo de esta informacin y esta se muestra en pantalla. Tambin invoca a Get Parame ters par a que recupere una lista de los parmet ros para cada mtodo y tambin mues tra esa informacin. Como puede ver en la figura 32.3. su aplicacin muestra una gran cantidad de informacin sobre el objeto de la clase. Obv iamente. esta aplicacin no es especialmente til, ya que ya tiene el codigo fuente de la clase en cuestin y no necesita la reflexin par a darle detalles. Lo

699

importante aqu es que la reflexin funciona de la misma manera, aunque estemos t rat ando con un ensambl ado par a el que no tengamos el codigo fuente.
CC

C:\WIND0WS\System32\cmAexe

C:\>ReflectionTest.exe Type of class: R e f lectionTest.Classl+aUsefulClass Namespace: R e f lectionTest Constructors are: Uoid . c t o r O Uoid .ctor<Int32> Pro pe rt ie s are : Int32 TestProperty Methods are: Name: GetHashCode Name: Equals Type: System.Object parameter name: obj Name: ToString Name: flddlQ Type: System.Int32 parameter name: IntegerUalueIn Name: get_TestProperty Name : s e t _T e s t Pro pe rt y Type: System.Int32 parameter name: value Name: GetType C:\>___________________________________________________

Figura 32.3. Las clases Pef.iect.ion y Type revelan una gran cantidad de inform acin relativa al objeto de la clase

Cmo generar cdigo dinmico mediante la reflexin


Puede crear codigo en tiempo de ejecucin usand o el espacio de nombres

System. P e f "o : t i on .F.mi t. Al us ar las clases de este espacio de nombres,


se puede definir un ens ambl ado en la memoria, cr ear un modulo, definir nuev os tipos par a un modulo (incluyendo sus mi embros) y emitir codigos de operacin MSIL para lgica de la aplicacin.

NOTA: "Opcodes" es la abreviatura de cdigos de operacin. ste es el cdigo real que genera el compilador de NET.
El listado 32.5 contiene el codigo que puede usarse p ar a generar codigo en tiempo de ejecucin.
Listado 32.5. Cmo generar cdigo dinmicamente en tiempo de ejecucin using us m g using System; System. Ref lection ; System.Reflection.Emit; PynamicCode

namespace

700

cas s CodeGeerator

{
Type t; App D orna in curren t Doma ir .; AssemblyName assemName; As semb 1 yBu i 1de r ass emBui lder; M o d u 1eBu 1 1de r m o d u 1eBu i 1de r ; TypeBu i 1de r typeBuilder; MethodBu i lder methodBui lder; TLGenerator msi1G;

pub 1 ic s t a t ic void Main ( '. )

{
CodeGenerator codeGen T yp e t = codeGen.T; if (t != null) object o = A c t i v a t o r .CreateInstanoe <t / ; Methodlnfo helloWorld - t .GetMethod ("He 1 loWoila" if (helloWorld != null) - new CocieGenerat or i ;

{
// Ejecuta el metodo HelloWorld hello Wo r1d .Inv oke (o , n u 11);

1
Console . W i i t e L m e ("Could Methodlnfo"); not ret, ri eve

} } else {
Console . W r i t e L m e ("Could not access the Type");

public

CodeGenerator( )

{
// Obtiene el dominio de aplicacin actual. // Esto es necesario cuando se construye codigo. c u r r e n t D o m a m = A p p D o m a m .C u r r e n t D o m a m ; // Crea un nuevo ensamblado para nuestros assemName = new AssemblyName ( ); as s e m N a m e .ame = "BibleAssembly" ; assemBuilder = cur r ent Doma m .De f ine DynamicAs s e m b 1 y (a s s emName , A s s e m b l y B u i l d e r A c c e s s .R u n ) ; mtodos

701

// Crea un nuevo modulo en este ensamblado moduleBuilder = as s e m B u i l d e r .De f m e D y n a m i c M o d u l e ("B i b 1e M o d u l e ") // Crea un nuevo tipo en el mdulo typeBuilder = m o d u 1e B u i l d e r .Def m e T y p e (" B ib le Cl as s" ,TypeAt tributes.Public) ; // Ahora podemos agregar el // mtodo HelloWorld a la clase methodBuilder = t ype B u l d e r .D e f m e M e t h o d ("He 11o W o r l d " , Me thodAt tributes.Public,nuil,nuil) ;

recien creada.

// Ahora podemos generar algo de codigo de lenguaje // intermedio de Microsoft gue simplemente escriba // una linea de texto en la consola. msilG = m et ho d B u i l d e r .GetILGenerator ( ); ms i 1 G .EmitWriteLine ("Helio from C# B i b le "); m s i l G . E m i t ( O p C o d e s .R e t ) ; // Crea un tipo, t = t y p e Bu il de r.CreateType ( );

}
public Type T

{
get

{
return this.t;

} }
1

} Como se esperaba, esta aplicacin slo escribe un mensaje en la consola, como muestra la figura 32.4. La funcin dereflexin para generar objetos y cdigo en tiempo de ejecucin es realmente impresionante y constituye la col umna vertebral par a la generacin de aplicaciones de lgica difusa que se adaptan y aprenden como resulte apropiado.

NOTA: La lgica difusa es un tipo de lgebra que usa los valores verdade ro y falso para tomar decisiones basndose en datos imprecisos. La lgica difusa suele relacionarse con los sistemas de inteligencia artificial.

Resumen
Las clases R e f l e c t i o n y T y p e van unidas cuando necesita descubri r in formacin de tipo en tiempo de ejecucin. Estas clases permiten e xa mi na r obje-

702

tos. c argar objetos di nmi cament e en tiempo de ejecucin e incluso generar codiuo en caso de necesidad.

Cc C:\WINDOWS\System32\cmdLexe

iteC

-!! x l

Figura 32.4. Los resultados del cdigo generado dinmicam ente

703

33
Subprocesamiento en C#

La potencia del multiprocesamiento de N E T Framework permite escribir apli caciones muy estables con varios s ubprocesos en cualquier lenguaje NET. En este captulo apr ender los entresijos de los multiprocesos. El captulo comienza con una visin general de los diferentes tipos de subprocesos y de su f un ci ona miento en N E T Framework. para luego continuar ensendole lo que puede hacer en sus aplicaciones graci as al multiprocesamiento. A medida que avance en el captulo, sopese cuidadosamente los peligros de agregar varios s ubprocesos a sus aplicaciones antes de implementarlos. porque el multiprocesamiento no es un con cepto sencillo.

Subprocesam iento
Antes empezar a escribir aplicaciones con mltiples subprocesos. debe c o m prender lo que sucede cuando se crean los subprocesos y cmo gestiona el sistema operativo los subprocesos. Cuando se ejecuta una aplicacin, se crea un s ubproceso primario y el mbito de la aplicacin se basa en ese subproceso. Una aplicacin puede crear subprocesos adicionales para realizar tareas adicionales Un ejemplo de creacin de subprocesos primarios sera iniciar Microsoft Word. La ejecucin de la aplicacin comienza

705

en el subproceso principal. En la aplicacin Word, la impresin en segundo plano de un documento sera un ejemplo de un subproceso adicional creado para c ont ro lar otra tarea. Mientras esta interactuando con el subproceso principal (el d ocu mento Wor d), el sistema lleva a cabo su peticin de impresin. C u an d o el subproceso de la aplicacin principal termina, todos los otros subprocesos cr ea dos a partir de ese proceso tambin finalizan. Considere estas dos definiciones del Kit de desarrollo de software de Microsoft Foundation Class ( MF C SD K ): Proceso: Una instancia que se ejecuta de una aplicacin Subproceso: Una ruta de ejecucin dentro de un proceso C ++ v MF C llevan muchos aos a po ya ndo el desarrollo de aplicaciones multiproceso. Como el corazn del sistema operativo Wi ndows est escrito con estas herramientas, es importante que sean compatibles con la capacidad de crear s ubprocesos en los que se puedan a si gnar y crear tareas. En los primeros tiempos de Wi nd ows 3.1. la multitarea no exista: este concepto se hizo realidad con Wi ndows N T 3.5 y NT 4.0 y luego en Wi ndows 95. 98. 98SE. ME. 2000 y XP. Para apr ov ech ar las caractersticas del sistema operativo, las aplicaciones con varios s ubprocesos se hicieron ms importantes. Hoy en da. la capaci dad de realizar ms de una tarea a la vez es un rasgo necesario para una aplicacin. Visual Basic 6.0 y v ersiones anteriores compi laban aplicaciones de un solo p r o ceso. lo que significaba que. sin i mportar lo que pasara, la aplicacin de VB solo poda hacer una cosa a la v ez. En realidad, en un sistema con un solo procesador, no importa qu herramienta use para escribir su aplicacin ya que todo sigue sucediendo en un proceso lineal. Si es un pro gr amado r de C++. puede crear nuevos subprocesos y realizar tareas mientras tienen lugar otros sucesos, pero en realidad slo se compart e el mismo tiempo con el resto de procesos que se estn ejecutando en el sistema. Si solo hav un procesador, solo puede suceder una cosa cada vez. Este concepto se llama mu M area p r e fe r e n te .

Multitarea preferente
La multitarea preferente divide el tiempo del procesador entre las tareas o subprocesos en ejecucin. Cuando una tarea se est ejecutando, usa un esp a c io de tiempo. C uando el espacio de tiempo de la tarea que se est ejecutando caduca, en a pr o xi ma d am en t e 2 0 milisegundos. dependiendo del sistema operativ o que este usando, se invalida y otra tarea recibe el espacio de tiempo. El sistema g uar da el contexto actual de la tarea invalidada y cuando se asigna a la tarea otro espacio de tiempo, se restaura su contexto y el proceso continua. Este bucle de tarea continua repetidamente hasta que la tarea es ab or ta da o finaliza. La multitarea preferente da al usuario la impresin de que se realiza ms de una tarea a la v ez. <,Por que finalizan algunas tareas antes que otras, aunque se inicie antes la ultima en t e r mi n ar 7

706

Prioridades de subproceso y bloqueo


Cuando se crean subprocesos. el p ro gr a ma do r o el sistema operativo les as i g na una prioridad. Si una aplicacin parece estar bloqueando el sistema, tiene la prioridad ms alta y est bloqueando el acceso a los tiempos de los demas subprocesos. Las prioridades determinan lo que sucede y en que orden. Su apl ica cin puede estar completa en un 90 por ciento con un proceso determinado c ua n do. de repente, se inicia un nuevo subproceso y se coloca por delante del subproceso que esta ejecutando su aplicacin, haciendo que a ese s ubproceso se le asigne una prioridad menor. Esto suele suceder en Windows. Algunas tareas son ms priori tarias que otras. To memo s como ejemplo el nuevo Reproductor de Wi ndows M e dia. Al iniciar este proceso hace, bsicamente, todo lo que se esta ejecutando deja de responder hasta que esta completamente cargado, incluyendo la pagina de la Guia multimedia. Uno de los mavores peligros a los que se enfrentan los p rogr amadores al escri bir aplicaciones que usan varios s ubprocesos son las situaciones de bloqueo, en las que dos o ms subprocesos intentan usar el mismo recurso. Un bloqueo de subproceso tiene lugar cuando un subproceso accede a un recurso compart ido y otro s ubproceso con la mi sma prioridad intenta acceder a dicho recurso. Si los dos s ubprocesos tienen la misma prioridad y no se ha codificado el bloqueo c o rrectamente. el sistema s ucumbe lentamente porque no puede liberar ninguno de los s ubprocesos de alta prioridad que se estn ejecutando. Esto puede suceder fcilmente en las aplicaciones con varios subprocesos. C uando el pr og ramado r asigna prioridades a los subprocesos y estn compart iendo datos globales, debe bloquear el contexto correctamente par a que el sistema operativo gestione cor rec tamente el espacio de tiempo.

Multiprocesamiento simtrico
En un sistema m u ltip ro ccsa d o r . puede tener lugar realmente mas de una tarea a la v ez. Como cada procesador puede asignar espacios de tiempo a las tareas que quieren ejecutarse, puede realizar mas de una tarea a la vez. C uan do necesita ejecutar un subproceso largo que requiera mucho trabajo del procesador, como ordenar 10 millones de registros por nombre, direccin, codigo postal, apellidos y pas, si se usan varios procesadores el trabajo concluir antes que si se usa un solo procesador. Si puede delegar ese trabajo en otro procesador, la aplicacin actualmente en curso no se v era afectada en absoluto. Tener mas de un procesador permite este tipo de m ultiprocesam iento sim trico (SMP). La figura 33.1 mues tra las opciones de procesador par a SQL Server 2000. Si est ejecutando S QL Server en un equipo multiprocesador. puede definir el nmero de procesadores que debe usar p ar a las tareas largas y que exigen el tipo mencionado. SQL lleva esto un poco mas all, realizando consultas a lo largo de los diferentes procesadores, uniendo los datos cuando se completa el ultimo

707

s ubproceso y mostrando los datos al usuario. Esto se conoce com o sincronizacin de s u h p r o c e so s. El subproceso principal, que crea varios subprocesos. debe espe rar a que todos los otros subprocesos este'n completos antes de cont inuar con el procesado.
Propiedades de SQL Server (C
Conexiones General | Memoria | j Contiguacin del servidor Duplicacin Procesador | | Active Directory Segundad

Configuracin de base de datos

Control del procesador . Especifique qu procesadores utilizar SOL Server en un entorno de multipfoceso simtrico (SMP).

J
Nmero mximo de subprocesos de trabaio Aumentar la prioridad de SQL Server en Windows P Paralelismo Especifique el nmero de procesadores que desea utilizar para *J 3 elecu*a consultas en paralelo: Utilizar todos los procesadores disponibles Utilizar intraprocesos de Windows NT IZ3

H
T~] -iJ

Umbral mnimo de plan de consultas para T E j corisiderar la ejecucin de consultas en paralelo I (costo estimado): Valores configurados f Aceptar Valores actuales I Cancelar

Ayuda

Figura 33.1. Cuadro de dilogo de opciones de SQL Server 2000 Processor

Observe que. cuando se usa un sistema SMP. un solo subproceso sigue ejecu t ndose en un solo procesador. La aplicacin V B 6 se ejecuta exact ament e igual que si le aade otro pr oces ador adicional. Su aplicacin de Access 2 .0 de 16 bits t ampoco se ejecuta mejor porque 16 bits siguen siendo igual a un solo proceso. Deber crear nuevos procesos en los dems procesadores par a aprovecharlos. Esto significa que no diseamos una GUI multiprocesador. Desarrolle una GUI que cree otros procesos y pueda reaccionar c uando esos procesos se completen o sean interrumpidos, mientras sigue permitiendo al usuario usar la GUI par a otras tareas.

Cmo usar los recursos: cuantos ms, mejor


Los subprocesos consumen recursos. Cu an do se estn usando demasi ados re cursos. el equipo se ralentiza increblemente. Si intenta abrir 80 instancias de Visual Studio N E T mientras instala Exchange 2000 en un equipo con 9 6 M B de R AM. percibir que la pant al la no dibuja correctamente, el ratn no se mueve muv deprisa y la ms ica que est aba es cuchando en el reproduct or de Wi ndows Medi a ya no suena. Estos probl emas de rendimiento se producen porque hay demasi ados s ubproc es os ej ecutndose al mi smo tiempo en un sistema operativo con un har dware que no puede gestionar esta cantidad de trabajo. Si intenta hacer

708

lo mi smo en un servidor nuevo, el Unisys de 32 procesadores con 1 t erabyte de RAM, no percibir ninguna prdida de rendimiento. C uant a ms memori a tenga, ms espacio fsico tendrn las aplicaciones par a crear ms subprocesos. Cuando escri ba aplicaciones que creen subprocesos. asegrese de que tiene esto en c ue n ta. Cuant os ms subprocesos cree, ms recursos consumir su aplicacin. Esto podra llegar a c a u s ar un rendimiento menor que el de una aplicacin de un solo proceso; todo depende del SO. "Cuantos ms mejor" no se refiere a los subprocesos. Por tanto, tenga cuidado al crear subprocesos en la nueva versin de Tetris con mltiples subprocesos que est escribiendo en C#

Dominios de aplicacin
Anteriormente se indic que el MF C S DK define un proceso c omo una i nstan cia de una aplicacin que se ejecuta. Cad a aplicacin que se esta ejecutando crea un nuevo subproceso principal, que dura lo que la instancia de la aplicacin. Como cada aplicacin es un proceso, cada instancia de una aplicacin debe tener aislamiento de procesos. Dos instancias de Microsoft Wor d actan i ndependien temente entre s. Cu an do hace clic en Ort ograf a y gramt ica, la InstanciaA de Wo r d no comp ru e ba los errores ortogrficos del document o que se est ej ecut an do en la InstanciaB de Word. Incluso si la InstanciaA de Word intenta pa sa r un puntero de memori a a la InstanciaB de Word, la InstanciaB no s abr a que hacer con l, o siquiera dnde buscarlo, ya que los punteros de memori a slo se refieren a los procesos en los que se ejecutan. En . NET Framework. los dominios de aplicacin se usan par a proporci onar seguridad y aislamiento de aplicacin par a el cdigo gestionado. Algunos d omi nios de aplicacin pueden ejecutarse en un solo proceso o s ubproceso. con la mi sma proteccin que si las aplicaciones se estuviesen ejecutando en varios p r o cesos. El cons umo de recursos se reduce con este concepto, ya que las llamadas no necesitan estar circunscritas a los lmites de los procesos si las aplicaciones necesitan c ompar tir datos. Por el contrario, un solo dominio de aplicacin puede ejecutarse en varios subprocesos. Esto es posible graci as al modo en el que el C L R ejecuta el cdigo Una vez que el cdigo est p r epar ado par a ser ejecutado, el compi lador JIT ya le ha hecho p a s a r el proceso de verificacin. Este proceso de verificacin gar ant iza que el cdigo no va a realizar acciones invlidas, como accesos a memori a imprevistos, que provoquen un fallo de pgina. Este concepto de cdigo c/t' tipo seguro g ar ant iza que un cdigo no va a violar ninguna regla despus de que el verificador lo haya a pr obad o al pas ar de cdigo MS IL a PE. En las tpicas aplicaciones Wi n32. no existan mecanismos de p r o teccin que evitaran que un fragmento de codigo supl ant ase a otro, de modo que cada aplicacin necesitaba aislamiento de proceso. En NET. como la seguridad de tipo est garantizada, resulta seguro ejecutar varias aplicaciones de varios proveedores en el mismo dominio de aplicacin.

709

Ventajas de las aplicaciones de varios subprocesos


Algunas aplicaciones pueden sac ar partido del multiproccsamiento. Aplicaciones con procesos largos. Aplicaciones de sondeo y escucha. Aplicaciones con boton C a n c e l a r en la GUI. Las siguientes secciones muest ran cada una de estas razones.

Aplicaciones con procesos largos


Las aplicaciones que requieren procesos largos en los que el usuario no tiene por que int eract uar se pueden beneficiar del mul tiproccsamiento porque los p r o cesos de ejecucin duradera pueden ser creados en un subproceso t rab aj ado r que procese la informacin en segundo plano hasta que se notifica al proceso que llam al s ubproceso que este ya ha terminado. Entre tanto, el usuario no esta obligado a per manecer inactivo, mirando el cursor de reloj de arena para pas ar a la siguiente tarea.

Aplicaciones de sondeo y escucha


La s a p l i c a c i o n e s de s o n d e o y de e s c u c h a p u e d e n b e n e f i c i a r s e del multiproccsamiento. Imagine que tiene una aplicacin que ha creado subprocesos que estn es cuchando o sondeando. C uan do sucede algo, un subproceso puede consumi r ese evento concreto y los otros subprocesos pueden seguir sondeando o e sc uchando por si sucede un evento. Un ejemplo de esto es un servicio que e sc u cha las peticiones de un puerto de red o una aplicacin de sondeo que comprueba el estado de Microsoft Message Queue ( M S M Q ) por si hay mensajes. Un ejemplo de una aplicacin de sondeo comercial es Microsoft Biztalk Serv er. Biztalk esta const ant emente sondeando en b us ca de cosas como archivos en un directorio o archivos en un servidor SMTP. No puede lograr todo esto con un solo subproceso. de modo que v a n o s s ubprocesos sondean recursos diferentes. Microsoft Message Queue tiene una extensin par a Wi ndows 2000 y una funcin de Wi ndows XP llamada Message Queue Tn gg er s . Con M S M Q Triggers. puede establecer p ro piedades que hacen que un dese ncade nado r desencadene un evento. Este es un servicio de mu lti proccs ami ent o que puede manej ar miles de solicitudes s imu lt a neas.

Botn Cancelar
Cual qui er aplicacin que tenga un boton C a n c e l a r en un formul ari o debe se guir este proceso:

710

1. Abri r y mo st rar el formulario modalmente. 2. 3. 4. Iniciar el proceso que tiene lugar en el nuev o proceso. Esper ar a que el subproceso termine. Cerr ar el formulario.

Al seguir estos pasos, el evento c l i c k del boton C a n c e l a r tiene lugar si el usuario hace clic en el botn mientras otro subproceso se est ejecutando. Si el usuario hace clic en el botn C a n c e l , en realidad hace clic mientras el proceso est e jecutndose en un su bproc es o que no es el que controla el evento click. y el cdigo debe entonces detener el proceso en el otro sub pro ces o que se est ejecutando. Este es un rasgo de la GUI que conv ierte una buena aplicacin en una aplicacin genial.

Cmo crear aplicaciones multiproceso


Es hora de emp ez ar a crear aplicaciones multiproceso. El multiproceso se controla a trav s del espacio de nombres System .Threading. Los miembros que usara ms a menudo de la clase Thread aparecen en la tabla 33.1.
Tabla 33.1. Miembros com unes de la clase T h r e a d

M ie m b r o

D e sc r ip c i n

CurrentContext CurrentThread ResetAbort Sleep ApartmentState IsAlive IsBackground

Obtiene el contexto actual donde se est ejecutan do el subproceso Obtiene el subproceso actualmente en ejecucin Restablece una peticin de anulacin Bloquea el subproceso actual durante el tiempo especificado Obtiene o establece el estado de apartamento de un subproceso Obtiene un valor que indica si el subproceso ha comenzado y no ha finalizado Obtiene o establece un valor que indica si un subproceso es o no un subproceso en segundo pla no Obtiene o establece el nombre del subproceso Obtiene o establece la prioridad del subproceso Obtiene el estado del subproceso

Name Priority Threadstate

711

Miembro

Descripcin

Abort Interrupt Join Resume Start Suspend

Inicia T h r e a d A b o r t E z c e p t ion, que puede finali zar el subproceso Interrumpe un subproceso que se encuentra en es tado de subproceso W a i t S l e e p J o i n Espera un subproceso Reanuda un subproceso que ha sido suspendido Inicia la ejecucin del subproceso Suspende el subproceso

Cmo crear nuevos subprocesos


La creacin de una variable de tipo S y s t e m .Threadi ng .Thread p e r mi te crear un nuevo s ubproceso con el que empez ar a trabajar. C omo el concepto de subproceso implica la ejecucin independiente de otra tarea, el constructor Thread necesita la direccin de un procedimiento que har a el t rabajo del s ubproc es o que esta creando. L1 delegado ThreadStart es el nico p ar met ro que necesita el constructor para empezar a usar el subproceso. Para pr oba r este codigo, cree un nuevo prov ecto con la plantilla Aplicacin de consola. El cdigo del listado 33.1 crea dos nuevos s ubprocesos y llama al metodo Start de la clase Thread para hacer que se ejecute el subproceso.
Listado 33.1. Cmo crear nuevos subprocesos using using public System; System.Threading ; c 1 a s s T h re a d s void T h r e a d e r l ( )

{
public

public f

void

Threader2()

} }
public class Threadiest

712

public t Threads

static

int M a i n ( S t r i n g [J args)

testThreadmg

= new Threads !] ;

Thread ti = new Th r e a d (n ew Th r e a d S t a r t (testThreadina.Threader 1) t.1 .S tart ( );

Thread t / 2 = new Thread (new ThxeadStart (test.Threadmq. Thre a de r 2 , )) ; t: : .S t a rt () ; C o n s o l e . R e a d L m e () ; return 0;

(
1

C uando crea una variable de tipo thread. el procedi miento que controla el s ubproe es o debe existir par a el delegado ThreadStart. En caso contrario, se produce un error y la aplicacin no compila. La propiedad ame establece o recupera el nombre de un subproeeso. Esto le permite usar un nombre con sentido en lugar de una direccin de cdigo hash para hacer referencia a los s ubprocesos que se estn ejecutando. Esto es til cuando se usan las utilidades de depuracin de Visual Studio N E T En la b ar ra de tareas de depu rado hay una lista desplegable con los nombres de los s ubproc es os en ejecu cin. Aunque no se puede "salir" del subproeeso y saltar a otro subproeeso con el depurador, es til par a saber en que s ubproeeso ha ocurrido un error. Una vez declaradas, nombrada s e iniciadas las variables de los subprocesos. necesita hacer algo en los s ubproces os creados. Los nombres de procedimientos que se han pasado al constructor de subprocesos eran Threader 1 y Threadcr2 . Ahora puede agr egar codigo a estos mtodos y o bs er var como actan. El codigo deberia tener un aspecto como el del listado 33.2
Listado 33.2. Cmo recuperar informacin de los subprocesos en ejecucin using us rng public S ys t .em; Syst em. Thr e a d m g ; class Threads

public void T h r e a d e r ] ( ) 1 Consol . W r i t e L m e (" * * * Threader 1 Information A ' A " / Consol . W r i t e L m e ("ame: " + T h r e a d .CurrentThiead.Mame); Consol . W n t e L m e (T h r e a d .C u r r e n t T h r e a d ); Consol . W n t e L m e ("State: " + Th r e ad .Cu r ren t Th r e ad .Th r ea dS t a t e ' );

713

Console.WriteLine ("Priority: " + T h r e a d .C u rr en tT hr ea d.P riority); C o n s o l e . Wr it eL in e(" * * * End Threaderl Information ++*");

}
public void Threader2()

{
Console.WriteLine (" * * * Threader2 Information * * * " ) ; Console.WriteLine ("Name: " + T h r e a d .C u rr en tT hr ea d.N a m e ); Console.WriteLine ( Thread.CurrentThread); Console.WriteLine ("State: " + T h r e a d .C u rr en tT hr ea d .Thread St at e) ; Console.WriteLine ("Priority: " + Thread.CurrentThread.Priority); Console.WriteLine (" * * * End Threader2 Information * * * " )

} }
public class Threadiest

{
public static int M a i n (S t r m g [ ] args)

{
Threads testThreadmg = new Threads ( );

Thread t 1 = new Thread (new ThreadStart (testThreadmg.Threaderl) ) ; t 1 .Name = "Threaderl"; tl .Start () ; Thread t2 = new Thread (new ThreadStart (testThreadmg.Threader2) ) ; t . 2 .Name = "Threader2 " ; t2 .Start () ; Console. R e a d L m e ( ); return 0;

} } Cua nd o ejecuta la aplicacin, el resultado en su consola debera parecerse al most rado en la figura 33.2. El resultado que muest ra la figura 33.2 no es muy bonito. Si realiza otra llamada, est ar t rabaj ando con subprocesos. Sin establecer una propiedad o dos. el procedimiento Threader 1 nunca terminar antes de que empiece Threader2 . C u an do se ejecute el siguiente codigo:
1 1 .S t a r t () ;

714

Co m en z a r la ejecucin del cdigo de Threader 1 . Como es un subproceso. tiene apenas 2 0 mi lisegundos de espacio de tiempo, en ese perodo de t iempo a lcanzar la segunda lnea de cdigo de la funcin, devolver el control al sistema operativo y ejecutar la siguiente lnea de cdigo:
1 2 .s t a r t () ;

El procedimiento Threader 2 se ejecuta entonces durante su espacio de tiempo y es sustituido por el subproceso t i . Este ir y venir de procesos continua hasta que los dos procedimientos p uedan finalizar.

2J Figura 33.2. Resultado de una aplicacin de subprocesam iento

Prioridad de los subprocesos


Para que el procedimiento Threader ] finalice antes de que el procedimiento I di r eader 2 empiece, debe darle a la propiedad Pr ior ity el valor de la e nu meracin Thread Pr io r i t y correcta, con el objeto de as egurars e de que el subproceso ti tenga prioridad sobre cualquier otro subproceso. Antes de la lla mada al mtodo ti .Start. agregue el siguiente codigo:
t 1 .Priority Th readPr ior ity .H ighe s t .;

Cuando establezca la prioridad al mximo, t i finalizara antes que 1 2 . Si ejecuta la aplicacin de nuevo, el resultado deber ser como el que muestra la figura 33.3. La enumeracin ThreadPr ior ity establece como se planifica un d et er mi na d o s u b p r o c e s o en relacin a los otros su bp rocesos en ejecucin. T h r e a d P r i o r i t y p uede a d o p t a r c u a l q u i e r a de los s igui ent es valores: A h o v c N o r m a l . B e / o w N o r m a l . Highcst. I.owesi o N o r m a / . El algoritmo que det er mina el orden de los s ubprocesos vara en funcin del sistema operativo en el que se ejecutan los subprocesos. Por defecto, cuando se crea un nuevo subproceso. se le concede la prioridad 2. que es Normal en la enumeracin.

715

^ ls jd

Ld
Figura 33.3. Resultado tras establecer la prioridad del subproceso

Estado del subproceso


Al crear un nuevo subproceso. llamamos al mtodo Start ( ) . En ese m o m e n to. el sistema operativo asigna espacio de tiempo par a la direccin del procedi miento pas ad o al const ructor de subprocesos. Aunque el subproceso puede durar mucho tiempo, sigue pasando por diferentes estados mientras los otros subproccsos estn siendo procesados por el sistema operativo. Este estado puede resultarle til en sus aplicaciones. Basndose en el estado del subproceso. puede det erminar si al guna otra cosa necesita ser procesada. Apart e de Start. los es tado s de subproceso que usar ms frecuentemente son Sleep y Abort. Al pasar un nmero de milisegundos al con st ru ctor Sleep. est indicando al subproceso que a ba ndone el resto de su espacio de tiempo. Si llama al mtodo Abort se detiene la ejecucin del subproceso. El listado 33.3 mues tra cdigo que usa Sleep y

Abort.
Listado 33.3. C mo usar el mtodo T h re a d .Sleep using using public System; System.Threading; class Threads

{
public void Threader 1 ( ) intX < 50;intX ++)

{
for (int intX = 0; i f (intX == 5){ T h r e a d . Sleep (500) ; Console.WriteLine("Thread!

Sl ee pi ng ") ;}

716

public

void Threader2() intX = 0; intX < 50;intX ++)

{
for ( m t

{
if ( m t X == 5) { T h r e a d .Sleep (5 00) ; Cons ole. W n t e L m e ("Thread2

Sleeping") ;

public

class

ThreadTest

public

static

int M a i n (S t r i n g [ ]

args)

Threads

testThreadmg

= new Threads () ;

Thread tl = new Thread (new ThreadStart (testT hr ea d mg . Threader 1) tl.Priority = Th readPriority.Highest; 1 1 .S t a r t () ; Thread t2 = new Thread (new ThreadStart (testThreadmg.Threader2) t 2 .S t a r t ( ); C o n s o l e . R e a d L i n e ();

return

0;

Observe que se ha establecido la propiedad Priority del sub pro ces o tl al mximo. Esto significa que. pase lo que pase, se e jecutar antes de que comience t2. Sin embargo, en el procedimiento Threader 1 . tiene el siguiente bloque if:
f or (int intX = 0; mtX < 50; m t X ++)

{
if (intX == 5) { Thread.Sleep(500) ; Consol. WriteLine (Thr ead2

Sleepmg") ;)

} Esto indica al s ubproces o t l que se bloquee durante 500 milisegundos. a b a n donando su actual espacio de tiempo y permitiendo que el s ubproceso t 2 co mi en ce a ejecutarse. C uand o los dos subprocesos se han completado, se invoca al m t od o Abort y los s ubproces os son eliminados. Las llamadas al mtodo Thread .Suspend bloquean un s ubproces o indefi nidamente. hast a que otro s ubproces o lo active de nuevo. Si al guna vez ha o b s e r vado el cont ador del procesador en el Admi ni strador de tareas llegar al 100 por

717

ciento cuando no est gast ando memoria, puede entender lo que sucede cuando un s ubproceso se bloquea. Para que el subproceso vuelva a funcionar, debe llamar al mt odo Resume desde otro subproceso par a que pueda reanudarse. El siguiente cdigo mues tra los mtodos Suspend y Resume:
T h r e a d .C u r r e n t T h r e a d .S u s p e n d ; Consol . W r i t e L m e ("Thread 1 Suspended" ) ; T h r e a d .C u r r e n t T h r e a d .R e s u m e ; Con sol. W n t e L i n e ("Threadl Resumed" ) ;

Aqu debe tener mucha precaucin: Suspender s ubprocesos puede a carr ear r esult ados indeseados. Debe a s e g u r a r s e de que otro s u b p ro c es o reanude el subproceso. La figura 33.4 muestra lo descrito en el par rafo anterior. Observe en la figura que la ventana de la consola est en la lnea de codigo TI Suspended. Este ejemplo refleja una prueba, de modo que no necesita el mtodo Resume. Los resultados del Admi ni strador de tareas indican el estado del sistema. s o s i i m
Ver P ro c es o s

: :
A pagar A yuda | R e n d im ie n t o ] F u n c io n e s d e r e d | U s u a rio s

A r c h iv o

O p c io n e s

A p lic a c io n e s

M o s t r a r pr o c e s o s d e t o d o s los u s u a r io s

T e r m in a r p r o c e s o

P ro c e s o s : 3 5

U so d e C PU: 1 0 0 %

C a r g a d e t r a n s a c c io n e s : 2 9 3 4 4 K

Figura 33.4. Procesador forzado por un subproceso bloqueado

T h r e a d S t a t e es u n a c o m b i n a c i n bit a bit de la e n u m e r a c i n Flag.sAttr bute. En cualquier momento, un subproceso puede estar en mas
de un estado. Por ejemplo, si un subproceso es un subproceso en segundo plano y se est ejecutando en ese momento, el estado puede ser Running y BaekgrouncJ. La tabla 33.2 describe los posibles estados en los que se puede encon trar un subproceso.

718

Tabla 33.2. M i e m b r o s d e T h r e a d S t a t e

Aborted AbortRequested Background Running Suspended Suspend Requested Unstarted WatSleepJoin

El subproceso se ha anulado. Se ha solicitado la anulacin del subproceso. El subproceso est ejecutndose como subproceso en segundo plano. El subproceso est ejecutndose. El subproceso se ha suspendido. Se ha solicitado que el subproceso se suspenda. El subproceso no se ha iniciado. El subproceso se ha bloqueado como resultado de una llamada a wait, sieep o Join.

Cmo unir subprocesos


El mtodo Thread .Joi n espera a que el subproceso termine antes de seguir el proceso. Esto es til si crea varios subprocesos para que cumpl an una d etermi nada tarea, pero antes de que quiera que la aplicacin en segundo plano continedebe as egurars e de que todos los subprocesos que creo han terminado. En el siguiente ejemplo, cambie:
T 2 .J o in () ;

por
Consol.Writeline("Writing");

La segunda vez que ejecute el cdigo, obt endr dos conjuntos de resultados. El resultado Writing no aparece en la consola hasta que los dos subprocesos han terminado.
Listado 33.4. Cmo unir subprocesos using System; using S y s t e m .Threading; public class Threads Threaderl () = 0;
5)

public

void

for ( m t

mtX

intX < 50; m t X

++ )

i f (in t X

719

T h r e a d .Sleep (500) ; Console . W r i t e L m e ("Threadl

Sleeping") ;

} } }
p ubl ic v o ir 1 Threader2 ( ) intX - 0; mt.X < 50; m t X + +)

{
for ( m t

{
if (mt. X = - b )

{
Thread.Sleep (5 0 0 ) ; Consol e .Wri t e L m e !"Threacl2 Sleeping"! ;

p ubl ic class

T h re a c lTest

{
p u b lie static mt Main (String [] a rg s )

I
Threads test.Threadinq = new Threads f );

Thread t . C - new Thread (new Thread S tart (testThreadinq.Threader 2) ) ; bbStart. f ); T h re a c i t 1 = n ew Thread (new ThreaclStart (test Threading. Threader 1 i ) ; t 1 .P r io r it y = ThreaclPr or ity .H ighes t ; t 1 .S tart I i ; /* Invoca a Join para que espere subprocesos terminen 1/ t C .J o in (l ; Consol e .Wri te L m e ("Writi n g " ) ; a que todos los

C on s o 1e .P e a d Line !) ; re t u rn u ; 1

) Como puede ver. el establecimiento de varias propiedades en los s ubprocesos simplifica mucho su control. Tenga en cuenta que tras suspender un subproceso. debe reactiv arlo o su sistema cons umi r recursos innecesariamente.

720

Cmo sincronizar subprocesos


La sincronizacin de datos es un aspecto importantsimo en la utilizacin de subprocesos. Aunque no es una tarea compleja de programacin, los datos corren el n e s go de es tropearse si no los dirige cor rectamente C u an do los s ub pr oc es os estn ejecutndose, compar ten tiempo con otros subprocesos en ejecucin. Esto se aprecia perfectamente en el ejemplo que ejecu tamos en este capitulo. Si tiene un mtodo que se esta ejecutando en varios subprocesos. cada sub pro ees o solo tiene varios milisegundos del tiempo del procesador antes de que el sistema operativo sustituya el s ubproeeso para darle tiempo a otro s ubproees o del mismo mtodo. Si esta en medio de una instruccin mat emtica o de la concatenacin de un nombre, es probable que el subproeeso se detenga algunos milisegundos y otro s ubproe es o en ejecucin s obrescri ba sus datos. Sin embargo, esto no es el fin del mundo porque \ arios mtodos le permiten hacer que esto no suceda. Observe el siguiente codigo:
in t : Y; iu t V ; f o lint Z = u ; Z - 2 1 1; Z + + i { rcturn Y * V ;}

I Es muy probable que durante el bucle, un s ubproees o en ejecucin se detenga para permitir que otro s ubproeeso use este mtodo. Recuerde que esto solo ocurre si permite que haya mltiples subprocesos accediendo a este bloque de codigo. Al escribir aplicaciones con mltiples subprocesos. esto sucede muy a menudo, de modo que necesita saber como solucionar la situacin. El siguiente codigo resuel ve este problema:
lock (t h i s ) { int Y "; in t V ; f o r (in t Z = 0 ; z < 2 0; return Y * V ;}

Z++) {

} La instruccin L o c k es un modo de obligar a los subprocesos a unirse. Su i mplementacion es un poco diferente a la del mtodo J o i n . Con Loo}:. evalua mos una expresin que se ha pasado al bloque Loo}:. Cuando un subproeeso llega al bloque l oo}:, espera hasta que puede conseguir un bl oqueo exclusivo de la expresin que se esta ev al uando antes de intentar seguir con el proceso. Esto asegura que no se estropeen los datos compartidos al usar v a n os subprocesos. La clase M o n i t o r p e r m i t e la s i n c r o n i z a c i n m e d i a n t e los m t o d o s Mon i t o r . E n t e r . M o n i t o r . T r y E n t e r v Mo n i t o r . E:-:i t . Tras usar un bl oqueo en una regin de cdigo, puede usar los mtodos Moni t o r . W d i t . M o n i t o r . Fu 1 s e v M o n i t o r . Pu i s e A i . 1 para determinar si un subproeeso

721

debe co nt inuar con un bloqueo o si al gunos mtodos bloqueados anteriormente estn ya disponibles. Wait levanta el bloqueo si ste se mantiene y espera a que se le notifique. C uando se invoca Wait. se rompe el bloqueo y vuelve par a volver a cerrarlo.

Sondeo y escucha
El sondeo y la escucha son otras dos instancias que representan la utilidad del multiprocesamiento. Las bibliotecas de clases, como System. N e t .Sockets. i n cl i nen un rango completo de clases de multiproceso que pueden ayudarl e a crear agentes de escucha TC P. agentes de escucha UDP y una gran cantidad de t areas de red que requieren multiproceso. Observe la clase T i m e r C a l l B a c k del espaci o de nombres System. Threading. Esta clase es muy parecida a las otras que hemos estado usando hasta ahora, excepto que una de las partes del c onst ructor es un temporizador. lo que le permite realizar sondeos en bu sca de acciones cada ciertos interv alos. Puede conseguir el mismo resultado agr egando un control temp ori za dor al formulario, pero usando la clase TimerCallBack.. el tempori zador y la res puesta al procedimiento son automticos. El listado 33.5 usa una devolucin de llamada t empori zada par a sondear un directorio en busca de archivos. Si se encuentra un archivo, es rpidamente b o r r a do. Slo debe ej ecutar este cdigo en un directorio de prueba, porque elimina archivos. El siguiente cdigo de ejemplo bu sca en el directorio C:\Poll. El const ructor de la clase T i m er C a 1 IBack espera una direccin en la que se va a ejecutar el subproceso; un tipo de datos objeto que representa el estado del t empori zador; un tiempo de vencimiento, que representa el perodo de tiempo hasta el que se van a realizar sondeos; y un perodo, que es una variable en mi lisegundos que indica cundo se produce el interv alo de sondeo.
Listado 33.5. C mo usar el delegado Tim erCallB ack
u sin g u sin g

System; Syste m. 10; System.Threading; cSharpTimerCallBack Ca s s 1 static void Main ()

usmg

n a me space

{
class

(
public

(
C ons ole . W r i t c L m e ( " C h e c k m g direcotry updates Consol . W n t e L m e every 2 seconds.") ;

722

Timer

(" (Hit Enter to terminate the samp le ) "); timer = new Timer(new T i m e r C a l l b a c k (Che ck st at us ), null, C o n s o l e .ReadLine () ; 1 1 me r .D i s p o s e () ;

0,

20 0);

)
static void CheckStatus (Ob]ect state)

{
if (s t r .L e n g t h >0 )

{
for ( m t i = 0 ; i < str .Length; i++)

{
C o n s o l e . W r i t e L m e (str [i ] ) ; FiIe.Delete (str [l] ! ;

} (
C o n s o l e . W r i t e L m e ("Dir e c tor y Emp t y " ) ;

} ) Tras ejecutar este progr ama durante un tiempo y copiar peridicamente unos cuantos archivos en el directorio C : \ P o l 1. el resultado en la consola tendr un aspecto parecido al de la figura 33.5.

Checking direcotry updates every 2 seconds <Hit Enter to terminate the sample> C :\PollSBones.txt C:\Poll\nccl701.xml C:\Poll\q300972_u2k__sp3_x86_en -exe Directory Empty Directory Empty C:\Poll\Bones.txt Directory Empty Directory Empty C :SPoIl\q300972_w2k_sp3_x86_en.exe Directory Empty C:\Poll\nccl701.xml Directory Empty Directory Empty Directory Empty

Figura 33.5. R e s u l t a d o del listado 3 3 . 2

Resumen
En este capitulo ha aprendido a implementar mltiples subprocesos en CU con el espacio de nombres S y s t e m .Thread. La idea basica tras el mul ti proces ami ent o es simple: al crear mas de un subproceso. puede realizar mas de una tarea a la vez. Tiene que probar antes el

723

numero de subprocesos que vaya a crear. Demasiados subprocesos pueden ca us ar problemas de recursos. Si no se crean suficientes subprocesos. puede que la a pl i cacin no trabaje con todo su potencial. C on el ejemplo que ha creado aqu, debera estar pre para do para i mplementar subprocesos en sus propias aplicaciones. Simplemente evite t omar riesgos p o r que. como sabe, las aplicaciones con varios subprocesos pueden generar varios en problemas. Como siempre, planifique su aplicacin con antelacin y decida si el uso del mul ti procesami ent o es una parte importante de este proceso de planificacin.

724

34 Cmo trabajar con COM

Como p r og r am ad or de Wi ndows, probablement e haya creado muchos c o m p o nentes C O M. bien como DLL solitarias o como DLL que se ejecutan en servicios C OM +. Con la llegada de NET. se preguntar si debe reescribir todo con este nuevo lenguaje. Las buenas noticias son que no tiene que reescribir ninguno de sus componentes. Microsoft ha sido suficientemente considerado como p ar a p r o porcionarnos las herramientas necesarias par a usar sus componentes existentes de NET. Adems, estos componentes pueden invocarse de for ma segura desde el Entorno comn de ejecucin. En este captulo apr ender lo sencillo que es mo di ficar el cdigo existente y usarlo desde un cliente admi ni strado por NET. El cliente puede ser cualqui er cosa: una aplicacin Web. otro componente N E T o incluso una aplicacin ba sa d a en servicios. No importa; la funcionalidad pri nci pal funciona en todo tipo de aplicaciones. Aunque siempre tiene la opcin de reescribir su cdigo, no es necesario. P r o bablemente querr usar N E T par a todos sus programas, especialmente el d e sa rrollo GUI. ya que es mucho ms sencillo de usar que las versiones anteriores. Al mismo tiempo, no quer r reescribir toda la lgica empresarial bsica de sus a pl i caciones. Con N ET . todo esto es posible; puede convertir sus aplicaciones a N E T mientras sigue us ando las miles de lneas de codigo existente que ya ha escrito en sus componentes.

727

Fin este capitulo, aprendera a us ar sus componentes C'OM existentes desde un cliente N E T usando las herramientas suministradas unto a N E T \ vera como todo sucede en segundo plano.

Introduccin al Contenedor al que se puede llamar en tiempo de ejecucin


El codigo N E T puede acceder a codigo no admi ni strado mediante un proxv llamado Cont enedor al que se puede llamar en tiempo de ejecucin o RCW. El R CW permite a una aplicacin N E T ver el componente no a dministrado como si fuera un componente administrado. Para ello, organiza llamadas a mtodos, exentos y propiedades mediante un contenedor creado por su aplicacin o manualmente, usando herramientas (como el Import ador de la biblioteca de tipos) que proporciona el Framework. Usando informacin de la biblioteca de tipos C OM . el R CW controla la mteroperabilidad entre cdigo admi ni strado y el no administrado, ('liando ejecuta su aplicacin, no es consciente de si el codigo que se esta ejecutando es el de una DEL no a dm in is trada o COM. El usuario de los componentes no necesita tener ningn conoci miento especial de como se escribi el codigo. en qu lenguaje fue escrito o si es un componente .NET. Todas las caractersticas del entorno administrado, como la recogida de ele mentos no utilizados y el control de excepciones, estn disponibles para el cliente . NET como si estuviera usando codigo administrado. Esto hace que sea e x tr e ma damente sencillo t ran sp or ta r mdulos desde sus aplicaciones anteriores a NE T hasta NE T. sin tener que realizar un gran trabajo o comprender perfectamente los entresijos de cualquier lenguaje . NET que este usando: CU. J U o VB NET. o cualquier otro. Puede rehacer el codigo cliente y colocar la lgica de datos \ la lgica e m p r e sarial en su sitio usando interoperabilidad COM. La figura 34.1 muestra la rela cin entre C O M DLL., el R CW y la aplicacin administrada NET.

Figura 34.1. Cdigo administrado y no administrado conviviendo ju n to s sin problema

728

Cmo crear ensamblados .NET a partir de componentes COM


Para usar sus componentes C OM en una aplicacin NET. debe crear el en s ambl ado de interoperabilidad. o R CW. que organiza las llamadas de mtodo desde el cliente N E T al servidor C'OM. En . NET hay varios modos de realizar esto. Los dos modos mas comunes son los siguientes: La utilidad Importador de la biblioteca de tipos, o Tlbimp exe. propor ci o nada j unt o a . NET Framevvork Hacer referencia directamente al C'OM desde la aplicacin de CU VS .NET El proxy creado para la mteroperabilidad se basa en los metadatos expuestos en la biblioteca de tipos del componente C'OM al que se esta intentando acceder. Las bibliotecas de tipos C'OM pueden hacerse accesibles de una de estas dos formas: Las bibliotecas de tipos pueden encontrarse como archivos individuales Las bibliotecas indiv iduales de tipos suelen tener la extensin T I B , Las bibliotecas individuales de tipos mas antiguas pueden tener la extensin OLB. Si esta creando una DLL. ActiveX de Visual Basic, puede crear una biblioteca indiv idual de tipos para su componente seleccionando la opcin Archivos de servidor remoto en el cuadro de dialogo Propiedades del proyecto. Las bibliotecas de tipo tambin pueden encontrarse incrustadas en un ser vidor C O M como un recurso binario. Los servidores C'OM en curso, em paquetados como DLL y los servidores C'OM detenidos, empaquet ados como EXE. pueden incluir la biblioteca de tipos como un recurso del pr o pio servidor COM. Los componentes C'OM creados con Visual Basic tie nen la biblioteca de tipos compilada dentro de la DLL. En la siguiente seccin aprender a crear el ensambl ado de interoperabilidad a partir de una DLL C'OM mediante los dos mtodos descritos al principio de esta seccin: usando la utilidad Tl bi mp y haciendo referencia directamente al DLL desde Visual Studio NET.

Cmo usar la utilidad Tlbimp


La utilidad Tl bi mp es una aplicacin individual de consola que crea el e n s a m blado de interoperabilidad N E T basado en la DLL C'OM que especifique. Est situada en el directorio Framevvork S DK en Archivos de programa. El siguiente fragment o de codigo muest ra la sintaxis de Tlbimp:
tlbimp [COMDl1 Fi1ename 1 /[options]

729

La tabla 34.1 .recoge las opciones de lnea de comandos par a tlbimp.exe


Tabla 34.1. Tlbimp.exe Opciones

/asm version: version umber /delaysign /help /keycontainencontainername

Especifica el nmero de versin del ensam blado que se genera Especifica a Tlbimp.exe que firme el ensamblado resultante con firma postergada Muestra las opciones de ayuda para tlbimp. exe Firma el ensamblado resultante con un nombre seguro utilizando el par de claves pblica y privada que se encuentra en el contenedor de claves especificado en el parmetro nom
bre del contene dor

/nologo /out:filename

Suprime la presentacin de la portada de ini cio de Microsoft Especifica el nombre del archivo resultante que se crear. Por defecto, el archivo resul tante tiene el mismo nombre que la DLL COM, pero tenga cuidado si intenta sobrescribir el archivo en caso de que exista en la misma ruta Genera un ensamblado de interoperabilidad primario para la biblioteca de tipos Especifica el archivo que contiene la clave pblica que se debe usar para sealar el en samblado resultante Especifica el archivo de ensamblado que se utiliza para resolver referencias en tipos defi nidos fuera de la biblioteca de tipos actual Suprime la presentacin de mensajes de apro bacin No importa una biblioteca de tipos si la herramienta no resuelve todas las referencias in cluidas en el ensamblado actual o en los ensamblados especificados con la opcin /
r e f e re n c e

/primary /publickey:filename

/reference:filename

/silent /stri ctref

/sysarray

Importa cualquier SafeArray de estilo COM como un tipo Clase S y s t e m . A r r a y adminis trado

730

Opcin /unsafe

Descripcin Genera interfaces sin comprobaciones de segu ridad de .NET Framework. Esta opcin no se debe utilizar a no ser que se conozcan los riesgos que supone exponer este cdigo como no seguro Muestra informacin adicional sobre la bibliote ca de tipos importada cuando se ejecuta tlbimp.exe Muestra ayuda sobre la sintaxis para tlbimp. exe

/verbose

/?

Este comando produce un ens ambl ado N E T con una extensin DEL que reci be el mismo nombre base que la biblioteca incrustada en el archivo de la bibliote ca de tipos (que puede ser diferente del nombre de archivo de la propia biblioteca de archivos). El comando tlbimp admite el nombre de un a r c h i \ o de biblioteca de tipos como dato introducido:
t 1 bim p se rve r.t 1b

Tambi n puede admitir el nombre de un servidor C O M que contiene la biblio teca de tipos incrustada:
t. 1 b i mp server .d11

Al usar la opcin / o u t . se puede especificar un nombre alternativo par a el ensambl ado N E T creado:
t 1 b i mp se rve r.d i 1 /o u t : dotN e tJerve r .d i 1

El ensambl ado producido por la herramienta Tl bi mp. exe es un ensambl ado . NET est ndar que puede ser visto con Ildasm.exe. El ens ambl ado 110 contiene el cdigo del servidor C O M; en su lugar, contiene referencias que ayudan al C LR a encontrar los objetos C O M al macenados en el s e n idor. como los CiUlD del obj e to COM. Imagine el ensamblado generado por tlbimp como un puente que conecta el codigo . NET con el servidor C O M Como el codigo C O M sigue estando en el servidor COM. no debe olvidar instalar e inscribir en el registro todos los servido res C O M que piense usar en sus aplicaciones .NET. En realidad, esto supone una gran ventaja para el programador. Como el servidor C'OM sigue registrado con Window s, las aplicaciones C O M est ndar que no son conscientes de la existencia de N E T pueden seguir usando el mismo servidor C'OM sin trasladar codigo a una pl at aforma especfica NET.

Cmo crear un componente COM


Antes de empl ear la utilidad Tlbimp necesita un componente C'OM con el que trabajar. El listado 34.1 muestra el cdigo para un sencillo DLL ActiveX VB6

731

con varias funciones de clase comn, como establecer y recuperar una propiedad, d es encadenar un ex ento y dex olx er un x alor de un mtodo que tenga par met ros de entrada.
Listado 34.1. Cdigo de servidor COM para Visual Basic 6.0 Op tion Prvate Public E x plicit strMessage Event As String String)

COMF.vent. (Message As

P n v a t e S u b C 1 a s s Tm t ia 1 iz e () s t. r Message - "Default Message" End Sub Public Property Get Message ' ) As essa c je - s t rM e s s a g e End Property Public Property Let Message(ByVdl trMessage - vNewValue Eiid Property Public Function S q u a r e l t (i n t 1 As Integer quarelt - int.l * m t 2 End Function Publ ic Sub Fi reCOMEvent () ai seFvent COMF.vent (strMessage) End Sub S tring

vNewValue

As

String)

Integer,

int2 As

Tnteger)

As

Este codigo se coloca en un modulo de clase llamado COMObj ect. El modulo de clase esta en un proy ecto llamado VB6COMServer. Visual Basic 6.0 compila este codigo en un servidor C O M en proceso e incrusta una biblioteca de tipo en el servidor. La representacin legible de la biblioteca de tipos, escrita en Lenguaje de definicin de mterfaz (IDE) de C O M se muest ra en el listado 34 2.
Listado 34.2. Fuente IDL para el servidor COM del listado 34 1 // Archivo .IDL generado (por el Visor de objetos OLE/COM)

//
// typelib fi 1e n a m e : VBcCOMServer.dll

r
uuid (R 4 0 9 :c 5 0 -ACA.4 - 4E 1F-8D3 c - F3 6F 1EE5F0 3B) , versin 1 .0)

]
1 ib i a r y VB COMS e rve r

{
// TLib : // TLib : OLE Automation : {00020430-0000-0000-

732

C O O O - O 0 0000 000046} imp o r t l i b (" s t d o l e 2 .t l b " ) ; // Declaracin anticipada de todos // esta biblioteca de clases interface COMObject; dispmterface COMObject; los tipos definidos en

[
odl, uuid(59 6 0D780-FEA2-4383-B2CB-9F78E4 6 77 142 ) , ve r s i o n (1.0) , hidden, dual, nonextensible, oleautomation

]
interface COMObject : IDispatch { [i d (0x 68030000) , propget] HRESULT Message ( [out, retval] BSTR* [i d (O x68030000) , propput] HRESULT Message([in] BSTR ); [ i d (0x600 3 0002 ) ] HRESULT S q u a r e l t ( [in, out] short* inti, [in , out] short* in 12, [out, retval] short* ) ; [i d (0x600 30003)] HRESULT F i r e C O M E v e n t ();

);

}; [
uuid (507 30 C 9 7 - 0 9 E B - 4 9 5 C - 98 73 BF.C 6 3 9 OAAc 3A I , version (1.0)

]
coclass COMObject { [default] interface COMObject; [default, source] dispinterf ace COMObject.;

}; [
u u i d (A4D4C3D8-DFFF-4 5D B - 9A 14 - 7 9 1E4F82EF3 5) , version (1.0) , hidden, nonextensible

]
dispinterface __COMObject properties : methods: {

[ i d ( 0x00000001) ]
void COMEvent ( [i n , out] BSTR* Message) ;

}; };

733

Para crear el ensambl ado de interoperabilidad que permite a la aplicacin C# usar la DLL no administrada, debe ejecutar la utilidad Tlbimp descrita en la anterior seccin. En la figura 34.2. puede ver que el parmet ro /out: se usa para dar al ensambl ado de interoperabilidad el nombre c o mp i n t e r o p .di 1 . El nombre del ens amb la do resultante puede ser el que prefiera (incluso puede tener el mismo nombre que el component e C OM original).

Jj
Figura 34.2. La utilidad Tlbimp en funcionam iento

El V B6 COMSe rv er . dl l que se creo usando VB6 ahora puede ser consumido desde cualquier cliente N E T (siempre que la aplicacin haga referencia al e n s ambl ado : omi nterop .d 1 1 y el component e VB6 este registrado en el equipo que este intentando consumi r el codigo). Coomo el resultado de Tlbimp es ahora un ensamblado NET'. puede usar la utilidad I LD AS M para ver los detalles sobre el metadato que se creo a partir de la DLL ActiveX que usa realmente el CLR. La figura 34.3 muestra la utilidad 1LDSM cuando se ejecuta el nuevo comnterop . d 1 1 recin creado. El ens ambl ado generado al i mportar la biblioteca de tipos cuyo cdigo fuente se muestra en el listado 34.3 incluye un espacio de nombres llamado cominterop. que es el nombre del ensambl ado que se paso al par met ro / out desde la utilidad Tlbimp. Este espacio de nombres debe ser tratado exactamente igual que un e s p a cio de nombres definido por el eodigo o por . NET Framework: el codigo debe hacer referencia al espacio de nombres cuando use alguna de las clases del e s p a cio de nombres. La figura 34.3 muestra las clases insertadas en el ensambl ado generado por tlbimp. La clase que usamos en el codigo C# para t rab aj ar con el objeto COM tiene el mismo nombre que el objeto C O M en la instruccin coc as s de la fuente IDE. En el listado 34.3. el objeto C O M recibe un nombre coclass de C OMObj ec t. El ens ambl ado generado por tlbimp incluye una clase N E T con el mismo nombre y es esta clase la que se usa en el codigo para t rabaj ar con el objeto Visual Basic C OM

734

m
A rch iv o Ve; Ayuda

is

^ jn J J

t . . jeL L " i .3 L : f a 5J .'


:n'irter:^ .'lOMObjeit
o n i r t e - : i __O jf . 'O L '. e c ^ E . *''!

'

sta^ce vo d inv:..:o-iib S.-::er' p-,ntr'-r


^ a i v i e vOt- 'ni:-.; : ^ d ^ S .s :r'- ^' tr- e

_J rnirifr-'d Fi'

jM E v
, *

J
J

^-.etncd g e ^ M e ^ - a g e s-et_ ^'e? -:ag e

nnr^ '
. i^ -:= t

D rcp M e ^ a a c

s n r .q '

B _-0r.lC b,e.:t
:a-:. .f'te rfa c 'r pi.;bli'i a r n tr a ::

'-C 'M E v-e'-*

v-:* z s v :n g ,

M 'jL je z t jI O M E iv e n t E en'.Kjndiet

B
asse m bty c o m in te ro p v e r 1 C' C C -

Figura 34.3. ILDASM con un ensamblado generado por Tlbimp

Cmo usar el ensamblado de interoperabilidad desde C#


Usar el component e C O M desde C# es muy sencillo una vez que lia creado el ensambl ado de interoperabilidad. Para usar este ensamblado, siga los siguientes pasos: 1. 2. C ree una aplicacin de cliente de prueba. Para hacerlo mas sencillo, cree una nueva aplicacin de formulario de Wi ndows y lamela Interop. Una vez que ha creado la aplicacin, coloque su codigo en el evento el ick de un botn y agregue un botn a Forml .es. A continuacin, haga clic con el botn derecho del ratn sobre el archivo References en el Ex plorador de soluciones y seleccione Agregar referencia. Se abrir el cuadro de dialogo Agregar referencia. Es igual al cuadro de dialogo Agregar referencia de VB6. Bsicamente, debe hacer referencia al e n s ambl ado que necesita usar, que al igual que cualquier otro ensamblado N E T no se aade por defecto a un nuev o prov ecto. Para agregar una referencia a la DLL Cominterop que creo anteriormente, haga clic en el botn E x a m i n a r y localice el ensamblado en su disco duro. Una vez hecho, su cuadro de dilogo Agregar referencia deber tener un aspecto similar al de la figura 34.4.

3.

735

Agregar referencia
.[JET jc O M [ P r o y e c to s |

- is

m r
E x a m in a r ...

_xj

N o m b re de

o rn p o n e n te

! V e rs i n 1 . 0 .3 3 0 0 . 0 ? n ' jm

| R u ta d e a

TfiM
< -. d*=- p fo g f-jrn . 'iM i :... .

--------------------- 1
S e le c c io n a r

A c c e s s ib ility dll

C :\W IN D 1iW S \M ic r o s o ft. N E T \...

vUib
/L it ' O ._.tdiDei:i'-. n r r . 1 f 't -i P tl[>--f--. n r .^ .r 'p p u r t -iijij

C :\A nh
I:'i.Ar nhiiv I : 'i, A r i;h i
I : 'i.A r c h i I : \ A t c h iv ::'i,A r.:h iv i-'lA r-rhi-..-

1.li.n.
9. l . ";n o .n '" - t i. -iji .n

: : \ A r . : h iv i-; i i r pr ijq r jrn .'iA r * .. . 'I : \ A r r h i v i? d e p r o g r a r r id 'iA fL ' i,A r c h iv is de p r o a r a n id'i,A ri' d e p r o q r.a rn .V iA n :.

1r ' . a

lL 'e i : u [r,

fis jyAJDu-, M
Ir h b l[ ie i- |'- n r ','Viridc'1 /'1 :- F

jU 0

-.1. jjuu.O j .
9 . i. : ; : - i 0 . n

O 'iA r c h iv i-; d e is d e <s d e

' I r y - . t j l t n f f r i p n s e u tr v - . r a ll n t i j'i to re L ib |-_r-..-,tdll

l.u.u.u l.lj.u.l]
l. . 0 .0 1 n n n

* -f

t-V Ljd e L it. i .- ir / 'l. )- ih

d e r; d e

.. p 'ri'iq ra rr i 'iM !':. .. pr o g ra n l'iA r c ... p r o q r arrid i,A r e . .. p ro g ra m a 1 !,A r e , .. p ro q ra m a 1 ! A r e . ..


r " r ifH ,r fi.V iA " _ J

C o m p o n e n te s s e le c c io n a d o s : N o m b r e d e c o m p o n e n te [c o m in te r o D .d ll I T ip o A r c h iv o | O r ig e n

.....

............1

Q u ita r

C :\c o m in te r o p .d ll

A c e p ta r [

C a n c e la r

A yuda

Figura 34.4. Adicin de la referencia C ominterop

Una vez que la aplicacin hace referencia al ensamblado, puede usarlo e x a ct a mente igual que cualqui er otro ens ambl ado N E T Como Visual Studio NET dispone de funciones tan tiles (como compl et ar o listar mi embros a u t o m t i c a mente) una vez que se agrega la referencia, sus mtodos, ex entos y propiedades estn a su disposicin mediante el IDE. La figura 34.5 muest ra el listado a u t o m tico de mi embros en f unc iona mie nto despues de que la instancia del objeto C o m i n t e r o p haya sido creada y de que se haga referencia al ensambl ado con la instruccin u s i n g
prvate '/oa button1_Clickiob; ect sender, S y s t e m E v e n t A r g s e)

{
C O M O b j e c t Objectlnstance: short N u m i short N u m 2 short S um; Obj ectl nstance = ne/.- C O M O b j e c t C l a s s ): N u m i = 1 23 N u m 2 = 456. S u m = Objectl nstance

*r ; , S ?
= :,- :-M E ..,',:

o . ' r Figura 34.5. Listado automtico de miembros en funcionamiento

736

Para co mp ro ba r todos los mtodos, propiedades y eventos que ha escrito en la DLL ActiveX, copie el listado 34.3 en la aplicacin Wi ndo ws Fo rms .
Listado 34.3. Cdigo de cliente COM escrito en C# < ' sumar y> El principal punto de entrada para < /s umar y> [STAThread] static void M a i n ( )

la aplicacin.

{
A p p l i c a t i o n .R u n (new Formi () ) ;

// Cree un controlador para el evento prvate COMObject COMEventEventHandler COMEvent Handle rlnstance; private vord buttonl Click (object sender, S y s t e m .EventArgs e

// cree una nueva instancia de la clase COMObject COMObject Objectlnstance; short Numl ; short N u m 2 ; short Sum; Objectlnstance - new COMObjectClass () ; Numl = 5 ; Num2 - 6; // Llame al mtodo Squarelt Sum - O b j ec tI ns ta nc e.S q u a r e l t (ref listBoxl .11 ems .Add 1 1 stBox 1.1 1 e m s .Add

Numl,

ref

N u m 2 );

(Sum . T o S t n n g O ) ; (Objectlnstance.Message) ; del que se

// Establezca un valor de mensaje diferente // ofrece por defecto Objectlnstance.Message = "C# Rocks";

COMEventHandlerInstance = new C O M O b j e c t _ C O M E v e n t E v en tH an dl er (C OM Ev en tH an d le r) ; Obj ec tI ns ta nc e.COMEvent += COMEventHandlerInstance; O b j e c t I n s t a n c e . F i r e C O M E v e n t ();

void

COM E v e n t H a n d l e r (ref

string Message)

{
1 i s t Box 1.It e m s .Add(Message) ;

737

y S H H R ,
C a ll In te ro p A s s e m b ly

--

IDefault _
!

M enage

^ OCXS

Figura 34.6. Resultado del cliente C# usando el co m ponente COM

Como cualquier otro objeto de NET. el oper ador n e w se usa para crear una nueva instancia de la clase C O M O b j e c t . como muestra el siguiente fragmento de codigo:
01 ? , r c t
Instance new COMObj e c t O ;

l i a s Distanciar el nombre de la variable O b i e c t I rus t a n c e . use el objeto igual que cualquier otro objeto NET; no hace falta hacer nada especial. El RCW se encarga de toda la interoperabilidad. conversiones de tipos y organizacin de objetos par a los tipos, de modo que no se dar cuenta de ninguno de los p r e p a r a m o s internos C OM que se estn produciendo. Si lia usado la nteroperabilidad C O M de VB. NET. percibir algunas diferen cias respecto al modo en que se pasan los parmet ros a los mtodos en CU. Si observa el codigo de CU del mtodo S q u a r e l t . ver que se ha agregado la pal abra clave Ref:
IJum 1
//

5; al me t o c i o S q u a r e Lt M um l, re Num2 ) ;

i'him" = :;
T, l a m e = S um Ob ; e O I n.s t a n e e . S q u a r e I t ( r e f

Eos servidores C O M de Visual Basic pueden pas ar valores por valor o por referencia. El codigo CU necesita usar las pal abr as clave adecuadas cuando pasa parmet ros a las llamadas de mtodo COM. Puede usar 1LDASM para que le ayude a determinar si un parmet ro debe pasarse por valor o por referencia. Abra el ensambl ado generado por Tl bn np usando la herramienta 1LDASM \ mire la definicin del mtodo al que quiere llamar. En este caso, debe llamar al mt odo S q u a r e l t ( ; . que se muest ra en el ens ambl ado con la siguiente firma:
S qua r e T t.

: 1 1 ;t i

i int 1> : , r n 1 . 1 f & i

Tras los dos puntos situamos el tipo de valor devuelto por el mtodo. La firma del mtodo S q u a r e l t ( ) muest ra un tipo devuelto i n t l o . que. en la jerga del lenguaje intermedio, indica un entero de 16 bits. Tras los tipos de par met ro se

738

coloca un signo & que indica que el p ar met ro debe pasarse por referencia. Los par met ros que deben ser pasados por referencia deben ir a c ompa ad os de la pal abr a clave r e f en el cliente CU. Los par met ros que deben pasarse por valor no aparecen con el smbolo & en el ensamblado. En este caso, el cliente CU no necesita usar la pal abr a clave r e f en los parmetros.

Cmo hacer referencia a la DLL COM desde C#


En la seccin s u m a n , aprendi a usar el ensambl ado de interoperabilidad creado por Tl bi mp. exe en una aplicacin de formulario Wi ndows de CU. La p ri n cipal razn para usar Tlbimp.exe para crear el ensamblado de interoperabilidades es que se le puede dar un nombre seguro con la utilidad SN.exc para despus instalarlo en la cache de ensambl ados global usando la utilidad G A C U T I L Una \ e z en la GAC. el e ns ambl ado puede ser compar tido entre muchos otros e n s a m b l a d o s o p r o v e c t o s N E T . Si e s t a e s c r i b i e n d o u n a a p l i c a c i n q u e us a mt eroperabi lidad C O M y el ens ambl ado no necesita ser compartido, puede si m plemente hacer referencia a la DLL C OM mediante Visual Studio .NET. lo que creara el R CW por nosotros. Para agregar una referencia para una DLL C O M directamente a su provecto, siga estos pasos:

1 . Haga clic con el botn derecho del ratn en la carpeta References del Explorador de soluciones. Se abrir el cuadro de dialogo Agregar re ferencia. mostrado en la figura 34.7. La segunda ficha. C OM . muestra
todos los objetos C O M registrados en el equipo local.
Agregar referencia

*J

se le ccio na r

N o m b re d e c o m p o n e n te

T ipo

O rig e n

m i

A c e p ta r

c a n c e la r

Ayuda

Figura 34.7. Cmo agregar una referencia a un objeto COM directamente

739

Tr as seleccionar el componente C O M que debe usar, puede utilizar el mi s mo cdigo que us par a escribir la aplicacin de formulario de Windows, c amb i an d o solamente el ens amb la do al que se hace referencia, que en este caso sera V B 6 C o mS er v er y no Cominterop.
using VB rC OM Se rv er ; Ob j e c t I n s t a n c e = n e w COMObj e c t C 1 a s s ( ) ;

C omo puede ver. hacer referencia a un component e C O M directamente desde IDE es incluso mas sencillo usando la utilidad Tlbimp. aunque pierda parte de versatilidad respecto a lo que puede hacer realmente con el componente.

Cmo manejar errores de interoperabilidad


En N E T Framework, el C L R informa de los errores iniciando excepciones cuando algo sale mal. En C O M. los EIRESULT son el modo de informar de los errores, de modo que el R CW necesita ser ca paz de describir el EIRESULT de un error dado a la excepcin N E T equivalente. La tabla 34.2 describe los EIRESULT est ndar de C O M a sus excepciones N E T equivalentes.
Tabla 34.2 H R E S U LT para excepciones NET

HRESULT
M SEE E A P P D O M A I NU N L O A D E D

Excepcin .NET
A p p D o m a in U n l o a d e d E x c e p t io n A p p li c a ti o n E x c e p ti o n A r g u m e n t Exce ption A r g u m e n tO u t O fR a n g e E x c e p t io n A r i th m e t ic E x c e p ti o n A r r a y T y p e M i s m a tch Except ion Bad I m a g e F o r m a t Exce pt ion C O M E m u la te E x c e p t ion C on te x t M a r s h a IExcept ion Co r e E x c e p ti o n C r y p t o g r a p h i c E x c e p ti o n PA TH NOT FOUND Di rec tor y N o tF o u nd Except ion D iv id e B y Z e ro E xc e p ti o n D u p l ic a t e W a i t O b j e c t E x c e p t i o n E n d O fS t re am Except ion Entry Point Not Fou nd Except ion Exce ption

C O R E A P P L IC A T I O N C O R E A R G U M E N T o E IN V A L ID A R G COR E A R G U M E N T O U T O F R A N G E COR E ARITHM ETIC o ERROR ARITHM ETIC O V E R F L O W C O R E A R R A Y T Y P E M IS M A T C H C O R E B A D I M A G E F O R M A T o E R R O R BA D F O R M A T COR E COMEMULATE ERROR

COR E CO NTEXTMARSHAL COR E CORE N TE FAIL COR E D IR E C T O R Y N O TFO U N D o ERROR C O R E DIVIDE B Y Z E R O COR E _ D U P L IC A T E W A lTO B JE CT COR E ENDO FSTREAM COR E TYPELOAD C O R E E X C E P T IO N

740

HRESULT
C O R E E X E C U T IO N E N G IN E C O R E FI E L D A C C E S S COR E FILEN O TFO UN D o ERROR FILE N O T F O U N D

Excepcin .NET
Exe cu tion E n g in e E x ce p ti o n Field A c c e s s Excefit ion Fi leN otF oi .i iid Ex ce pti on Foi m a tE x ce p ti o n In d e x O u tO f R a n g e E x c e p ti o n 1 11 valid C as t Exce pt ion In v a li d C o m O b j e c tE x c e p ti o n Inv a lid Fi lt e rC ri te r i aE xce pti on In v a li d O l e V a i i a n t T y p e E x c e p ti o n In v a li d O p e ia ti o n E x c e p ti o n lOEx c e p tio n A c c e s s E x c e p t io n M e th o d A c c e s s E x c e p ti o n M is si n g Fie Id Except ion M is s in g M a n i fe s tR e s o u i c e E x c e | )t io n M iss i n g M e m b e r Except ion M is s ingMet hod Except ion M u lt ic a s tN o tS u p p o r te d E x c e p t io n N o t F i n i te N u n i b e t Exce ption N o t lm p l e m e n te d Exce ption N ot S u pp o r te d Except ion N u l l R e fe r e n c e E x c e p ti o n O u tO fM e m o r y E x c e p ti o n O v e r fl o w E x c e p ti o n EXCED RANGE Path To o Long Except ion RankE xce ptio n R e fl e c ti o n T y p e L o a d Except ion R e m o ti n g E x c e p ti o n Sa te A r r a y T y p e M i s m a tc h Except ion S e cu rity E x ce p ti o n Se ria liz a tio n Ex cept ion St a ck O v e r fl o w E x c e p ti o n Sy n c hr o n iz at ion LockE xception S ys te m E x ce p ti o n T arg e tE xc ep ti o n Tar get In voc ation Ex ception T a rget Pa r a m et er C o u nt E xce ption Thr e ad A bo rt Except ion

COR E FORMAT C O R E_ I N D E X O U T O F R A N G E COR E JN V A L ID C A S T o E N O INTERFACE

COR E J N V A LID C O M O B JE C T COR EJN VALID FILTER C RITER IA COR COR E IN V A L ID O L EVA R IAN T T Y PE E INVALI D OP E R A TI O N

C O R E IO COR E MEMBERACCESS COR E METHODACCESS C O R E M IS S I N G F IE L D COR E MISSING MANIFESTRESOURCE C O R E M IS S I N G M E M B E R C O R E M IS S I N G M E T H O D COR E M U LT IC ASTN OTSU PPOR TED COR E NOTFINITENUM BER E NOTIMPL COR E N O TSUPPO RTED COR E N ULLREF ERE NC E o E POINTER

COR E O U TO FM EM O R Y o E OU TO FM EM OR Y COR E O VER FLOW C O R E P A T H T O O L O N G o E R R O R FI LE N A M E C O R E R AN K COR E R E FLECT IO N TYPELO AD COR E REMOTING COR COR COR E SA FE AR R A Y TY PE M IS M A T C H E S E C U R IT Y E SE R IA L IZ A T IO N

COR E STAC KO VER FLO W o ERROR STACK O VER FLO W COR E S Y N C H R O N I Z A T I O N LO C K

COR E SYSTEM COR E TARGET C O R E T A R G E TIN V O C A T I O N COR E TAR G ETPARAM C O U N T CORE THREADABORTED

741

HRESULT
COR E TH R E A D IN T E R R U P T E D COR E THREADSTATE

Excepcin .NET
Th le a d Interr up ted Except ion T h re ad State Except ion T h r e a d S t o p E x c e p ti o n T y p e L o a d E x c e p t ion T y p e ln it ia liz a ti o n E x c e p ti o n Ve r ifi c a ti o n Except ion W e a k R e f e re nee Except ion V T a b le C a ll s N o t S u p p o it e d E x c e p t m n C O M E x c e p t io n

COR E T H R E A D S T O P COR E TYPELOAD

C O R E T Y P E IN IT IA L IZ AT IO N COR E V E R IF I C A T IO N

COREWEAKREFERENCE COR E V T A B LE C A LLS N O T S U P P O R T E D C u a lq u ie r otro H R E S U L T

Si su aplicacin debe obtener informacin de error extendida y el objeto COM admite la interfaz IErrorlnfo. puede usar el objeto IE rr or ln fo para con seguir informacin sobre la excepcin. La tabla 34.3 describe la informacin de error adicional.

Tabla 34.3.

Informacin de error extendida de interoperabilidad COM

Campo de la excepcin
ErrorCode HelpLink

Informacin de la fuente COM


El
hresult

devuelto por la llamada de mtodo

Si IErrorlnfo->HelpConte:-:t no es cero, la cadena se forma concatenando IE rr orl nf o - > G e t H e 1 p F i le y "#" y I E r r o r l n f o >GetHe 1p c o n t e t . En caso contrario, la ca dena devuelta procede de I E r r o r l n f o
GetHelpFile.

InnerException Message Source StackT race TargetSite

Siempre es nuil Cadena devuelta de I E r r o r l n f o - > G e t D e s c riptio r .

Cadena devuelta de IErrorlnfo ~>GetSource El seguimiento de la pila de esta excepcin .NET El nombre del mtodo que hizo que se devolviese HRESULT a .NET
i

Obviamente, debe incluir control de errores en sus aplicaciones, aunque este usando interoperabilidad C OM . No hay diferencia fundamental entre el modo de codificar c omponentes C'OM y el modo de codificar ensambl ados NET. de modo que el control de excepciones e st ruc tur ado de N E T debe usarse siempre que escribe eodigo susceptible de ca us ar una excepcin.

742

Cm o usar la invocacin de plataform a


Si es un p ro gr amado r de Visual Basie 6. el API Win32 ha sido su modo de apr ovechar toda la potencia de la programacin. En NET. todava puede acceder al API Win32 desde C#. aunque casi toda o toda la funcionalidad que pr oba bl e mente este usando ya estaba presente en N E T Framework. La invocacin de funciones de DLL de C se consigue usando el servicio invocacin de plataforma. La invocacin de plat af orma es un servicio que permite al cdigo administrado llamar a funciones de DLL C O M no administradas. Mediante la clase E'LLImpor t Attribute, puede especi fi car el nombre de la DLL y de la funcin DLL que debe usarse en su aplicacin C#. Igual que el acceso al API Wi n32 en VB6. debe saber el nombre de la DLL \ la funcin de la DLL qu e se quiere ejecutar. Una vez ha logrado esto, puede llamar simplemente a la funcin usando el atributo DL LI mp or t en un mtodo sealado con mo di fi ca dores estticos y externos, como muest ra el siguiente eodigo:
us i n q p u b lic S y s t e m . R u n t i m e . I n t e r o p S e r v i c e .s ; s ta tic extern in t Me s s a f e B o : : ti nt t yp e i ; hVJnd , S trin q te:-:*, iE > 1 1 I mp o 1 1 f " u s e r 3 .1 . ci L 1 " ) J S t: r r n q c ap1 1 on , ui nt

C uando usa la i m o ca c i o n de plataforma, puede necesitar ca mb ia r el c o m p o r tamiento por defecto de la interoperabilidad entre el eodigo gestionado y el no g e s t i o n a d o . Es to p ue d e c o n s e g u i r s e m o d i f i c a n d o los c a m p o s de la cl as e D LLI mp ortAttribute. La tabla 34.4 describe los campos de la clase DL Ll mp or tA t tribute que pueden ser personalizados.

Tabla 34.4.

Campos DLLIm portAttribute

Campo de objeto
EntryPoint CharSet

Descripcin
Especifica el punto de entrada de la DLL a la que se va a llamar. Controla el modo en que los argumentos de cade na deben ser organizados para la funcin. El valor por defecto es C h a r S e t .Ans. Evita que un punto de entrada se modifique para que corresponda con el conjunto de caracteres. El valor por defecto vara dependiendo del lenguaje de programacin. Indica el valor de convencin de llamada utilizado para pasar los argumentos del mtodo. El valor por

ExactSpelling

CallingConvention

743

Campo de objeto

Descripcin defecto es winAPi, que se corresponde a t o __stcicall para las plataformas Intel basadas en 32 bits.

PreserveSig

Indica que la firma administrada del mtodo no se debe transformar en una firma no administrada que devuelve h r e s u l t y que puede tener un argumen to adicional [out, retval] para el valor devuel to. El valor por defecto es True (la firma no se puede modificar).

SetLastError

Permite al invocador usar la funcin API M a r s h a l . GetLastwin.32Error para determinar si se pro dujo un error mientras se ejecutaba el mtodo. En Visual Basic, el valor por defecto es True; en C# y C++, el valor por defecto es False. i

La operacion de llamar a funciones DLL desde C# es similar a hacerlo desde Visual Basic 6. Sin embargo, con el atributo D L L I m p o r t slo est pas an do el nombre de la DLL y el mtodo que debe llamar.

NOTA: Se recomienda que las llamadas de funcin DLL estn agrupadas en clases separadas. Esto simplifica la codificacin, asla las llamadas de funcin externas y reduce la carga.

Resum en
Este captulo describe cmo usar objetos C O M en cdigo N E T y cmo u sar la utilidad Tlbimp para generar ensambl ados NET. Tambi n se estudia b r e\ ement e como interpretar los ensambl ados generados. Ademas, se ha explicado cmo e s cribir codigo cliente C O M en C#. incluyendo llamadas a me'todos C O M y a t r a b a j a r con propiedades C O M Como puede ver. N E T Framework permite integrar fcilmente el codigo C'OM existente en sus aplicaciones NET. Esta sencilla inte gracin le da la oportunidad de mover poco a poco partes de una aplicacin a NET. sin tener que reescribir toda la lgica de componentes C O M de C#.

744

Hn Cmo trabajar con servicios COM+


Microsoft ha mejorado mucho la funcionalidad del subsistema C O M desde que se publico por primera vez en 1993. Una de las mejoras mas significativas intro ducidas en el modelo de progr amaci n C'OM se introdujo en 1997 con la pu bl i ca cin de Microsoft Transact ion Server (MTS). MTS. publicado por primera vez como complemento de Wi ndows NT 4.0. permita a los pro gr amad ore s d e sa r r o llar componentes mediante un intermediario que prop or ci onaba transacciones, s eg u n d a d b asada en funciones v servicios de agrupaci n de recursos. Con la publicacin de Wi ndows 2000. Microsoft elevo el modelo de programaclon que ofreca MTS a un subsistema de primera clase. C OM t es. en gran parte, una combi nacin del modelo de pro gr amaci n C O M tradicional \ el modelo de programaci n MTS. Por primera vez. Wi ndows p ropor ci onaba compatibilidad con los dos componentes C O M (o no configurados) tradicionales con co mp o ne n tes atribuidos (o configurados) del estilo MTS directamente desde el sistema o pe rativo. . NET Framevvork ofrece ambos estilos de componentes a los programadores que escriben s oftware basado en componentes. Este capitulo estudia como d e s a rrollar clases C# que pueden usarse como componentes configurados con C O M t .

ADVERTENCIA: Aunque NET Framework est disponible en muchas plataformas de sistemas operativos, COM+ no est disponible en el mismo

747

conjunto de plataformas. Los componentes escritos en C# que aprovechan los servicios COM+ slo pueden ser usados en plataformas que admiten COM+. El cdigo de la clase COM+ compilado en NET Framework inicia una excepcin de clase PlatformNotSupported si el cdigo intenta acceder a una caracterstica que no existe en la plataforma de tiempo de ejecucin.

El espacio de nombres System.EnterpriseServices


Cual qui er clase C# puede ser usada por clientes C O M como un componente C OM . independientemente del rbol de herencia de la clase. Las clases C# solo pueden der ivarse de S y s t e m .Ob j ect y seguir siendo usadas como c o mp o n e n tes COM. Sin embargo, apr ovechar los servicios C O M + en clases C# requiere unas normas de herencia mas rigurosas. El es paci de nombres System. E n t e r p r i s e S e r v i c e s proporciona las clases, enumeraciones, estructuras, delegados e interfaces necesarias para es cri bir aplicaciones que aprov echen C O M + y sus servicios de nivel de empresa. Si ha escrito componentes en C++ o Visual Basic 6 que t erminarn ejecutndose en un tiempo de ejecucin de servicios C O M + . la mayor parte de este captulo le res ul tara familiar Desde el punto de v ista de un pr ogr amad or de C O M + exp eri ment a do. el espaci o de nombres System. E n t e r p r i s e S e r v i c e s contiene la funcionalidad a la que antes tena acceso mediante programaci n. Si ha escrito componentes en VB6. le al egrar saber que las caractersticas que anteriormente 110 estaban disponibles, como la agrupaci n de objetos, ahora estn a su entera disposicin mediante Framework. Servicios como la activacin justo a tiempo (JIT). la agr upaci n de objetos, el procesamiento de transacciones y la admi ni s tracin de propiedades compar tidas estn disponibles como clases o atributos en el espacio de nombres S y s t e m .En terpriseServices. La tabla 35.1 describe cada una de las clases disponibles en el espacio de nombres Sy.stcm. E nterpr iseServices.

Tabla 35.1.

Clases System EnterpriseServices

Clase
Applicai ion AccessControl Attribute

Descripcin
Permite establecer una configuracin de seguridad para la biblioteca o apli cacin de servidor que alberga la apli cacin. No se puede heredar esta clase.

748

Clase Application Activation Attribute

Descripcin Especifica si los componentes del en samblado se ejecutan en el proceso del creador o en un proceso del sistema. Especifica el identificador de la aplica cin (como GUID) para este ensambla do. No se puede heredar esta clase. Especifica el nombre de la aplicacin COM+ que se utilizar para la instala cin de los componentes del ensam blado. No se puede heredar esta clase. Habilita el uso de una cola para el en samblado marcado y permite a la apli cacin leer llamadas a mtodos desde colas de Message Queue Server. No se puede heredar esta clase. Marca el mtodo con atributos como un objeto AutoComplet-.e. No se pue de heredar esta clase. Ajusta la clase Byot.ServerEx y las interfaces DTC i c r e a t e W i t h Transa ction Ex y IC r e a t .eWi t h T ip T r a n s ac t io n E de COM + . No Se puede
h e r e d a r e st a clase.

Application IDAttribute

Applicai ion NameAtt ri bute

Appi icationQueu i ng Attribute

AutoCompleteAttribute

BYOT

ComponentAccessControl Attribute

Habilita la comprobacin de seguridad en las llamadas a un componente. No se puede heredar esta clase. Permite pasar propiedades de contex to desde el Integrador de transaccio nes COM (COMTI) al contexto de COM+. Habilita la posibilidad de construccin de objetos COM+. No se puede here dar esta clase. Obtiene informacin acerca del contex to de objetos de COM+. No se puede heredar esta clase. Especifica una descripcin para un en samblado (aplicacin), componente, mtodo o interfaz. No se puede here dar esta clase.

COMTIIntrinsicsAttribute

Const ruction Enabled Attribute

ContextUtil

DescriptionAttribute

749

Clase EventClassAttribute

Descripcin Marca la clase con atributos como una clase de eventos. No se puede here dar esta clase. Habilita el seguimiento de eventos para un componente. No se puede heredar esta clase. Establece la clase de excepcin de cola para la clase en cola. No se puede he redar esta clase. Permite el acceso a valores intrnse cos de ASP desde co nt ex t ut i l . G e tN am ed Pr op er t y. No se puede heredar esta clase. Habilita la capacidad de utilizar una cola para la interfaz marcada. No se puede heredar esta clase. Habilita o deshabilita la activacin jus to a tiempo (JIT). No se puede heredar esta clase. Determina si el componente participa en el equilibrio de carga, en caso de que el servicio de equilibrio de carga de componentes est instalado y habi litado en el servidor. Obliga a crear el objeto con atributos en el contexto del creador, si es posi ble. No se puede heredar esta clase. Habilita y configura el agrupamiento de ; objetos para un componente. No se puede heredar esta clase. Identifica un componente como com ponente privado que slo puede ser visto y activado por otros componen tes de la misma aplicacin. No se pue de heredar esta clase. Recupera informacin de error exten dida sobre mtodos relativos a mlti ples objetos COM + . Esto tambin incluye mtodos que instalan, impor tan y exportan componentes y aplica-

EventT racking En a bledAttri bute

Except ionClassAttri bute

1 1 SIntri nsicsAttri bute

Inte rfaceQ ueu ing Attribute

J ust InTimeActi vat ion Attribute

Load Balancing Supported Attribute

MustRunlnClientContextAttribute

Object Poo ling Attribute

PrivateComponent Attribute

Reg istrat ion Erro rlnfo

750

Clase

Descripcin ciones COM+. No se puede heredar esta clase.

Registration Exception RegistrationHelper

Excepcin que se produce cuando se detecta un error de registro. Instala y configura ensamblados en el catlogo de COM+. No se puede here dar esta clase. Almacena objetos en la transaccin I actual. No se puede heredar esta clase. Garantiza que la infraestructura reali ce las llamadas por medio de una interfaz para un mtodo o para cada mtodo de una clase cuando se utiliza el servicio de seguridad. Las clases necesitan utilizar interfaces para poder usar los servicios de seguridad. No se puede heredar esta clase. Describe la cadena de llamadores que conducen hasta la llamada al mtodo actual. Suministra una coleccin ordenada de identidades en la cadena de llamadas actual. Contiene informacin relativa a una identidad incluida en una cadena de lla madas de COM+. Configura una funcin para una apli cacin o un componente. No se puede heredar esta clase. Representa la clase base de todas las clases que utilizan servicios de COM+. Excepcin que se produce cuando se detecta un error en un componente que utiliza servicios. Obtiene acceso a una propiedad com partida. No se puede heredar esta clase. Representa una coleccin de propie dades compartidas. No se puede here dar esta clase.

ResourcePool SecureMet hod Attribute

! SecurityCallContext
I

SecurityCallers

Securityldentity

SecurityRoleAttribute

ServicedComponent ServicedComponentException

SharedProperty Shared PropertyGroup

751

Clase SharedPropertyGroupManager

Descripcin Controla el acceso a grupos de propie dades compartidas. No se puede here dar esta clase. Establece el valor de sincronizacin del componente. No se puede heredar esta clase. Especifica el tipo de transaccin que est disponible para el objeto con atri butos. Los valores permitidos son miembros de la enumeracin T r a n sactionOption.

Synchronization Attribute

T ransactionAttribute

Si va a escribir clases que se ejecutan en servicios C O M + . estara escribiendo lo que se conoce como comp on en tes que usan servicios. Los componentes que u s a n s e r v i c i o s a p r o v e c h a n las c a r a c t e r s t i c a s del e s p a c i o de n o m b r e s S y s t e m .Enterpr i seServices y le permiten usar las caractersticas e m presariales de C O M +

La clase ServicedComponent
Cual qui er clase diseada par a apr ov ech ar los serv icios de C O M + debe deri varse d i rec tamen te de Se rvi c e d C o m p o n e n t o de una clase que tenga ServicedComponent en al guna parte de su rbol de herencia. Todos los serv icios C O M + que puede usar estn disponibles asignando atributos a las cl a ses que se derivan de la clase ServicedComponent. La clase Serv eedComponent no admite ninguna propiedad; sin e m b a r go. admite una s ene de mtodos pblicos que pueden ser invocados por clientes de c l a s e . La m a v o r p a r t e de e s t o s m t o d o s , i n c l u y e n d o A c t v a t e ( ) . Deactivate ( ) y CanRePooled ( ) . describen los mtodos definidos por mterfaces C O M t . como IOb jectCont ro 1 . Estos mtodos son virtuales y p u e den ser reemplazados por clases derivadas par a propor ci onar funcionalidad es pe cfica. El listado 35 1 muestra una sencilla clase C O M + escrita en CU. Este objeto participa en el ag rupami ent o de objetos C O M + .
Listado 35.1. C om p on e n te COM+ agrupable en C# us ing System.EnteipiiseServices; [Ob j e c t P o o 1 in g {5 , 10)] public.' class Pool cdClass

: Serv eedComponent

752

{
pi.ib 1 i c P o o led C Jass ( )

I 1 - P o o 1 e el C i i )
pub 11c ass

(j

ov er r id e true;

bo o 1

CanBePooled {

{
return

}
pub 1 .1 e ovo rrnde vo id Ac t i vat e )

1 )
puId lie ove r r i de void Dea e 1 1 vat. e < i

La elase del listado 35.1 usa un a t r ib u to de N E T F r a me w o r k ll amado Oh j e c t P o o l i n g para indicar que la clase P o c e ocie d s s debe poder a g r u parse en C OM + . El atributo O b j e c t P o o ' l i n q admite varios constructores. El listado 35.1 usa el const ructor que acepta dos nmeros enteros que representan el t amao mxi mo y mnimo de la agrupacin. El codigo usa los valores 5 y 10. lo que indica a C O M + que debe admitir un mi mmo de cinco y un mxi mo de diez objetos de esta clase en la agrupaci n de objetos C O M b Eos componentes C O M + escritos en C# que quieren formar parte de una a g r u pacin de objetos C O M + deben reempl azar al mtodo virtual C a n B e P o o 1 erl ; ; de la clase base S e r v i c e d C o m p o n e n t y deben devolver True. Si se devuelve un valor False significa que el componente no debe formar parte de la a g r u p a cin de objetos. Los componentes C O M + que pueden ser agr upad os tambin pueden reempl a zar a los mtodos Servi c e dC om p o n e n t virtuales llamados Act ivate ; ) y Peaeti vate ( ) . El mtodo A c t v at e ( ) es i nvocado cuando el objeto es eliminado de la agr up aci n de objetos y asi gn ad o a un cliente y el mtodo Peacti vate ( ) es invocado cuando el objeto es liberado por un cliente y de vuelto a la aplicacin. Debe seguir las directrices impuestas por el desarrollo de C O M + est ndar y colocar todo el codigo relevante de destruccin y construccin de estado de objetos en los mtodos A c t v a t e () y I eaot iva te (). El c ons tructor y destructor de su clase son invocados, pero solo son invocados una vez. El constructor es invocado solo cuando C O M + crea instancias de su objeto para colocarlas en la agr upaci n de objetos C O M + y el destructor solo es llamado cuando C O M 4 destruye el objeto tras eliminarlo de la agrupacin. El mtodo A c ti v a te ( ) se diferencia del const ructor en que se invoca cada vez que la

753

instancia se asigna a un cliente C O M + El mtodo D e a c t i v a t e ( ) se di fer en cia del dest ructor en que se invoca cada vez que la instancia es liberada de un cliente C'OM t- y devuelta a la agr upaci n de objetos C O M + . Si tiene codigo que debe realizar alguna micializacion cada vez que se le asigna a un nuev o cliente el uso del objeto, coloque el codigo en A c t v a t e ( ) . en lugar de en su constructor de clase. Del mi smo modo, si tiene algn codigo que deba realizar al guna desinicializacion cada vez que un nuev o cliente libere el objeto, coloque el codigo en - a t i v j* - ; : . en lugar de en su destructor de clase.

Cmo registrar clases con COM+


Las clases de CU diseadas para ser usadas en una aplicacin COM< deben seguir las mismas reglas bsicas que las clases de CU diseadas para ser usadas por los clasicos clientes COM. En el capitulo anterior se describe como usar CU para crear componentes C'OM. Al igual que los componentes C'OM escritos en CU. los componentes C O M + escritos en CU deben compilarse en un ensambl ado basado en DEL y deben tener un nombre seguro (lo que requiere que el e n sa mb l a do tenga un par de clave publica e informacin de versin). Al igual que los componentes C'OM. esta informacin puede ser especificada para componentes C O M + mediante atributos especificados en el codigo fuente CU. Puede instalar sus clases en una aplicacin C O M + mediante una herramienta de lnea de c omando llamada r e q s v c s que se incluye en N 1 I Framevvork. Esta herramienta de linea de comando inscribe todas las clases publicas encontradas en un ens ambl ado basado en DLL con C'OM t y realiza todas las inscripciones necesarias para hacer que las clases sean tan visibles como las clase C O M + . El listado 35.2 es una pequea modificacin al listado 35.1. Contiene los at ri butos necesarios para p re para r el ensambl ado generado para que admita un n o m bre seguro.
Listado 35.2. Objeto COM + agrupable con atributos de nombre seguro
US 1 !'. q i;s i n g S y s C 01 T 1 . P O f 1 (? c t. i o : ; C y s t. o ni . E n t e r. p n s e S e r v i c e s ;

i a s s e mb 1 y : A s s ni) j 1 y Y. e y F i l e i " k e y f i 1 e . s n k " ) ] [ a s s e mb ' y : A s s c.-nib 1 y Y e i s i o n ( " 1 . 0 . * " i ] [O b je c tP o o 1 in g (5, pub 1 i c c 1 ass 10i 1 : S e r v i cedComponent

Poo 1 eelC1 a s s
)

/
pi i b 1 i o Poo 1 edC 1 a s s

P o o 1 e d c: 1 a s s i' J

754

public

override true;

bool

CanBePoolcd( )

{
return

}
public override void Actvate))

I }
p ub 1 1 c o v e r n d e v o i d Deactivat e )

{ } t Puede exponer esta clase como una clase COIVH con solo unas cuantas her ra mientas de lnea de comando. En primer lugar, genere un nuevo par de claves para el nombre seguro del ensamblado con la herramienta de lnea de c omando estandar sn:
s11 - k ke y f i l e .snk

A continuacin, compile el codigo en un e ns ambl ado basado en DEL:


c sc /1 a iq o t :library List in q 3r 2 .c s

I ras generar el ensamblado, puede usar la herramienta r<: a s v es para regis t rar el ensambl ado con C'OM i :
yeqsvcs /appname :T ,is t .inq2 2App Listinq'-1 ) .d ! 1

T R U C O : La infraestructura de interoperabilidad NET/C O M + admite apli caciones COM+ basadas en la cach de ensamblados global. Si varios clien tes usan el cdigo, quizs quiera instalar su ensamblado en la cach de ensamblado global antes de registrarla con COM+. El argument o /appname para la herramienta t-asees especifica el n om bre de la aplicacin C O M + creada para al macenar las clases publicas encontra das en el ensamblado. Si cuando se ejecuta regsvcs ya existe una aplicacin C'OM4 con su nombre, las clases se agregan a la aplicacin preexistente La figura 3:v 1 muestra el expl orador COM t ejecutndose con el ensambl ado generado a partir del cdigo del listado 35.2 registrado con COM f E'oo 1 -d( 1a s s es detectado aut omt icamente por el proceso de registro y agregada a la aplicacin C'OM + Inicie el expl orador C O M + realizando los siguientes pasos: 1. Haga clic en el botn Inicio del Ex pl orador de Windows. Aparecera el men Inicio.

755

Servicios de componentes
yg* A r c h iv o A c c i n Ver V e n ta n a Ayuda

_ = lQ j x j

$ =
_ | -

s m >
F q'Jip.V '. ^ M l F1

c?

-cJ.

I
+

A l i .j I v

I 'j h t r ul P ijb li- 'h e r A j p k a h _I1 T r'l f.i f_ rrir*ri t *r*

appname Lsting28-2app

iQ F '.-.o if-d n .i-.


_ _ | F u rii'n E 'P lu r f- r i W
i' i

im + i n [ ie a d L e tte r O 'je u e L is te rn 'M t I Itilitip -; In F 'to rp v :; A p p lic a tio n s

I,' ^

IIS ' 11 u t O f F'rui >ry- P o n ie d A p p lir .itin I I . Ijtllitle -.. M '. 'T 'ig g ^ r A p f

..< 3M " .ofti/./aiP shadow '.opy F'tuvider __i


y r , 'd e i E n t r , A p p * S tc te h .jl

.. ,;.y '.-te iii A ppln..-ihi ir Utilidende-.. ME

_________________ ! J

b* V v 'p fiE v p rit--.A p p

zl

Figura 35.1. Explorador COM+ con un ensamblado .NET registrado

Escoja Program as>Herram ientas administrativas. A p a r ec e r n los iconos de las aplicaciones en el g rupo de p r ogr amas Herramientas admi

nistrativas
3. Seleccione Servicios de componentes. Aparecer el Explorador COM+.

Ea figura 35.2 muestra la hoja de propiedades de la clase PooledClas.s. Observe que la informacin de a grupaci n de objeto especificada en los atributos del listado 35 2 es detectada automt icamente por el proceso de registro y a g r e ga da a la aplicacin C OM + .

Cmo usar atributos para clases COM+


El atributo de agrupacin de objetos usado en el listado 35.2 solo es uno de los muchos atributos . NET que puede usar en sus clases CU. N E T Framework ad mi te \ ar i o s atributos que pueden usarse para configurar aspectos C O M + para sus clases CU. Todos los atributos N E T relativos a C O M + se incluy en en el espacio de nombres System. I'.nt.c-rpr i se S e r v i c e s . Las siguientes secciones d es criben mas atributos interesantes del serv icio ( OM +

N O T A : Para los atributos COM + del espacio de nombres System. EnterpriseServices, el valor predeterminado sin configurar hace referencia al valor que COM + asigna al atributo cuando el atributo no

756

aparece en el cdigo. Un valor predeterminado configurado hace referencia al valor asignado al atributo, si se asigna, pero omite su valor.

Propiedades de
G e n e ra i A c t iv a c io T r a n s a c c io n e s S im u lta n e id a d S e g u rid a d Avanzado

JZJ 2J

r**

H a b ilita r a g r u p a c i n d e o b je to s

T a m a o m n im o d e l g ru p o

T a m a o m xim o d e l g ru p o

T ie m p o d e e s p e ra p a ra la c r e a c i n |m s |

f~

H a b ilita r c o n s tr u c c i n d e o b ie lo s

C o n te x to d e a c tiv a c i n |V ! ' N o to rz a r el c o n te x to d e a c tiv a c i n El c o m p o n e n te a d m ite e v e n to s y e s ta d s tic a s H a b ilita r a c tiv a c i n p u n tu a l D e b e a c tiv a r s e e n el c o n te x to de l a u to r d e la lla m a d a D e b e a c tiv a r s e e n el c o n te x to p re d e te rm in a d o

M a rc a r el c o m p o n e n te c o rn o p r iv a d o p a ra la a p lic a c i n

A p lic ar

Figura 35.2. P g i n a d e la p r o p i e d a d d e cl a s e C O M + c o n i n f o r m a c i n d e a g r u p a c i n
de objetos

ApplicationAccessControl
El atributo App Licat ionAccessCont rol especifica si se puede confi g u ra r la seguridad de un ensamblado. Este atributo recibe un \ a l o r booleano que debe ser True si se permite la configuracin de s e g un d ad \ Falso en caso contrario. El valor predet ermi nado no configurado es Fu . - \ el \ a l o r predeter minado conf igur ado es True.

ApplicationActivation
El atributo Appl i cationActi vat ion es un atributo de m \ e l de en s am blado que especifica si se debe agregar la elase a una biblioteca o a una aplicacin de s e n i d o r C O M + . El atributo recibe como par met ro un tipo de enumeracin l lamado Act ivat ionOpt ion que admite los siguientes \al ores: Library. que especifica una aplicacin de biblioteca COM+Server. que especifica una aplicacin de scr\ idor COM * El valor predet ermi nado no configurado es Librar y .

757

ApplicationID
El atributo ApplicationID puede usarse par a especificar el GUI D que se va a asignar a la aplicacin C O M t creada para que contenga la clase C O M + . El GUI D se especifica usando su representacin de cadena, que se envia al co ns tr uc tor del atributo. El atributo ApplicationID debe aplicarse en el ni \el de ensamblado, como en el siguiente fr agmento de cdigo:
[dsscrnb 1 y :Ap p 1 ic dti onID (" {E 3 8 c 8 E 1 S - 4 8 6 E - 9 F 1 3 - FC 8 4 4 3 1 1 37 3 1 } " )
j u b 1 i r: cid s s My C 1 a s s

El atributo recibe una cadena como p ar amet ro que describe el GUI D de la aplicacin.

ApplicationName
El atributo Appl i c a t io n Ma me se utiliza par a especificar el nombre que se va a asignar a la aplicacin C O M t creada par a que contenga la clase C O M + . Se le debe propor ci onar el nombre del const ructor del atributo. Si se especifica este atributo en el codigo. no sera necesario usar el argument o /appnarr.e de la herrami ent a de linea de coman do reqsvcs. El atributo Appl :car ior Jane debe aplicarse en el nivel de ensamblado, como en el siguiente fr agment o de codigo:
f a .s y e n ) i y : A p p 1 c a t i - M i I J a m e i " M y r J a m e " ) ] pulic ' - .i a.s.s M yC lass

El atributo recibe como par amet ro una cadena que describe el nombre de la aplicacin \ su valor predeterminado es el nombre del ensambl ado para un \ a l o r predeterminado no configurado.

ApplicationQueuing
El atributo Appl i cat i o n p u c u m g se usa para especificar que la clase debe ser c on f ig u r a d a como un co mp o ne nt e en cola. El a tr i b u t o no admite parmetros. El atributo App ! i ; 11 io ngueu inq debe aplicarse en el nivel de ensambl ado, como en el siguiente fragment o de codigo:
j a s .v . '.-lab i y : A p p 1 i c a t . i - d i j u r u i n : ] pub 1 1
c

'.-1 a s s

My C l a s s

I El atributo no admite parmetros.

758

AutoCom pete
El atributo AutoOompl ete puede aplicarse a mtodos en una clase ( OM t Si la llamada de mtodo se hace en el mbi to de una transaccin \ la llamada de mtodo se completa con normalidad, las llamadas a mtodos marc ados como mtodos Aut oComp 1 o te van inmediatamente seguidas por una llamada de NET Framework a S e t Co m pi e te (). No es necesario realizar una llamada explcita a SotCon pl et.e ) par a los mt odos Au r .oC ornp i o t o . Si un mt odo Aut oCorr.pl etc ( ) inicia una excepcin, se invoca a C-^Abcrt ( > y la t ra n saccin es eliminada. El atributo AutoCornp oto debe apl icarse en el ni\el de mtodo, como en el siguiente fragment o de codigo:
pub 1 : .Cusa HyCLi.ss

I
l Aut . o C omp 1 e t e ]

pub 1 ii : MyMe thod (

El atributo A u t o C o m p l o t o no acepta parmetros. El \ a l o r por defecto para el \ a l o r predeterminado no configurado es I-'A 1 s e \ para el valor predeterminado conf igur ado es T r u e .

ComponentAccessControl
El atributo Cornponont Accs sCont ro a c t i \ a o d e sa c t i \a las c o m p r o b a ciones de s e gu n da d en las llamadas a instancias de clase. El atributo recibe como p ar met ro un \ a l o r booleano. que debe ser True si la c omproba ci on del i m e l de s e g un d ad de la llamada debe estar a c t a o Fa 1so en caso contrario. El atributo C o mp on en t A o c e s s C o n t r o 1 debe aplicarse en el nivel de cl a se. como en el siguiente fragment o de codigo.
[C o mp onenf A c c e s s C o 111 r o 1 ]
p u b i ir: r: 1 a s s M yClas s

I .

} El atributo C o m p o n e n t A c c e s s C o n t r o l no acepta parmetros. El valor por defecto para el valor predeterminado no configurado es Falso y para el valor predet ermi nado conf igur ado es True.

ConstructionEnabled
El atributo C o n s t r u c t i o n E n a b l e d permite la construccin de objetos C'OM + . El mecani smo de construccin de ob)ctos COM4 permite que se pueda

759

pas ar una cadena como cadena de constructor a las instancias de objetos con instancias. El atributo no especifica la cadena: en cambio, simplemente permite que se admita la construccin de objetos C O M+ . El atributo admite un valor booleano como parmetro, que debe ser True si la construccin de objetos C OM f debe estar activada para la clase y Fa 1se en caso contrario. Las clases de C# qu e a d m i t e n la c o n s t r u c c i n de o b j e t o s d e b e n i m p l e m e n t a r la i n t e r f a z 10b icnjf.Ccjnstruct. El mtodo Co ns tr uc t () de la mterfaz es invocado por C O M + para pasar la cadena de constructor al objeto. El atributo Construci'innEnablcd debe aplicarse en el nivel de clase, como en el siguiente fragment o de codigo:
( O o n .st :

uct
< :

; o n F . n a b 1 o el ]

p ubi ic

1 i s s My 0 1 a s s

El atributo Constructi o n E n a b l o d no admite parmetros. El valor por defecto del v alor predet ermi nado no conf igur ado es False y el del valor pre de terminado conf igur ado es T r u e .

JustlnTimeActivation
El atributo J u s t I n T i m e A o t i v a t i o n habilita o deshabilita la activacin justo a tiempo (JIT) de una clase. El atributo admite un valor booleano como parmetro, que debe ser T r u e si se va a permitir la activacin JIT en la clase y Fa ; s e en caso contrario. La activacin JIT siempre debe estar habilitada en los objetos que toman parte en transacciones. El atributo J u s t i nT i m e A c t i v a t i o n debe aplicarse en el nivel de clase, como en el siguiente fragment o de codigo:
[ Just: InTimeAct ivat : o i ij I ) u b 1 i< : cas s M y 0 1a s s

El atributo ;ust 7 n.T ineAc. iva t ion no admite parmetros. El v alor por defecto para el valor predet ermi nado 110 configurado es Falso y para el valor pre det ermi nad o conf igur ado es T r u e .

LoadBalancingSupported
El atributo LoaciBa ian> i n q S up p or te d habilita o deshabilita la c o m p a tibilidad con el equilibrio de cargas de una clase. El atributo admite un valor booleano como p ar met ro que debe ser True si la compatibilidad con el equili brio de cargas va a estar habilitada y Fa 1 se en caso contrario.

760

El atributo LoadBa 1 anc ingSuppor ted debe aplicarse en el ni\el de c l a se. como en el siguiente fr agment o de cdigo:
Le dilBd 1 anc i ngS u ppo rted] p ub 1 1 c c .1 a s s M y C 1 a . ss

{ ( El atributo LoaclBalancingSuppor ted no admite parmetros. El \ a l o r por defecto par a el \ a l o r predeterminado no configurado es Falso y para el valor predet ermi nado conf igur ado es T r u e .

SecurityRole
El atributo SecurityRole especifica una funcin de s egu nd ad. Este at ri buto puede aplicarse a una clase, un mtodo o un ens ambl ado completo. El c on s t ruct or recibe como ar gu me nt o una cadena que debe especificar el nombre de la funcin a la que deben pertenecer los miembros, como muest ra el siguiente fr ag mento de codigo.
[a s s emb ly: S e c u r i t y R o l e (" M y S e c u n t y R ole " ) J pu b l i c class M y C l a s s

Cmo procesar transacciones


La compatibilidad de transacciones de C O M + fue uno de los principales res ponsables de su popularidad. Gracias a la compatibilidad de transacciones, puede escribir codigo que realice mas de una tarea, pero la aplicacin lo ve como una sola unidad de trabajo, como actualizar una base de datos y borr ar un registro en otra tabla de una base de datos completamente distinta. Con las transacciones, puede gar ant izar que se va a aplicar un modelo de todo o nada en estas situacio nes. Si la eliminacin falla en la segunda base de datos, la actualizacin de la pri mera base de datos tambin es cancelada. Sin las transacciones, los datos podran no c ompar ars e correctamente y no podra escribir aplicaciones de nivel de empresa. Una de las primeras aplicacio nes de ejemplo en usar la compatibilidad de t ransacciones que publico Microsoft se llamo ExAir. ExAir es una compa a area ficticia. El concepto bsico tras la aplicacin es un agente de billetes que recibe reservas de vuelos. Cuando un cliente solicita un vuelo, tambin debe solicitar un tipo de comida, como carne, vegetariana o pasta. La parte de comida de la aplicacin intenta introducir los datos en una base de datos distinta de la base de datos con el diagrama de asientos de la compa a area. La base de datos diferente representa una t ransaccin dis-

761

tribuida a otra compaa, el proveedor de alimentos. Si el primer mtodo contiene codigo que introduce la peticin de billete en la base de datos de la linea aerea, y un segundo mtodo contiene codigo que intenta introducir datos en la base de datos del proveedor de alimentos. (,que ocurrir si no se encuentra la base de datos del proveedor de a li ment os '! La informacin original que contiene los det a lles del \ uelo se introducir en la base de datos de la compaa aerea, pero cuando los pasajeros aparezcan, no tendrn comida, porque la segunda parte de la t ra n saccin no se pudo realizar. Evidentemente, esto no es una situacin deseable para una aplicacin de empresa. Si el proveedor de alimentos no esta disponible, el billete no se introducir en la base de datos de la compa a aerea. Este probl e ma puede solucionarse fcilmente envolviendo las dos llamadas de mtodo en una transaccin.

N O T A : En el ejemplo Ex Air. a la compaa no le interesa dejar de reservar un billete slo porque el vnculo a la base de datos de su proveedor de alimentos no funciona. En esta situacin, la solucin podra ser usar algo como los com ponentes en cola o M icrosoft M essage Queue. Con los servi c io s M e ssa g e Q u eu e. que se in c lu y e n en el e s p a c io de n om b res System.Messaging, puede garantizar la peticin eventual de envo de comida envindola a una cola de mensajes en lugar de intentar escribir inmediatamente los datos en la base de datos remota. Con este tipo de arquitectura, la aplicacin siempre puede aceptar las peticiones de billetes V el proveedor slo tendr que extraer mensajes de la cola de mensajes cuando pueda procesar los pedidos de alimentos.

Propiedades ACID
Para que funcionen las transacciones, deben atenerse a las propiedades ACID ACID es el acroni mo de atomicidad, coherencia, aislamiento y permanenci a La tabla 35 2 describe las definiciones de las propiedades ACID.
Tabla 35.2. P r o p i e d a d e s A C I D

Propiedad
Atomicidad Coherencia Aislamiento

Descripcin
Todo el trabajo es atmico o sucede en una sola unidad de trabajo. Todo dato que se usa en la transaccin es abando nado en un estado consistente. Cada transaccin est aislada de las otras transac ciones, lo que permite que las transacciones pue-

762

Propiedad

Descripcin dan sobrescribir los datos de otros procesos, lo que mantiene la uniformidad.

Permanencia

Cuando se completa la transaccin, todos los da tos deben estar en un almacn permanente, como ! una base de datos. Si la transaccin falla, todos los datos usados en ella deben ser eliminados. La per manencia garantiza que los datos sobrevivan a acontecimientos imprevistos, como cortes de luz o huracanes.

Cmo escribir componentes de transacciones


El atributo T r a n s a c t i o n especifica un 11 i\el de compatibilidad con t r a n sacciones que debe estar disponible para este objeto. El atributo recibe como par met ro un valor de una enumeracin en el espacio de nombres yst.ern. l'Tit.ernr iseServi ces llamado Tr ansact. ronpt i on. que es c om p a t i ble con cualquiera de los siguientes valores: nisabled. que especifica que el objeto debe pas ar por alto cualquier transaccin en el contexto actual NotSupportcd. que especifica que el objeto debe crear el component e en un contexto sin una transaccin que lo controle Required. que especifica que el objeto debe compar tir una transaccin si \ a existe una o crear una nueva t ransaccin en caso de que sea necesario Requii esNew. que especifica que el objeto debe crear el componente con una nueva transaccin, independientemente del estado del actual co n texto S u p p o r t e d . que especifica que el objeto debe compart ir una transaccin si va existe una El atributo T r a n s a c t i o n debe aplicarse en el nivel de clase, como en el siguiente fragmento de codigo:
[T r diis a o t ion Transact i onOpt ion .Supp o r t ed i ] public c 1a s s M y C 1a s s

{ }

763

El atributo recibe un solo par met ro que nombra a un valor de la enumeracin

Transacti onOpti on y describe el nivel de transacci n que admite el diseo


de la clase. El atributo tambin puede usarse sin parmetros, como en el siguiente fragmento de codigo:
|Tra n . sa c t .i 011 ] pub J .1 c c 1a s s MyC 1 a s s

Si se especifica el atributo Transaction sin especificar un parmetro, el nivel de compatibilidad con el par met ro de la clase pasa a ser R e q u i r e d . El listado 35 3 muestra el codigo completo par a el contexto de E A i r . Exis ten dos mtodos \ cada uno accede a recursos diferentes. Como estn contenidos en una t ransaccin, queda gar an ti zad o que el procesami ent o del pedido tiene lu gar como una sola unidad de t rabajo; el proceso esta aislado de los otros posibles pedidos; los datos del pedido se dejan en un estado coherente; y una vez que el pedido esta consignado, per manecen en un almacn permanente.

Listado 35.3.
namespace

E j e m p l o de ba se de datos transaccional

Transactio n S u pport

{
u s 1 n g S y steni ; u s 111 g System. D ata. S q iC 1 1 e n t .; u s 1 n g S y s t e m .F.nterpr 1 seServi c e s ; [Transa c t .1 on !T r a nsact. .1 onOpt 1 011 .Required) ] p ub J ic el a s s F ,y.A1 rM a 111 : Serv c e d C omp o n e n t

{
p u b 11 o v o 1 d P r o c e s s !)

{
/* 1 1ama a mtodos T 1 c ket * / para agregar informacin de Food y de

AddFood p r o c e s s 1 = new A d d F o o d (); AddAi rl m e process 2 = new A d d A i r l m e ( ); p r o c e s s 1 .A d d ! ; proces.s2 .Add () ;

I }
[T ra n s a c t .ion (T i a nsact 1 onOpt ion .Supported) ] [A uto Co m p 1e t o ] publ i r : class AddFood : Serv 1 cedComponent

{
public voi d Add . 1

764

SQLConnection cnn = new SQLConnect.i on (" FoodSuppl erC onn e ct ion " ) ; SQLCommand cmcl = new SQLCommand i ' ; cnn .O per. ( ) ; cmd .Ac ti veConnec1 1 on = cnn; c m d .CommandText = // Introduce una instruccin 0 m d .E xe c uteNonQuery ( ); cnn.Close () ;

en C P :

I }
[Transa ction TransactionOption.Supported j ] [AutoComplete] pub Lie elass AddAirline : ServcedComponcit

{
p u b 1 ic voi d Add ()

{
SQLConnectron cnn - new S QLConnection ("Ai r 1i n e C o n n e c t r o n " ; SQLCommand cmd = new SQLCommand ( ); c n n .O p e n (); c m d .ActiveConnection - cnn; cmd .CommandText = "" // Introduce una c m d .Execut eNonQue r y () ; c n n . C l o s e ();

m s t i ucci on en I > B

} 1 }

Cmo acceder al contexto de objetos


El espacio de nombres S y s t e m . E n t e r p r i s e S e r v i c . e s incluye una cl a se l lamada C o n t e x t l J t i 1 que puede ser utilizada por clases C# para acceder a un contexto de tiempo de ejecucin C O M + de un objeto. En Visual Basic 6. se a c ce d e al c o n t e x t o de o bj et o s del c o m p o n e n t e en uso m ed i a n t e el objeto Ob j e c t C o n t e x t . como mues tra el siguiente codigo:
Drm ctx as ObjectContext ctx - GetObjectContext

La clase C o n t e x t U t i l contiene varias propi edades y mtodos que conce den a los mo c a d o r e s el acceso a i nformacin de estado de contexto COM+. Todos los mtodos y propiedades de la clase son estticos, lo que significa que se puede acceder a los mi embros directamente desde la clase C o n t e x t u t i 1 sin crear un objeto de la clase. La tabla 35.3 describe las propiedades de la clase C o n t e x t U t i l y la tabla 35.4 describe los mtodos de la clase C o n t e x t U t i l . El cdigo del listado 35.4 implementa un componente C O M + transaccional que implementa un mtodo publico llamado D o W o r k ( ) . El mtodo D o W o r k ( )

765

comprueba la propiedad 1 s C a i l e r I n P . o l e ( ) para determinar la funcin COM + del moc a dor . Si la funcin del m o c a d o r es C 1ientRole. entonces la t ra ns a c cin del objeto se realiza con una l lamada a S e t C o m p l e t e ( ) . Si la funcin del invocado!' es distinta de la de C i i e n t R o l e . entonces la transaccin del objeto es cancelada con una llamada a SetAbort ().
Tabla 35.3. Propiedades de la clase ContextUtil

Propiedad
Activityld Applicationld Applicationlnstanceld Contextld DeactivateOnReturn IsInT ransaction IsSecurityEnabled MyT ransactionVote Partition Id T ransaction T ransactionld

Descripcin
i

Obtiene un identificador GUID que representa la actividad que contiene el componente Obtiene un identificador GUID para la aplicacin actual Obtiene un identificador GUID para la instancia de aplicacin actual Obtiene un identificador GUID para el contexto ac tual Obtiene o establece el bit hecho en el contexto de COM+ Obtiene un valor que indica si el contexto actual es transaccional Obtiene un valor que indica si la seguridad basada en funciones est activa en el contexto actual Obtiene o establece el bit consistente en el contex to de COM+ Obtiene un identificador GUID para la particin ac tual Obtiene un objeto que describe la transaccin de DTC actual de COM+ Obtiene el identificador GUID de la transaccin de DTC actual de COM+.
Tabla 35.4. Propiedades de la clase ContextUtil

Propiedad
DisableCommit EnableCommit

Descripcin
1

Asigna a los bits consistente y hecho el valor en el contexto de COM+.

Fa] se

Asigna al bit consistente el v a l o r T r u e , y al bit hecgi el v a l o r F a i . s e , en el contexto de COM+

766

Propiedad GetNamedProperty IsCallerlnRole SetAbort SetComplete

Descripcin Devuelve una propiedad con nombre desde el con texto COM+ Determina si el llamador se incluye en la funcin especificada Asigna al bit consistente el valor f . l s -, y al bit hecho el valor T r u e , en el contexto de COM+ Asigna a los bits consistente y hecho el valor en el contexto de COM+.
Tr >

Listado 35.4. Cmo acceder al contexto COM+ mediante la clase ContextUtil


i;s i r .q
u.s i r . g
-

ys

em . R e t i c - o t i c,n ;
r vict-s ;

' y s t e n i . K n t e r p r j. s e e

i a s s e mh l y : A s s f mb 1 y K o y F i 1 o ( " k e y f i 1 <- . s r. k "

'a s s emb Jy :As s emb 1y A- i s is>n i" 1 .i j .


i - ' h : e f t p o o 1 : ur j ( 5 , [ T r u r. s a r i un 10 ) 1

iT

i a n s a c t i o r . ' . p t

: cui . l - ' r - qm t - u

[ : i e u i r i t y p o 1 e i " c: 1 i e n t F o t-- "

publ i r

Poc 1 r l e 1 a s s u

Po ole r 1 C 1 a s s (;

( }
pub 1 e ove r ride b o o i CanBePooled i

I
returr. t ru;

p u b i :r : ove r r id e

voi d Actvate i

pi ; b 1 ic

ov e r r i d e

v o id

I> e ae t i v at r u

I }
pu, b 1i r

vo i d I )o Wo r k i )
IsIn R o le ;

)
bool

767

IsTnRole - Co ntextUti1.I s C al le rI nR ol e("ClientRole") ; ii ( Is 1n R o l e -- truel


C oiit o o Js e
C

t U t: i. 1 . S e t C omp l e t e () ; t U t i 1 . S e t : A):: o r t i ) ;

ont e

Resum en
La exposicin de una clase C# como si fuera una aplicacin C O M + no supone ningn esfuerzo v resulta mas sencillo que implementar la misma funcionalidad usando versiones anteriores de Visual Studio 6.0. Las aplicaciones de C O M i escritas en Visual C + + 6.0 necesitaban mucho mas codigo para realizar las mi s mas tareas v algunas caractersticas de C O M + (como la agrupacin de objetos) ni siquiera estaban disponibles en Visual Basic 6.0. El desarrollo de componentes C OM f mediante C# implica cuatro sencillos conceptos: Derivar la clase de ServicedComponent Agregar atributos para describir las configuraciones de la aplicacin Usar la herramienta regsvcs para construir una aplicacin C O M 4 para las clases publicas Invocar a mtodos y propiedades en la clase ContextUti 1 para acceder al contexto C O M 4 en el tiempo de ejecucin. Microsoft ofrecio pistas sobre este modelo de programacin C O M + hasta 1W7. Entonces, describieron un modelo basa do en pr ogr amaci n con atributos, en el que los componentes C O M deberan ser descritos con at ri but os y el tiempo de ejecucin se encargar a de detalles como los generadores de clases y el clculo de referencias al estilo iLJnknown. Ahora es evidente que el modelo N E T de d e s a rrollo de componentes C O M i es la culminacin de esa visin original.

768

ETn Cmo trabajar con los servicios remotos de .NET


N E T Framework proporciona v an o s mecanismos que le permiten escribir apli caciones que no existen en el mismo dominio de aplicacin, procesos de servidor o equipo. Basndose en los requisitos de la aplicacin, como la ca paci dad de los servidores que no sea de N E T para acceder a sus datos, puede escoger cualquiera de los diferentes tipos de mtodos de comuni caci n de objetos. En este capitulo, estudiaremos el entorno remoto NET. Al usar un entorno remoto, puede recodificar objetos y llamadas de mtodos a lo largo de limites de procesos y p as ar datos entre aplicaciones eficazmente. Anteriormente aprendimos que los servicios Web de A S P . N E T y X M L tambin eran excelentes medios para p as a r objetos y datos entre lmites de procesos, pero dependiendo de la infraestructura de la aplicacin, esos servicios podan no ser la mejor opcin disponible. El entorno remoto se ocupa de los aspectos que no cubran estos servicios. En este captulo, aprender a implementar entornos remotos, a crear los objetos cliente y servidor de un entor no remoto y a pas ar datos usando el entorno remoto a travs de limites de procesos.

Introduccin al entorno remoto


El entorno remoto N E T permite a las aplicaciones comunicarse entre objetos que estn en servidores diferentes, procesos diferentes o dominios de aplicacin

771

diferentes. Antes de la llegada de N E T Framework. se podan p as ar objetos a travs de lmites de procesos mediante C O M o D C O M. D C O M funcionaba bien, pero tena limitaciones, como los tipos de datos que podan p as ars e y el contexto de seguridad p as ad o entre el l lamador cliente y la activacin del servidor. Ade ms. estaba bas ad o en C O M. lo que significaba que aunque poda comuni carse a travs de lmites de equipo, todos los equipos deban estar ejecutando un sistema operativo de Microsoft. Esto no era una gran limitacin, pero limitaba nuestras opciones respecto a lo que podamos hacer con la infraest ruct ura existente. En N ET . el entorno remoto se ocupa de estos aspectos y mejora lo que DC O M ofreca como un mtodo viable p ar a establecer una comunicacin remota entre objetos. El entorno remoto permite implement ar un servidor o una aplicacin de servi dor v una aplicacin cliente. En el serv idor o el cliente, la aplicacin puede ser cualquiera de las plantillas de aplicacin N E T disponibles, incluyendo aplicacio nes de consola, aplicaciones de serv icios Wi ndows, aplicaciones A S P . N E T . apl i caciones WindovvsForms y aplicaciones IIS. En el servidor, se configura mediante programaci n (o se emplea un archivo de configuracin para especificarlo) el tipo de activacin que permitirn los clientes. Los clientes pueden u sar uno de los varios tipos de mtodos de activacin, incluyendo Singleton y SingleCall. como se expl icar en la seccin "Cmo acti var el objeto remoto." ms tarde en este mismo captulo. Es en este punt o donde se especifica el canal y el puerto a travs de los cuales se comuni ca el objeto y el for mato que tendrn los datos c uando pasen entre el servidor y el cliente. Aprender a implement ar canales y puertos poco despus. El for mato de los datos es importante, segn el diseo del sistema; puede usar datos binarios. S O AP o un formato personalizado, para recodificar los datos. Tr as especificar el canal, el puerto y el formato, segn el tipo de servidor remoto que est exponiendo, debe det er minar cmo exponer los met adatos a los clientes. Puede hacerlo de varias maneras, como permitiendo al invocador d es car ga r el ens ambl ad o o haciendo que la fuente est disponible para el invocador. En cualqui era de los dos casos, el cliente debe saber qu objeto est creando, de modo que los metadatos en varias formas deben estar disponibles para el invo cador. C uando el serv idor est configurado y creado adecuadamente, puede escri bir el cliente. En el cliente, todo lo que debe hacer es crear una instancia del objeto en el canal y puerto especificados que esperen peticiones del servidor. Puede l ograr esto mediante pro gr amaci n o mediante un archivo de configuracin. En este punto, las llamadas de mtodo no son diferentes de cualqui er otro objeto de una aplicacin N E T que se pueda usar. Tra s crear objetos, llame a los mtodos, est abl ezca y recupere propiedades y desencadene eventos igual que hara con un objeto que no est usand o el entorno remoto. Estos pueden parecer muchos pasos, pero en realidad es muy sencillo una vez que lo ha hecho una v ez Puede resumir todo el proceso en las siguientes tareas, esquemat izadas en la figura 36.1.

772

1. 2.

Especifique los canales y puertos que recodifican los objetos entre el servi dor y el cliente. Use formateadores (explicados ms adelante en este captulo) para especi ficar el formato en el que los datos son serializados y deserializados entre el servidor y el cliente. Determine cmo se activ an los objetos del servidor \ cuanto dura la activ a cin.

3.

Dominio de aplicacin de cliente

Figura 36.1. Vista del entorno remoto

NET

En las siguientes secciones, aprender a crear la aplicacin a n f i t no n a en un contexto remoto, incluyendo los detalles especficos de los formateadores. c a n a les y puertos y cmo se puede activar el servidor. Despus de const rui r el servi dor. apr ender a consumi r el objeto remoto de una aplicacin cliente.

Cmo crear un ensamblado de servidor remoto


Para empezar con la aplicacin remota, necesita crear un ensambl ado que contenga las llamadas de mtodo reales que us ar a la aplicacin anfit nona. Una v ez creado el ensamblado, cree la aplicacin a n f i t no n a que acepte peticiones de los mtodos del ens ambl ado por parte de los clientes. En los siguientes pasos, cr ear el ens ambl ado que implemcnta los mtodos que se van a llamar: l. C r e e u n a n u e v a a p l i c a c i n C# de B i b l i o t e c a de c l a s e s y l l m e l a S e r v i d o r O b j e c t . Para hacerlo ms sencillo, yo cre un directorio en

773

mi unidad C llamado cSharpRemoting y le agregue tres subcarpet as llamadas Servidor. ServidorOb j ect y Client. Ya se imaginara lo que se pretende. La aplicacin de biblioteca de clases ServidorOb ject debe ser creada en el directorio cSharpRemot ing\ServidorOb j ect. Esto hace que le sea mas sencillo ej ecutar las aplicaciones de consola que crear posteriormente. 2. Tras crear la aplicacin de biblioteca de clases ServidorOb j ect. agr e gue un mtodo publico que reciba un parmetro, llamado customer ID y devuelva el nombre del cliente de la base de datos Northwind en el SQL Server basado en el customer ID que se ha pasado. La clase completa par a la aplicacin ServidorObject deberia tener un aspecto parecido al listado 36.1.
Listado 36.1. Cmo crear la aplicacin ServidorObject us ing using using Syst.em; System.D ata; System.Da t a .S qlClient ; ServidorObject class Classl: MarshalByRefObject

namespace

{
public

(
public public string thisCustomer;

C 1ass 1 ( ) has been activated") ;

{
Console . W n t e L m e ("ServidorObject

}
public string ReturnName(string customerlD)

(
// Crea una conexion, enva al objeto al SQL

string cnStr = "Initial Cat alog = N o r th wi nd ;Data " + "S our ce = 1 oca 1s e r v i d o r ;Integrated S e cur 1 1y-S S P I ;"; SqlConnection en = new SqlConnection(cnStr) ;

string strSQL = ("Select CompanyName from Customers " + " where CustomerlD = '" + customerlD + "'"); SqlCommand cmd = en .CreateCoinmand () ; = strSQL;

c m d .CommandText e n .Open () ; SqlDataReader

rdr

= c m d .ExecuteReader

774

(CoinmandBehavior .CloseConnection
v/h i 1c (ra r .Re a c i !i ' idr .Cet . V .t r inq 1 :

;;

t h i s C ustome r -

1
C o n s o l e .Wr 1 1 e L i ne ;t h is l i s to i i i ei * " was returned to the cliont " . ; rcturr. ch i s C us t orne r ;

El codigo anterior realiza una simple peticin a SQL Serxer para tomar el c a mp o C o m p a n y N o r n e en la base de datos Cas- * o r e r s basada en el parmet ro c u s : . o n e r 1 I.), que se pasa al mtodo. C'omo puede ver. este cdigo no es dife rente de cualquier otra biblioteca de clases que hava creado en Cf. El siguiente paso es crear la aplicacin servidor que atiende a las peticiones de esta clase de biblioteca por parte del cliente.

Cmo crear un servidor remoto


Para crear la aplicacin que distribuir el ensamblado s c*r v i d o r O b i c ::r.. que es donde realmente empezara a usar algunas de las caractersticas remotas creadas en el listado 36.1. debe crear una aplicacin de consola llamada S e r v i d o r en el directorio C : \ c S h a r p R e m o t i n q \ S e r v i d o r . Esta aplicacin a n f it n on a es el autentico servidor remoto que usa las caractersticas del espacio de nombres System. Runtime .Remotinq. Antes de empezar a codificar, deben describirse varias caractersticas c l a \ e del entorno remoto. El espacio de nombres que contiene la funcionalidad remota es System. Runtime .Remotinq. c u \ a s clases se describen el la tabla 36.1.

Tabla 36.1.

Clases de System. Runt ime .Re mot: mej

Clase
ActivatedClientTypeEntry

Descripcin
Almacena valores de un tipo de objeto regis trado en el cliente como un tipo que puede activarse en el servidor Almacena valores de un tipo de objeto regis trado en el servicio como un tipo que puede activarse cuando se solicita desde un cliente

ActivatedServiceTypeEntry

775

Clase ObjectHandle

Descripcin Ajusta referencias de objetos calculadas por valor, de este modo, se pueden devolver a travs de un direccionamiento indirecto Almacena toda la informacin relevante ne cesaria para generar un proxy y establecer comunicacin con un objeto remoto Proporciona varios mtodos estticos para configurar la infraestructura remota Excepcin que se inicia cuando se produce algn tipo de error durante la interaccin re mota Proporciona varios mtodos para utilizar y publicar servidores proxy y objetos remotos. No se puede heredar esta clase Excepcin que se inicia cuando no se puede obtener acceso al servidor o al cliente en el perodo de tiempo previamente especificado Excepcin que se inicia para comunicar erro res al cliente cuando ste se conecta a apli caciones distintas de .NET Framework que no pueden iniciar excepciones Proporciona varios mtodos para utilizar y publicar objetos remotos en formato SOAP Implementa una clase base que contiene la informacin de configuracin utilizada para activar una instancia de un tipo remoto Contiene valores de un tipo de objeto regis trado en el cliente como objeto de tipo cono cido (llamada nica o singleton) Contiene valores de un tipo de objeto regis trado en el servicio como objeto de tipo co nocido (llamada nica o singleton)

ObjRef

RemotingConfiguration RemotingException

RemotingServices

RemotingTimeoutException

ServerException

SoapServices TypeEntry

WelIKnownClientTypeEntry

WelIKnownServiceTypeEntry

Aunque no use todas estas clases cuando escriba aplicaciones remotas, varias de estas clases son ext remadament e importantes par a implcmentar una infraes tructura remota; es decir, la clase Ob j Ref . la clase Remo t ingConf igurat i on. la clase RemotingServices y la enumeracin We 1IKnownObjectMode. Aprender ms de cada una de ellas ms tarde en esta mi sma seccin mientras escribe el codigo de su aplicacin anfitriona.

776

Para empezar a escribir la aplicacin anfitriona. debe comprender lo que la infraestructura remota necesita para funcionar Para recordarle los pasos n ecesa rios par a crear la aplicacin anfitriona. revise los siguientes pasos reseados con anterioridad: 1. 2. 3. Especifique los canales y puertos que recodifican los objetos entre el servi dor y el cliente. Use formateadores par a especificar el formato en el que los datos son s e a li z ad os y d es en al i za do s entre el servidor y el cliente. Determine cmo se activan los objetos del servidor \ cunto dura la activ a cin.

Las siguientes secciones estudian cada uno de estos pasos.

Cmo especificar canales y puertos


En la i nfraestructura remota, los canales procesan el t ransporte de mensajes o datos entre los objetos cliente y servidor. Recuerde lo que esta sucediendo real mente cuando est usando objetos remotos: est cr uzando un limite, como un dominio de aplicacin, un proceso de servidor o un equipo fsico. El canal espec fico que propor ci ona controla todos los detalles subyacentes de trasl adar los d a tos a y desde los objetos remotos; simplemente especifique un tipo de canal y le har n todo el t r ab a jo sucio. La clase System. Ru n t i m e .Remoting. Channels proporci ona las implemcntaciones par a crear los canales que sern usados en el servidor remoto. C uando registra un canal en su aplicacin, debe asegurarse de que se registra antes de intentar acceder a los objetos remotos Si no registra correctamente los canales se producir un error. Si otra aplicacin esta es cuchando en el canal al que este intentando escuchar, se produce un error y su aplicacin anfitriona no se cargar. Debe saber que canales se estn usando y que canal debe usar su aplicacin, basndose en las solicitudes del cliente. Tras decla r a r u n a i n s t a n c i a del t i p o de c a n a l q u e va a u s a r , l l a m e al m t o d o RegisterChannel ( ) de la clase Channel Servi ces. que registra el c a nal para su uso. La tabla 36.2 describe los mtodos de la clase ChannelServices disponibles.
Tabla 36.2. Mtodos de la clase ChannelServices

Mtodo
AsyncDispatchMessage

Descripcin
De forma asincrnica, enva el mensaje especificado a las cadenas del servidor, en funcin de la direccin URI incrustada en el mensaje

777

Mtodo CreateServerChannelSinkChain DispatchMessage GetChannel GetChannelSinkProperties GetUrlsForObject

Descripcin Crea una cadena de receptores de canal para el canal especificado Enva las llamadas remotas de entrada Devuelve un canal registrado con el nom bre especificado Devuelve una iDictionary de propie dades para un proxy determinado Devuelve una matriz de todas las direc ciones URL que pueden utilizarse para alcanzar el objeto especificado Registra un canal con los servicios de canal De forma asincrnica, enva el mensaje de entrada a las cadenas del servidor, en funcin de la direccin URI incrustada en el mensaje Anula el registro de un canal determina do de la lista de canales registrados

RegisterChannel SyncDispatchMessage

UnregisterChannel

En esta tabla no aparece una propiedad de la clase Channel Services llamada RegisteredChannels. que obtiene o asigna los canales registrados de la actual instancia de objetos. El siguiente fragmento de codigo crea y registra un canal T C P y otro H T T P en los puertos especficos us ando el mtodo RegisterChannel de la clase

ChannelServices:
TcpChannel chanl = new Tc pChanne1(8085); Channel Servic es .Regist erCha-nnel (chanl) ; HttpChannel chan2 - new H ttpChanne1 (8 08 ) ; Channel.Services.RegisterChannel (chan2) ;

Cuand o crea un canal, tambin especifica un tipo de for mateador par a el c a nal. Las siguientes secciones describen los tipos de formateadores disponibles.

Cmo especificar un formato de canal


Al mismo tiempo que crea un canal, tambin especifica un formato para el tipo de canal escogido. En el espacio de nombres System. Runtime .Remot i ng . Channels hay dos formateadores predeterminados disponibles: el canal T C P y el canal H T T P

778

Espacio de nombres System.Runtime.Remoting.Channels.Tcp


El espacio de nombres System. Runtime .Remot i n g .C h a n n e Is .T c p contiene canales que usan el protocolo T C P par a t rans por tar datos entre objetos remotos. La codificacin predeterminada par a TC P es la codificacin binaria, lo que hace que sea un modo eficaz de p a sa r datos entre objetos remotos. Los datos binarios siempre o cupan menos espacio que los datos X M L equivalentes pasados mediante S OAP en un canal H T T P La d esventaja de usar el protocolo TC P es que es un formato propietario, de modo que solo funciona en si stemas que c o m prenden este tipo de formato. Para que el objeto remoto sea ms accesible debe usar el canal H T T P para codificar, ya que estara pasando datos en el protocolo SOAP. La tabla 36.3 resume las clases disponibles en el espacio de nombres

S y s t e m . R u n t i m e .R e m o t i n g .C h a n n e 1s .Tcp. Tabla 36.3.


Espacio de nombres S yste m .Runtime R em oting.C hannels .Tcp

Clase
TcpChannel

Descripcin
Proporciona una implementacin de un canal emi sor-receptor que utiliza el protocolo TCP para trans mitir mensajes. Esta clase es una combinacin de la clase TcpCIientChannel y la Clase T cp S er verChannel, lo que permite la comunicacin en ambos sentidos a travs de TCP. Proporciona una implementacin de un canal de cliente que utiliza el protocolo TCP para transmitir mensajes. Proporciona una implementacin de un canal de servidor que utiliza el protocolo TCP para transmi tir mensajes.

TcpCIientChannel

TcpServerChannel

Espacio de nombres System.Runtime.Remoting.Channels.Http


El espacio de nombres Sy stem .Runt me . emot ing .Chan ne 1 s .Ht tp contiene canales que usan el protocolo H T T P para t ranspor tar datos entre objetos remotos. La codificacin predeterminada para el protocolo H T T P es SOAP. lo que le convierte en un modo verstil de p as ar datos entre objetos remotos. La tabla 36.4 resume las clases disponibles en el espacio de nombres System. R u n t im e .R e m o t i n g .C h a n n e l s .Ht.tp. Hasta aqu, puede agr egar los espacios de nombres correctos y crear codigo para registrar un canal H T T P \ un canal T C P para la aplicacin anftnona. El listado 36.2 muest ra como la aplicacin a n f it n on a debe ocuparse de que se regis tren los canales.

779

Tabla 36.4. Espacio de nombres S yste m .R u n tim e .R e m o tin g .C h a nne ls.Http

HttpChannel

Proporciona una implementacin de un ca nal emisor-receptor que utiliza el protocolo HTTP para transmitir mensajes. Esta clase es una combinacin de las clases Http ClientChannel HttpServerChannel , lo que permite la comunicacin en ambos sen tidos a travs de HTTP. Proporciona una implementacin de un ca nal de cliente que utiliza el protocolo HTTP para transmitir mensajes. Implementa un controlador ASP.NET que enva solicitudes al canal HTTP remoto. Inicializa nuevas instancias de la clase
HttpRemotingHandler.

HttpCIientChannel

HttpRemotingHandler HttpRemotingHandlerFactory HttpServerChannel

Proporciona una implementacin de un ca nal de servidor que utiliza el protocolo HTTP para transmitir mensajes.

Listado 36.2. C m o registrar canales usmg using using u sing using System; Syst em .R un t me .Remot i n g ; Sy st em .R un t me .Remot i n g .Chan ne 1s ; S y s t e m . R un t me .Remot i n g .Channe i s .T c p ; Sy s t e m .R un t me .Remot ing.Channels.Http; Client

namespace

{
/ / / <summa ry > /// Descripcin resumida de Classl. /// ^/summary> class RemotingC1ient

{
[S T A T h r e a d ] static void M a i n (s t r i n g [ ]

args)

{
TcpChannel chanl = new TcpChanne1 (8 085 ) ; C h a n n e l S e r v i c e s .R e g i s t e rC ha nn e1 (chanl) ; HttpChannel chan2 = new HttpChanne1 (808 6) ; Channel S e r v i c e s .Regist e rCh an ne 1 (c h a n 2 ) ;

780

NOTA: No necesita usar los canales HTTP y TCP en la aplicacin anfitriona. Si est permitiendo a los clientes que llamen en los dos tipos de canales, puede registrar los dos tipos de canales; sin embargo, por lo gene ral, usar un formateador, TCP o HTTP, basado en el tipo de los clientes que estn accediendo al objeto remoto.

Cmo activar el objeto remoto


Para hos pedar el objeto remoto solo queda registrar el ens amb la do con el entorno remoto. En la aplicacin anfitriona. antes de poder activar el ensambl ado que contiene los mtodos, debe agr eg ar una referencia al ensamblado. Ha ga clic con el botn derecho del ratn en el objeto Referenees en el Explorador de soluciones, lo que hace que a p a r ez c a el cua dro de dilogo Agregar referencia. En la a p l i c a c i n q ue e s t a m o s e s c r i b i e n d o , d e b e r b u s c a r el d i r e c t o r i o C : \ c S h a r p R e m o t i n g \ S e r v i d o r O b j ec t y a g r e g a r el e n s a m b l a d o ServidorOb j e c t .dll a la aplicacin. Tra s hacerlo, puede agr egar el e s p a cio de nombres ServidorOb j ect a su archivo de clase usando la instruccin using, como mues tra el siguiente fragmento:
using usmg usmg using usmg usmg System; System. Runtime .Remoting; System. Runtime .Remoting .Channels; System.Runt i m e .Remoting.Channels.Http; System. Runt ime .Remoting .Channels .Tcp; ServidorOb j ect ;

Tras agr egar una referencia al ensambl ado remoto creado anteriormente, p u e de ag regar el cdigo que registra el objeto mediante el entorno remoto. Hay dos maner as de hacerlo: Use el mtodo RegisterWellKnownServiceType ( ) de la clase RemotingConf igurat ion para pasar el tipo de objeto que est creando, el URI del objeto y el modo de activacin del objeto. Use el mt odo Conf igure ( ) de la clase RemotingConf igurat ion p ar a p as ar un archivo de configuracin con los detalles de activacin del objeto. Ca da mtodo de activacin funciona igual, pero al macenar los detalles de activacin en un archivo de configuracin le otorgan ms flexibilidad si cua lqui e ra de los detalles de activacin cambia, como el numero de puerto del canal que est usando. Ya sopesaremos las ventajas y desventajas de ambos tipos de activa-

781

cion. pero antes examine los mtodos y propiedades de la clase Remo ti ngConf igurat ion disponibles, descritos en la tabla 36.5 y en la tabla 36.6. respectivamente. Ademas de los mtodos de activacin descritos anteriormente, puede usar muchos mtodos y propiedades muy prcticos de esta clase par a d es cubrir informacin en tiempo de ejecucin sobre los objetos que est ejecutando.
Tabla 36.5. Mtodos de la clase RemotingConfiguration

M to d o

D e sc r ip c i n

Configure

Lee el archivo de configuracin y configura la infraestructura remo ta. Recupera una matriz de tipos de ob jetos registrados en el cliente como tipos que se activarn de forma re mota. Recupera una matriz de tipos de ob jetos registrados en el servicio que se pueden activar cuando lo solici ta un cliente. Recupera una matriz de tipos de ob jetos registrados en el cliente como tipos conocidos. Recupera una matriz de tipos de objetos registrados en el servicio como tipos conocidos. Obtiene el tipo de la instancia ac tual. Devuelve un valor booleano que in dica si el tipo especificado est au torizado para ser cliente activado. Sobrecargado. Comprueba si el tipo de objeto especificado se registra como tipo de cliente activado de forma remota. Sobrecargado. Comprueba si el tipo de objeto especificado est regis trado como tipo de cliente conoci do. Sobrecargado. Registra un tipo de objeto en el cliente como un tipo

GetRegisteredActivatedClientTypes

GetRegisteredActivatedServiceTypes

GetRegisteredWelIKnownClientTypes

GetRegisteredWelIKnownServiceTypes

GetType (heredado de Object) IsActivationAllowed

IsRemotelyActivatedClientType

IsWelIKnownClientType

RegisterActivatedClientType

782

Mtodo

Descripcin

que se puede activar en el servi- ; dor. RegisterActivatedServiceType Sobrecargado. Registra un tipo de objeto en el servicio como un tipo que se puede activar a peticin del cliente. Sobrecargado. Registra un tipo de objeto registrado en el cliente como objeto de tipo conocido (llamada nica o singleton). Sobrecargado. Registra un tipo de objeto en el servicio como objeto de tipo conocido (llamada nica o singleton).

RegisterWelIKnownClientType

RegisterWelIKnownServiceType

Tabla 36.6. P ropiedades de la clase R e m o t i n g C o n i g u r a t i o n

P r o p ie d a d

D e sc rip ci n

Applicationld ApplicationName Processld

Obtiene el ID de la aplicacin que se ejecuta ac tualmente Obtiene o establece el nombre de una aplicacin remota Obtiene el ID del proceso que se ejecuta actual mente

Cmo registrar objetos con RegisterWelIKnownServiceType


P a r a r e g i s t r a r un o b j e t o con el m t o d o R e g i s t o r W e l I K n o w n Servi ceType ( ) de la clase RemotingConfi guration. slo tiene que pa sa r el nombre de la clase, que es ServidorObject .Classl; el URI del objeto remoto, que es ReturnName: y el tipo de modo en el que el objeto ser creado, que en este caso es SingleCall. Mas adelante estudiaremos la e nume racin W e l l K n o w n O b j ectMode. El listado 36.3 compl et a la apl icacin anfitriona usando el mtodo RegisterWelIKnownServiceType.
Listado 36.3. Cmo usar R egisterW elIKnownServiceType

using S y s t e m ; us m g System.Runtme.Remot ing ; using System.Runtime.Remot ing.Channeis;

783

using u sin g u sing

S y s t e m . R u n t i m e .R e m o t i n g .C h a n n e l s .Http; S y s t e m .R u n t i m e .Remot ing .Channels .T c p ; ServidorObject;


S ervid o r

namespace

{
/ / / / / / / / / cla ss <summary> D e sc rip c i n < ' /summa ry'C1 as s 1 resum id a de C la ssl.

/// <summary> /// El principal punto de entrada a la aplicacin. // / "/ s umma ry > [STAThread] static void Main(string[ ] args)

{
TcpChannel chanl - new TcpChanne 1 (8 0 8 5 ) ;

.RegisterChanne 1 (chanl);
RemotingConfiguration.RegisterWellKnownServiceType( typeof (Se rvi dor Obj ect .Classl) , "R e t u r n N a m e " , We 11 K n o w n Ob ] cc t M o d e .S m g l e C a l l ) ; C o n s o l e . W r i t e L i n e ("Press C o n s o l e . R e a d L i n e () ; any key to exit") ;

C omo la aplicacin anfitriona es una aplicacin de consola, agregue la ins truccin Consol .ReadLine al final par a que la ventana de la consola p e r manez ca abierta mientras los objetos estn usando el objeto remoto. La duracin del canal es la cantidad de tiempo que la v entana permanece abierta Tras cerrar la ventana de consola, el canal se destruye y termina la concesin de ese canal en par ti cular en el entorno remoto. La e numer aci n W e 11KnownObjectMode contiene dos mi embros que d e finen como se crean los objetos. Si WellKnownOb j ectMode es SingleCali. cada peticin de un cliente es atendida por una nueva instancia de objeto. Lsto puede representarse mediante el siguiente pseudo-codigo:
Cree ob j et o X

Llame al mtodo del objeto X Devuelva datos al llamador

784

De s t m y a R eco gid a

el de

ob j e t o X elem entos

no

u tiliz a d o s

Si WellKnownOb j ectModc es S m q ] eton. eada peticin de un cliente es atendida por la mi sma instancia de objeto. Esto puede representarse mediante el siguiente pseudo-cdigo:
Cree L lame Llam e o b je to al al X d e 1. ai al del ob j e t o o b je to el X X sea d e stru id o llam ad o r lla m ad o r mtodo da t os mtodo datos hasta

Dev u e 1 v e D evuelva

... c o n t i n u a

que

canal

Este bucle continua hasta que el canal con el que se registra este objeto en el entorno remoto es destruido. Dependiendo del tipo de aplicacin que este escribiendo, determine el modo de activ acin que debe u sar segn los siguientes factores: Coste: Si crear el objeto remoto c onsume recursos y tiempo, usar el modo SingleCall puede no ser el modo mas e f e c t u de cr ear su objeto. va que el objeto es destruido despus de que cada cliente lo use. Inform acin de estado: Si esta al macenando informacin de estado, como propiedades, en el objeto remoto, use objetos Sinq etnn. que pueden mantener datos de estado.

Cmo registrar objetos con el mtodo Configure


Si necesita un modo ms flexible de mant ener los datos de configuraci n que necesita el entono remoto par a registrar el objeto, puede usar el mtodo Con igure () de la clase RemotingConf iguration. La i nformacin de con fi gu racin al mac en ad a en el archivo es la misma informacin que puede usar en el mtodo RegisterWellKnownServiceType (). Las ventajas de usar un archivo de configuracin es que. si cualquiera de las configuraci ones del objeto cambia, puede modificar el archivo de configuracin sin ca mb ia r el codigo. El esquema para realizar la configuracin aparece en el listado 36.4 y la explicacin de eada elemento en la tabla 36.7.
Listado 36.4. Archivo de configuracin remota
< c o n f i g u r a 1 1 on > 'system . ru n t im e . r e m o t m g > v app1 1 c a1 1 on> < 1 i f e 1 1 me > <ch an ne ls > < chann e 1> iIn stan ce) (Insta nce ) ( I n s t a i i c e ,) (Instance)

< s e r v e r Pr ov i d e r s > < p ro v id e r>

785

- t '' r r,a r t e r * ; I n s t a n r: e i i i r.t ? r " vi 1 e r s . Tnstance i p r o v i ri e r > "form atter > " c l i e n t
w p

(I ns t an c e ) (I n s t a n c e ) Instance) 1n s t an c e )
Instance;

!C lie n t - c 1 1 e r. t
<S c r v i c e

I 1 l ' .nown' -

: ar: t i v a t. e el ' -'.serv c ^


w p ! 1 kn o w n '

" a ": 1.1 v a t. o d " s o a p I n t. e i o p >

(S e r v i c e

Instance)

" i n t e r o p >'.ni 1 T y p e - m t e r o p Z m l E l e m e n t ,> -' p r e L o a d > r: h a r. n e 1 s > ( T e mp l a t e ) - c h a n n e ! ' T e mp 1 a t e ) -' s e r v e r P r o v i c i e r s > ' p r o v i d e r '
- i orrna11 er >

(Instan ce )

In s ta n c e )
(Instance)

c 1 i e n t P r o v i d e r s > Instance) ' p i o v i d e r ' (Insta nc e ) fo rm atter'- !Instance) ch a n n e 1 S i n k P r o v i d e r s > -' s e i v e r P r o v r d e r s > ( 1 e mp l a t e ) pro v i de r f o r ma t t. e r > T e mp l a t e ) T e mp l a t e ) (Tem p l a t e )

e l i e n t. P r o v i d e r s

- pr ovid er '
' ' d
i o

(Template)
! T e mp 1 a t e )

r ma t t e r

b n cj -

Aunque ha> muchas opciones en el archivo de configuracin, solo necesita usar las necesarias para su aplicacin. Por ejemplo, el fragment o de codigo del listado 36.5 representa un archivo de configuracin par a un objeto activado con H T T P que es un objeto de modo
S i n q 1e Ca J ! .
Listado 36.5. Ejemplo de configuracin de archivo
c onf ig u r a t io n 'system . ru n t im e . r em o 11 n g > < 'app 1 i c a t i on>
<' c: I

e n t

u r l = h t t p : / / l o c a l . s e r v i d o r / S e r v i d o r Ob j e c t " > t y p e = " S e r v i d o r Ob j e c t . C l a s s l , ReturnNam e"

< ' we 1 1 k n own

u r 1 = " h 1 1 p : / / 1 o c a 1 s e r v i d o r / S e r v i d o r Ob j e c t / C l a s s l . soap" /> / c 1 len t > 'channel s >

786

<channel

r e f = "ht.tp"

</channels > < / . s y s t e m . r u n t i m e .remot ing> : / c o n ig u ia f 101P

Tras crear el archivo de configuracin, la operacin de crear el objeto anfi trin es mucho mas simple que registrar un objeto con el mtodo P. ogi s t . - i W e l I K n o w n S e r v i c e T y p e ( ) de l a c l a s e P . e mo t i n q C o n f i a u r a t i o n . El eodigo del listado 36.6 muestra cmo registrar el objeto mediante el mtodo C o n
figure ().
Listado 36.6. Cmo usar un archivo de configuracin remota en la clase anfitriona
11 a me s p a c e Se rv id o r

{
/ / / ,/// / / / ' summary> D e sc rip ci n / s i mura r y C1 ass 1 :summary> El p rin c ip a l < / s umrna r y > vo id Mam (s t r m g [ ] a ig s i resu m id a de C la ssl.

c1 ass

{
/ / / / / / / / / punto de entrada a la a p lic a c i n .

[S T A T h re a d ] st.atic

{
R e m o t i n g C o n f ig u i a t i o n . C o t i f i g u r e { " S e r v i d o r . E x e . C 011 i g " ,> ; C o n s o l .W rite L in e ("P ress C o n so l . R e ad Lm e ( ; any key to ex i t " ; ;

1 } ) Como puede ver. el cdigo se ha visto reducido de quince lineas a una

N O T A : El nombre del archivo de configuracin debe ser el nombre del ejecutable, incluida la extensin exe, con la extensin adicional conf ig aadida. En el caso de la aplicacin anftriona. el archivo de configuracin recibir el nombre servidor .exe .conf ig y estar en el directorio Bin donde est el archivo ejecutable de la aplicacin anftriona.

La tabla 36.7 recoge todos los elementos disponibles y sus usos para el esque ma de archiv os de configuracin remota.

787

Tabla 36.7. E s q u e m a p a r a el a r c h i v o d e c o n f i g u r a c i n d e v a l o r e s r e m o t o s

Elemento
<system.runtime.remoting> <application>

Descripcin
Contiene informacin sobre objetos y canales remotos Contiene informacin sobre los obje tos remotos que la aplicacin consu me y expone Contiene informacin sobre el perodo de duracin de todos los objetos acti vados en el cliente que atiende esta aplicacin Contiene los canales que la aplicacin utiliza para comunicar con objetos re motos Configura el canal que la aplicacin utiliza para comunicar con objetos re motos Contiene los proveedores de recepto res de canal que van a formar parte de la cadena de llamadas de receptores de canal predeterminada del servidor correspondiente a esta plantilla de ca nal cuando se hace referencia a la plan tilla en otro lugar del archivo de configuracin Contiene el proveedor de receptores de canal correspondiente a un receptor de canal que se ha de insertar en la cade na de receptores de canal Contiene el proveedor de receptores de canal para un receptor de formateador que se ha de insertar en la cadena de receptores de canal Contiene los proveedores de recepto res de canal que van a formar parte de la cadena de llamadas de receptores de canal predeterminada del cliente correspondiente a esta plantilla de ca nal cuando se hace referencia a la plan tilla en otro lugar del archivo de configuracin

<lifetime>

<channels> (Instancia)

<channel> (Instancia)

<serverProviders> (Instancia)

<provider> (Instancia)

<formatter> (Instancia)

<clientProviders> (Instancia)

788

Elemento

Descripcin

<client> <wellknown> (Instancia de cliente)

Contiene los objetos que la aplicacin consume Contiene informacin sobre los obje tos (conocidos) activados en el servi dor y que la aplicacin desea consumir Contiene los objetos activados en el cliente que consume una aplicacin de cliente Contiene los objetos que la aplicacin expone a otros dominios de aplicacin o contextos Contiene informacin sobre los obje tos (conocidos) activados en el servi dor y que la aplicacin desea publicar Contiene informacin sobre los obje tos activados en el cliente y que la apli cacin expone a los clientes Contiene las asignaciones de tipos uti lizadas con SOAP Crea una asignacin bidireccional en tre un tipo de Common Language Runtime y un tipo XML y espacio de nombres XML Crea una asignacin bidireccional en tre un tipo de Common Language Runtime y un elemento XML y espacio de nombres XML Especifica el tipo para cargar las asig naciones de las clases que extienden SoapAttribute Contiene las plantillas de canal que la aplicacin utiliza para comunicar con objetos remotos Contiene la plantilla de canal que la aplicacin puede especificar y configu rar para comunicar o escuchar las soli citudes de objetos remotos Contiene plantillas para proveedores de receptores de canal de cliente y servi-

<activated> (Instancia de cliente)

<service>

<wellknown> (Instancia de servicio)

<activated> (Instancia de servicio)

<soaplnterop> <interopXmlType>

<interopXmlElement>

<preLoad>

<channels> (Plantilla)

<channel> (Plantilla)

<channelSinkProviders>

789

Elemento

Descripcin

dor. Se puede hacer referencia a todos los proveedores de receptores de ca nal especificados debajo de este ele mento en cualquier lugar donde est registrado un proveedor de receptores de canal <serverProviders> (Plantilla) Contiene plantillas de receptores de canal que se pueden insertar en una cadena de llamadas de canales de ser vidor Contiene la plantilla de proveedores de receptores de canal correspondiente a un receptor de canal que se ha de in sertar en la cadena de receptores de canal del servidor o cliente Contiene el proveedor de receptores de canal para un receptor de formateador que se ha de insertar en la cadena de receptores de canal del cliente o servi dor Contiene plantillas de receptores de , canal que se pueden insertar en una cadena de llamadas de canales de cliente Especifica si se van a cargar tipos en el archivo de configuracin cuando se inicia la aplicacin

<provider> (Plantilla)

<formatter> (Plantilla)

<clientProviders> (Plantilla)

<debug>

Hast a ahora, este capitulo ha explicado los entresijos de la creacin de la aplicacin a n f i t no n a que registra el objeto remoto con el entorno remoto. Ahora debe escribir la aplicacin cliente que realiza las peticiones al objeto remoto, que es el tema de la siguiente seccin.

Cmo escribir el cliente remoto


Hast a ahora, ha creado el objeto anfitrin y la aplicacin de servidor anfitrin que gestiona las peticiones del objeto anfitrin por parte del cliente para el m e diante el entorno remoto. El ultimo paso para escribir esta aplicacin remota es escribir la aplicacin cliente que realiza las peticiones al objeto remoto. En este caso, el cliente llama al mtodo P . e t u r n N a r n e del ensambl ado S e r v i d o i -

790

O o j e c t v pasa un parmet ro c u s t o m c r I D que usa el mtodo F e t u r nUame i. ; para bu sca r el nombre de la compa a del cliente en la base de datos Northwind Para empezar, cree una nueva aplicacin de consola llamada Client: en el directorio C : \ c S h a r p R e m o t i n g \ C l i e n t . Puede llamar al objeto remoto con cualquier tipo de aplicacin, pero para hacerlo mas sencillo, crearemos una aplicacin de consola. Se puede llamar al objeto remoto desde el cliente de una de estas tres formas: Ll amando al mtodo GetOb j e c t ( ) de la clase A c t iva t . o r . con lo que es a c t u a d o en el servidor. Llamando al mtodo C r e a t e l n s t a n c e ( ) de la clase A c t i v a t o r . con lo que es acti vado en el cliente. Usando la p al ab ra clave n e w. con lo que puede ser a cti vado en el servidor o en el cliente.

La diferencia entre activacin en el cliente y activacin en el serv idor es en u n cio se crea realmente el objeto. Cada tipo de a c t u acin puede conseguirse medi an te programacin o mediante un archivo de configuracin (usando el mismo formato descrito en la tabla 36.7). pero para la activacin en cliente, se hace un viaje de ida y vuel ta al s er v id or p a r a c r e a r el obj et o c u a n d o se invoca al mt odo C r e a t e l n s t a n c e ( ) . Por el contrario, cuando un objeto es a c t u a d o en el servidor, el objeto servidor no se crea hasta que se hace una llamada al mtodo desde el cliente. Los objetos activados en el servidor crean un proxy que el cliente puede usar par a descubri r las propiedades y mtodos disponibles en el objeto servidor. La principal desv entaja de la activ acin en el serv idor es que solo se permiten constructores predeterminados, de modo que si necesita p a sa r v a n os par met ros a un const ructor de mtodo, deber usar una activacin en el lado del cliente mediante el mtodo C r e a t e l n s t a n c e ( ) de la clase A c t i v a t o r . Todos los mtodos de la clase A c t i v a t o r aparecen en la tabla 36.K.

Tabla 36.8.
M to d o

Mtodos de la clase Activator

D e sc r ip c i n

CreateComlnstanceFrom

Crea una instancia del objeto COM cuyo nom bre se especifica, utilizando el archivo de en samblado con nombre y el constructor que mejor coincida con los parmetros especificados Sobrecargado. Crea una instancia del tipo es pecificado utilizando el constructor que mejor coincida con los parmetros especificados Sobrecargado. Crea una instancia del tipo cuyo nombre se especifica, utilizando el archivo de

Createlnstance

Createl nstanceFrom

791

Mtodo

Descripcin

ensamblado con nombre y el constructor que mejor coincida con los parmetros especifica dos GetObject Sobrecargado. Crea un proxy para un objeto re moto en ejecucin, un objeto conocido activado en el servidor o un servicio Web XML

Tras decidir el tipo de aplicacin necesaria para la aplicacin, puede escribir el cdigo cliente El listado 36.7 muest ra el codigo completo de la aplicacin cliente. ( o r n o suceda en el codigo anfitrin, debe registrar un canal en primer lugar. C uand o registra un canal desde el cliente, no especifica el numero de canal. La llamada al final del URI indica al cliente la direccin en la que se encuentra el canal correcto, porque esta incluido en la llamada de mtodo G e t O b j e c t ( ; ; especifique el objeto que esta intentando crear y la localizacin del objeto. Tras crear la clase, puede llamar a mtodos y establecer p ropiedades del mismo modo que en cualquier otra clase
Listado 36.7. Aplicacin de cliente remoto
u s m g Syst .e m ;

us incf u.s i ng us i nq i . i s in g

Syst . e m .Punt ime .P .e rao ting; ."yst.om. P.unt. i me .Peino t ing .C h a n n e l s ; S ys 1 .e m .P.un t ime .P. emot ing .C h a n n e l s .T c p ; S e r v i d o r Ob ]e c t ; Client

namespace

i
/// - summar y ' / / / r>o s c i ip 1- io n l e s uiai d a d e Clas.s 1 . /// /s amina y 0 1a s s P emo t .ir.gClient

1
lSTAThiea d ] s ta t . lo v o i ' i Ma i n s t r i n g \ ] a r g s , )
i

Cha une 1Seivi ( e s .P e g i s t e t C h a n n e 1 (new


S e r v id o iO b ] ecf . (Jlass 1 =

T n p C h a n n e 1 t) ) ;

(C l a s s 1 ) A c t i v a t o r . G e t O b j e c t i

t y p e o f !C 1 a s si) , " t < : p : / / 1 o c a 1 s ervid o r :8 O 8 5 / R e t u r n N a m e " ,nuil ) ; C o n s o l .VJrxt eLine ( . Pet u r n M a m e ("ALF'KI") ) ; C o 11 s o le .P e a d L m e ) ;

792

I ras escribir el cliente, puede ejecutar la aplicacin S er\ idor. exe y. a conti nuacin. ejecutar la aplicacin cliente: \ debera obtener unos resultados simila res a los de la figura 36.2. La aplicacin anfitriona permanece siempre abierta, o hasta que la cierre, mientras cada llamada de cliente a la aplicacin anfitriona devuelve el nombre de la compa a para A L F k l c u s t o m e r I D . que es la identificacin de comprador pas ad a a la aplicacin cliente.

Figura 36.2. Resultados de ejecutar Servidor.exe y Client exe

Si deja el codigo de la aplicacin anfitriona original en modo S i n q i c C a l i . cada vez que ejecute la aplicacin cliente, el objeto servidor se destruir > se volver a crear. Al cambiar We ] 1 K n o w n O b j e c t M o d e a S i n q l c t . o n . observara la dife rencia entre los modos S i n q l e C a l l v Si n q l e t o n . El siguiente fragment o de codigo muest ra la aplicacin anfitriona que crea el objeto en modo S i n q l e t o n :
R e m o t in g C o n f ig u r a t io n . R e gisterW e llK n o w n S e r v ic e T y p e ( t y p e o f ( S e r v i d o r Ob j e c t . C a s s i ) , " P . e t u r n i Ja me " , We 1 1 K n o w n O b j e c t M o d e . S m g l e C a l l ) ;

La figura 36.3 muest ra la diferencia entre los resultados de la aplicacin anfitriona tras ejecutar la aplicacin cliente v a n a s veces. C omo puede ver. el modo S i n q l e t o n no destruye el objeto cuando el metodo sale del contexto, mientras que el modo S i n q 1 e C a i 1 necesita volver a crear el objeto cada vez que se llama al mtodo R e t u r n N a r n e ( ) .

793

Figura 36.3. Aplicacin anfitriona eje cutndose en modo SingleCall y en modo Singleton

Resumen
Este captulo analiza detalladamente el entorno remoto de .NET. Al usar el entorno remoto, puede activ ar objetos a trav s de limites de proceso, dominios de aplicacin y limites de equipo. Si v a a implementar un entorno remoto, hay a l g u nos temas mas av anzados en el S DK que quizas le conv enga leer antes de e m p e zar: Crear formateadores de usuario: Puede crear formateadores de usuario si los formateadores T C P y H T T P no satisfacen sus necesidades de uso de datos Busque Receptores y Cadenas de receptores en Framevvork SDK Acceso remoto asincrnico: El acceso remoto es otra tecnologa N E T con c a p a c i d a d e s a s i n c r n i c a s i n t e g r a d a s . B u s q u e R P C a s i n c r n i c o en Framevvork SDK para apr ender a usar delegados y eventos con proc edi mientos remotos. Hay muchas buenas razones para estudiar los accesos remotos, pero antes de empezar, asegrese de estudiar las capaci dades de los servicios Web X ME v A S P . N E T para conseguir comunicacin entre procesos. Puede ahor rarse mucho t iempo v esfuerzo creando las aplicaciones anfitrionas y modificando el modo en que sus clientes instancian objetos.

794

37 C# y seguridad .NET

Una de las cosas ms importantes que debe recordar cuando se t raslade a C# y N E T Framework es la seguridad. Debe asegurarse de que c uando cree apl icaci o nes con n-mveles. la seguridad sea de la m xi ma prioridad porque las p roba bil i dades de que se produz ca una brecha en una aplicacin distribuida son mucho mayores que en una aplicacin independiente. Es por esto que N E T Framework se creo pensando en la seguridad, lo que se refleja en cada aspect o del entorno. N E T Framework es ca paz de ejecutarse de manera remota, realizar descargas dinmicas de nuevos componentes e incluso de ejecucin dinmica. Con este tipo de entorno, si un p r og r am ad o r debe crear el modelo de seguridad, probablemente t arde mas en codificarlo que en crear el propio programa. C ua nd o cree aplicaciones, el modelo de s e g u n d a d suele bas ars e en el nivel de usuario o el nivel de grupo. La aplicacin realizara ciertas acciones o no. NET Framew ork proporciona a los progr amadores medios para se g u rid a d basada en fu n c io n e s , que t rabaj a de una manera muy parecida a la s e g u nd a d de nivel de usuario y de nivel de grupo. La seguridad bas ada en funciones se puede resumir en principios e identidades, aun qu e tambin propor ci ona s e g u n d a d de nivel de codigo. al que se hace referencia general ment e com o seg uridad de acceso a cdi go o s e g u n d a d b asada en pruebas. Cuando un usuario inicia una aplicacin que usa s egu nd ad de acceso a codigo. puede tener acceso a un recurso (por ejemplo, una unidad de red), pero si el

797

cdigo contenido en la aplicacin no es fiable, el pr ogr ama no puede a cceder a la unidad de red. Este tipo de s eg u n d a d se basa en codigo mvil. Quizas no quiera usar una aplicacin mvil y dejar a esa aplicacin que acceda a todos los recursos a los que se ha encomendado. La s e gu n da d b as ada en funciones evita que los programadores malintencionados escriban aplicaciones que puedan ejecutarse como si las estuviramos ejecutando nosotros y realizar todo tipo de acciones en n u es tro equipo local o a travs de nuestra red corporativa. La s e gu nd a d de N E T Framevvork se coloca sobre la seguridad ya presente en su sistema operativo (OS). Este segundo nivel de seguridad es mucho ms extensible que la s e gu nd a d OS. Ambos tipos de seguridad. OS y N E T Framevvork. pueden compl ement arse entre si. Este capitulo le acerca a varios temas relacionados con la seguridad, como el uso de funciones de Wi ndows par a determinar permisos. Aprender a solicitar y denegar permisos dentro del codigo mientras realiza operaciones de registro. Por ultimo, aprender a usar permisos basados en atributos para definir los derechos de su codigo en tiempo de ejecucin.

Seguridad de cdigo
La seguridad de acceso a cdigo determina si se permite a un ensambl ado ejecutarse basandose en v a n a s unidades de prueba, como la URL de la que p roc e de el ensambl ado y quien autoriza el control. Al instalar N E T Framevvork. estn configurados los permisos predeterminados, lo que reduce enormemente las pos i bilidades de que un control que no es de confianza procedente de Internet o de una intranet local pueda ejecutarse en su equipo. Puede haber visto esto si ha intenta do ejecutar algunas aplicaciones o us ar algunos controles desde una unidad de red que exija privilegios de s e g u nd a d especiales. Estos privilegios de s e g un da d e spe ciales incluyen la escritura en un archivo de disco, leer o escribir en y desde el registro, adems de operaciones de red. Norma lme nte recibir una excepcin de s e g un d ad como las siguientes cuando intente hacer estas acciones si no cambia la directiva de s e g u n d a d par a que permita este tipo de comportamiento:
U nhandled for the E x cep tio n : of System . S e c u r it y . S e c u rity E x c e p t io n : type Request perm i.ssio n

S y s t e m . S e c u n t y . Pe r m i s s i o n s . F i l e I OPe r m i s s i o n The stdte o the f a i ie d p e rm issio n was :

' I P e r m i s s i o n e l ass = " S y s t e m . S e c u r i t y .Pe r m i s s i o n s .F i l e l O P e r m i s s i o n , V e is i


or

mscor lib ,

- 1 . U. 3 300 . ,
K

C u ltu re ^ n e u tra l,
b

P u b lic

eyToken =b7 7a

c b 6 1 9 3 4 e 8 9"

v e r s i n - " 1" Re a d = " Z : \ t es t . d a t " Wr 1 1 e - - " Z : \ t e s t . d a t " / "

798

La s e g u n d a d de acceso a codigo solamente funciona en codigo \ e n f i e ab l e. Durante la compilacin justo a tiempo (Jl l ). se examina el lenguaje intermedio de Microsoft (MSIL) para gar ant izar la s eg u nd a d de tipo L1 eodigo de seguridad de tipo solo tiene acceso a las posiciones de memoria para las que tiene derechos Acciones como las operaciones de puntero estn prohibidas, de modo que solo se puede en tra r \ salir de las funciones desde los punt os de ent rada \ salida predefinidos. Lsto no es un mtodo infalible; pueden producirse errores Sin e m bargo. impide que una unidad de codigo malintencionado pueda forzar un error en su aplicacin \ apr ovech ar algn error en el sistema operativo, consiguiendo asi acceder a la pila. Ln estas circunstancias, cuando una unidad de eodigo malicioso ha forzado un error, el eodigo que genero el error solo puede acceder a las posi ciones de memoria que el JIT determino que eran accesibles para el

Directiva de seguridad de cdigo


La s e gu n da d de acceso a codigo permite a una pl at aforma asi gnar un nivel de s e g un d ad a una aplicacin o ensamblado. C omo esto se consigue con pruebas t omadas del elemento en cuestin, la s e gu n da d de acceso a codigo t ambin recibe el nombre de s eg u n d a d basada en pruebas Las pruebas recogidas del eodigo podran ser la ubicacin en Internet desde la que se descargo el codigo. una firma digital ubicada en el codigo o cdigo escrito por el propio aut or Las directivas de s eg u n d a d de cdigo definen v a n o s grupos de eodigo. cada uno de los cuales tiene un conjunto de permisos C uand o una aplicacin se ha ejecutado, es analizada en busca de pruebas. Segn la prueba del codigo. este se coloca en un g rupo de codigo. heredando asi los permisos de ese grupo. Estas directivas de s e g u n d a d pueden establecerse en el nivel de dominio de empresa, equipo, usuario o aplicacin, proporci onando as una alto grado de control sobre lo que se ejecuta y con que acceso. Puede haber permitido a su eodigo que tenga derechos ilimitados, pero su administrador de red puede definir algunas directivas de s e gu nd a d que superen a las suyas.

Permisos de cdigo
El CLR. cuando concede permisos de s e gun da d, solo concede permisos al codigo en las operaciones que se le permite realizar. El C LR usa objetos llamados perm isos para implementar este tipo de seguridad en codigo gestionado. Los prin cipales usos de los permisos son los siguientes: El cdigo puede solicitar los permisos que pretende usar o que posiblemen te necesite. . NET Framevvork tiene la tarea de determinar si estas peticio nes son v alidas. Las peticiones de s e gun da d se conceden solo si las pruebas recogidas del cdigo lo permiten. El codigo nunca recibe mas permisos de los permitidos por la seguridad actual. Por otra parte, el codigo puede recibir menos permiso que el especificado en la peticin.

799

El C L R concede permiso al eodigo bas andos e en varios factores: La iden tidad del codigo (como la URL de la que fue obtenido, quien escribi el codigo y similares), los permisos que se solicitan y la cantidad de cdigo que es de confianza, definida por las diferentes directivas de s eg und ad. L1 codigo puede hacer una peticin para obtener un determinado permiso. Si se realiza una peticin mediante el codigo. todo el codigo que se ejecute en el contexto de la aplicacin debe tener acceso al permiso para que este sea concedido. L1 codigo puede recibir tres clases de permisos, cada uno de los cuales tiene un proposito especifico: Los permisos de codigo de acceso representan el acceso a un recurso p r o tegido o la autoridad para realizar una operacion protegida. Los permisos de identidad indican que el codigo tiene credenciales que admiten un tipo de identidad particular, como codigo que puede tener una identidad "Administrador" y. por tanto, ejecutarse con todos los permisos que pueda tener un administrador. Los permisos de s eg u n d a d basada en funciones proporci onan un meca ni s mo para descubri r si un usuario (o el agente que acta en nombre del usuario) tiene una identidad particular o es un miembro de un cargo es pe cifico. r r i n : i p 1 . ?v; r m i s s i o n es el umeo permiso de s eg u n d a d b a sada en funciones. Ll tiempo de ejecucin propor ci ona clases de permiso integradas en varios nombres de espacios y propor ci ona compatibilidad para disear e mplementar clases de permiso personalizadas.

Seguridad de usuario
( asi todos los sistemas de s e g un d ad actuales implementan algo llamado s e g u n d a d de usuario. Estos tipos de sistemas de seguridad requieren i nformacin de los usuarios que solicitan acceso. Por ejemplo, deben saber quin es esa persona y a que elementos tiene acceso ese usuario. La seguridad de usuario desempea un papel nuiY importante en los sistemas computerizados porque, cuando ejecuta una aplicacin en su equipo, la aplicacin suele g uar dar la identidad de la persona que la esta ejecutando. Por tanto, si ejecuta una aplicacin, esa aplicacin tiene todos los derechos y permisos en su equipo local y a travs de la red que tendramos nosotros. A diferencia de los servicios Wi ndows, que le permiten configurar quien p a r e ce estar ejecutando la aplicacin, una aplicacin Wi ndows normal nunca haba otorgado este tipo de control con anterioridad. Este hecho ha facilitado la prolife-

800

racin de muchos virus y t royanos a los que tienen que enfrentarse diariamente los usuar ios v empresari os de ordenadores. Al permitirle determinar el tipo de permiso que tienen las aplicaciones en su equipo, se reduce enormemente la pos i bilidad de un at aque por parte de un codigo maligno. Operaciones, como leer el registro, sobrescribir archivos de sistema o recorrer su libreta de direcciones personal, no sern posibles. Puede p rob ar rpidamente si sus aplicaciones se ejecutan segn el usuario que las ejecuta probando el p rog rama del listado 37.1.
Listado 37.1. Variables de entorno para tareas de seguridad sencillas
u sin g System ; S .1 mp 1 e S e c u r i t y C la ssl

n a me s p a c e

I
d a s s

I
[S T A T h r e a d ] sta tic vo id M a in (s trin g [J am argsj cu rre r.tly : : ru nn in g as : " ) ;

{
C o i i s o l e . Wr 1 1 e L i n e ( " I Co n so l .W r it e L in e ("User C o n s o l . W r i t e L i n e ( " D o ma i n ( 0 } " , E n v 1 r o n m e n t .U s e r Dom aInNam e) ; { 0 } " , E n v 1 r o n m e n t . IJs e r a m e ) ;

Cuando ejecuta este programa, debera ver el nombre que usa par a conectarse a Wi ndows, adems del nombre de su dominio, como muestra la figura 37.1.
C:\WINDOWS\System32\cmAcxc
C:\>S impleSecurit y .exe I an currently running as User : Francisco Domain : FRflN C:\>

I
Figura 37.1. La clase Environm ent puede ser utilizada para tareas de seguridad sencillas

Si no esta conect ado a un dominio de red. simplemente vera el nombre de su sistema como el nombre de dominio. Fl tipo de seguridad mas sencillo que proba-

801

blcmente pueda implementar en este momento sera hacer que se c ompare el n o m bre de usuario y el nombre de dominio p ar a validar una operacin y. si todo es correcto, continuar con el programa. Esto es vlido hasta que lleva su aplicacin a otro equipo y deja de funcionar porque ha incluido nombres seguros en su cdigo. La siguiente seccin revisa este tipo de seguridad junto con otros tipos sencillos.

Seguridad .NET y basada en funciones


La s e g ur i d a d b a s a d a en f un ci one s se b a s a en la cl ase P r i n c i p a l Permission. Puede usar PrincipalPermission para determinar si el usuario actual tiene un nombre concreto (como John Doc) o si el usuario pertene ce a un grupo particular. Esta clase es el nico permiso de seguridad basado en funciones propor ci onado por la biblioteca de clases N E T Eramework. Tras definir los objetos Identity y Principal, puede realizar c o m p r o baciones de seguridad con ellas de uno de estos modos: Usando c omprobaci ones de seguridad i mperativa Usando comprobaci ones de s eguridad declarativa Accediendo direct ament e al objeto Principal Al utilizar codigo administrado, puede empl ear co mprobaci ones de seguridad i mperativa o declarativ a para determinar si un objeto principal concreto es mi em bro de una funcin conocida, tiene una identidad conocida o representa una iden tidad conocida que ac t a en una funcin. Para realizar la compro ba ci n de seguridad utilizando seguridad i mperativa o declarativa, se debe efectuar una solicitud de seguridad par a un objeto PrincipalPermission. Durante la comp rob aci n de seguridad, el entorno de ejecucin comn exami na el objeto principal de quien efecta la l lamada p ar a determinar si su identidad y su funcin coinciden con las representadas por el objeto PrincipalPermission que se d e m a n d a . Si el o b j e t o p r i n c i p a l no c o i n c i d e , se i n i c i a u n a e x c e p c i n Secur ityException. C uando esto sucede, slo se c omprue ba el objeto p ri n cipal del s ubproceso actual. La clase PrincipalPermission no produce un recorrido de pila con permiso de acceso a cdigo, ya que podra ca u sa r graves probl emas de seguridad. Adems, se puede acceder directamente a los valores del obj et o p ri n ci p al y re a li za r c o m p r o b a c i o n e s sin un o bj et o P r i n c i p a l Permission. En este caso, bast a con leer los valores del s ubproceso Prin cipal actual o utilizar la aut orizacin de ejecucin del mtodo IsInRole

Cmo asignar las funciones Windows


Por regla general, cuando se necesita asignar varios usuarios a funciones espe cficas. es mejor usar la funcionalidad de grupo integrada en Wi ndows N T 4.0.

802

Wi ndows 2000 y Wi ndows XP. En lugar de aadir privilegios para cada usuario, puede crear un nuevo g rup o con ciertos derechos de acceso \ luego ag regar los usuarios al grupo en concreto. Estas funciones ahorran una cantidad considerable de tiempo y permiten a los admi ni stradores del servidor controlar una gran canti dad de usuarios. Empecemos agr egando un nuevo g rup o en Wi ndows 2000/ W indows XP: 1. Haga clic con el botn derecho del ratn en Mi PC y seleccione Ad mi ni s trar. Cuando se abra la consola de Administracin de equipos, expanda la vista del rbol en el cuadro izquierdo haciendo clic en Usuarios locales y grupos para que aparezca Grupos y haga clic en Grupos. Cuando haga clic en Grupos, ver una lista de ap ro xi ma damen te siete grupos integrados en el sistema operativ o Window s, como muestra la f igu ra 37.2.

2.

2 Administracin de equipos
i , A rc h iv o A c c i n Ver V e n ta n a A yuda

S i
j j j t . H e r r a m ie n t a ;- d e l s is te m a + ' U j V is o r d e s u c e s o s + , J 'l a r p e t a s c o m p a r tid a s

[
N o m b re A d m im s tr a d o r e s D u p lic a d o r es I n v it a d o s D e s c rip c i n L o s a d m in is t r a d o r e s t ie n e n a c c e s o c . .. P u e d e n d u p lic a r a r c h iv o s e n u n d o m in io L o s I n v it a d o s t ie n e n p r e d e t e r m in a d a . . L o s m ie m b r o s e n e s t e e q u ip o p u e d e , . L o s o p e r a d o r e s d e c o p ia p u e d e n s o b . . L o s u s u a r io s n o p u e d e n h a c e r c a r n t u . .. L o s u s u a r io s a v a n z a d o s t ie n e n m a s ... A lo s m ie m b r o s d e e s t e g r u p o se le s .. .N e t D e v e lo p e r G r o u p G r u p o p a r a el C e n t r o d e a y u d a y s o . .. L o s u s u a r io s d e l d e p u r a d o r p u e d e n ... L o s d e s a b o l l a d o r e s d e V is u a l S t u d io .

-HJ, A d m in is tr a c i n d e l e q u ip o ( lo c a l)

U s u a r io s lo c a le s y g r u p o s S O p e r a d o r e s d e c o n ig u r _ ] U s u a r io s O p e r a d o r e s d e c o p ia

| |] R e g is tr o s y a le r t a s d e r e n d ir r A d m in is tr a d o r d e d i s p o s it iv o ; A lm a c e n a m ie n to

4%U s u a r io s
U s u a r io s a v a n z a d o s U s u a r i o s d e e s c r it o r io r e . D e v e lo p e r s H e lp S e r v ic e s G r o u p

M e d io s d e a lm a c e n a m ie n t o e D e s f r a g m e n t a d o r d e d is c o A d m in is tr a c i n d e d is c o s

U s u a r io s del d e p u ra d o r V 5 D e v e lo p e r s

S e rv ic io s y A p lic a c io n e s

Figura 37.2. La administracin de grupos se consigue con la consola Administracin de equipos

3.

Haga clic con el botn derecho del ratn en el cuadro a la derecha y selec cione Grupo nuevo. Llame a este grupo Developers. como muestra la figura 37.3. Tras crear este grupo, haga clic en el boton A g r e g a r y agregue su cuenta de usuario al grupo. Para este ejemplo, asegrese de que no esta en el grupo Administradores. Si es un administrador, quizas quiera probar la siguiente aplicacin con otra cuenta Windows.

4.

803

jjxj
N o m b re d e grupo:

1 e r
| NET ['e v e lo p e r Luoup

D e s crip ci n :

A g re g a r

Crear

Cerrar

Figura 37.3. Agregue un grupo Developers a W in d o w s

Una vez que ha c o lo ca d o el n uevo g ru po , v am os a e s t u d i a r las clases

Windows Pr incipa 1 y Windows Identity. C uan do se usan en conjunto,


estas dos clases pueden determinar si el usuario actual de Wi nd ows pertenece a algn grupo especfico. Examine la aplicacin de ejemplo del listado 37.2.
Listado 37.2. W in dow sP rincip al le permite co m probar la pertenencia a una funcin
us i ng u s ] 11 g cla s s y s t e m; S y s t. e m - S e c u r i t y . P r i n c i p a ] ; C 1as s 1 st at i c v o i cl Ma i n wi wp Wi n d o w s I d e n t i t y . G e t . C u r r c u t () ; new lo s en W i n d o w s P r i n o i p a 1 (w i ) ; del a d m in istrad o r lo ca l


Wi n d o w sI d e n t i t y W indow sPr i n c i p a 1 // // i e lse C o n s o l e . W r i t e L m e ("You i
f

Esto si se

com prueba encuentra

derechos un

d o m in io are an not A d m in istra to r!" i ; an A d m in istra to r." );

(v/p . I s I n R o l c (W j n d o w s B u i l t l n R o l e . A d m i n i s t r a t o i ) )

C o n s o le . W r it e L in e ("Your

are

(w p . I s I n R o l e ( " P O WE R H O U S E \ \ D e v e 1 o p e r ") ) C o n s o l e . W r i t e L m e ("You are are in not the in D evelo p er the group !"! ;

e lse C o n s o l e . W r i t e L i n e ("You g ro u p ." ); D eveloper

804

Este codigo crea un nuevo objeto Windows Ident 1 1 y (basndose en la iden tidad del actual usuario) con el mtodo GetCurrent El objeto WindowsPrinoipal usa este objeto de identidad como paramet ro en su constructor, de modo que puede recuper ar cierta informacin sobre la p er s o n a u obj et o. A c o n t i n u a c i n l la ma al m t o d o I s I n R o l e de la cl ase WindowsPrincipal par a determinar si el usuario pertenece al grupo Admi nistradores. El mtodo IsInRole tiene tres variaciones sobre carg ad as de las cuales puede usar dos. La p ri mera recibe una enumeraci n W i ndows Bui 1 tlnRol e . Cu an do c o m pruebe la pertenencia a al guno de los grupos integrados en Windows, debe usar esta enumeracin Dependiendo de si es un administrador, vera uno de dos m en sa jes. A continuacin, el codigo c omp rue ba si el usuario actual pertenece al nuevo g ru po Developer. us ando la segunda versin del mtodo IsInRoJ o . Esta ver sin simplemente recibe un p ar me tr o de cadena que especifica el equipo o el nombre de dominio seguido por el nombre de grupo. En el cdigo anterior, sustituya la pal abr a P O W E R H O U S E por el nombre de su dominio o equipo. Si no pertenece al gru po Administrador y Developer puede observ ar que esta aplicacin de ejemplo solo le reconoce en el gru po Admi nistradores. como muestra la figura 37.4.
CVC:\WINDOWS\System32\cmd.exe C :\M s A d p iin .e x e V o u r a r e an f l d n i n i s t r a t o r ? Voit a r e n o t i n t l i e D e v e l o p e r g r o u p . C :\> _ y. ^
ip j

Figura 37.4. Pertenencia al grupo Administradores puede confu ndir a IsInRole

Esta confusin se produce porque, si es un administrador, forma parte inhe rente de todos los grupos y tiene acceso a todo. Por tanto, cuando compruebe la pertenencia a funciones en sus aplicaciones, es aconsejable c o mp r ob a r la perte nencia al grupo especfico y a todos los otros grupos que esten por encima del grupo que est comprobando. (Por ejemplo. Administradores. Usuarios preferen tes y similares).

805

Principales
Cada s ubproceso de una aplicacin N E T est asociada con un principal del CLR. El principal contiene una identidad que representa la identidad del usuario que esta ej ecut ando ese s ubproces o. Si usa una propi edad esttica llamada Thread .CurrentPr incipal. puede devolver el principal actual asociado al subproceso. Los objetos principales implementan la interfaz IPrincipal que slo c on tiene un mtodo y una propiedad. La propiedad Identity devuelve el objeto actual de identidad y el mtodo TsTnRole se usa para determinar si un usuario pertenece a una funcin o grupo de seguridad determinado. Actualmente. N E T F r amevv or k c o n t i e n e d os c l a s e s p r i n c i p a l : W i n d o w s P r i n c i p a l y Genor icPr incipal. La clase GenericPrincipal se emplea c uando hace falta i mplementar un principal propio. La clase WindowsPri ncipaJ repre senta un usuario de Wi ndows y sus funciones o grupos asociados. Un objeto Identity implementa la interfaz Ildentity. que solo tiene tres propiedades.

Mame es la cadena asociada a la identidad actual. El sistema operativo del


prov eedor de autenticacin pas a la cadena al entorno de ejecucin comn. Un ej empl o de p r o ve e do r de a ut en t ic a ci n es N T L M ( W i nd o ws NT Challenge/Response). que a utentica conexiones de Wi nd ows NT.

IsAuthenticated es un valor booleano que indica si el usuario ha


sido autenticado.

Authenti cationType es una cadena que indica que tipo de aut ent i
cacin se ha usado. Algunos tipos posibles de autenticacin son aut ent i ca cin bsica. Forms. ker ber os . N T L M y autenticacin de pasaporte

Permisos de acceso a cdigo


Antes de ejecutar cualquier aplicacin NET. debe pas ar una serie de pruebas de seguridad que dan a la aplicacin permiso par a realizar ciertas operaciones Los permisos concedidos al codigo tambin pueden ser solicitados en el codigo o denegados por codigo. Todos estos permisos estn determinados por una directiva de seguridad en la que N E T Framevvork confa. Estas directivas de seguridad contienen permisos para acceder a recursos, como recoge la tabla 37.1. C uan do ejecuta una aplicacin, los derechos de cualqui era de los permisos ant eri orment e menci onados se basan nicamente en si el codigo tiene derecho al permiso. Es independiente del usuario que esta ejecutando el codigo real. Por tanto, estos permisos reciben el nombre de s eg u n d a d de acceso a codigo.

806

Tabla 37.1. P e r m i s o s d e a c c e s o a c d i g o m s c o m u n e s

R ecurso

P e r m is o

D e sc rip ci n

DNS Variables de entorno Registro de eventos

DNSPermission EnvironmentPermission EventLogPermission

Acceso al sistema de nombres de dominio. Acceso a las variables de entorno del sistema. Acceso a los registros de eventos, incluyendo los registros de eventos existentes y la creacin de nuevos registros de eventos. Acceso a realizar opera ciones como leer un ar chivo y escribir en un archivo. Acceso al registro de Windows. Acceso a la fu n c io nalidad de la interfaz. Acceso a realizar o acep tar conexiones en una di reccin Web.

Operaciones de archivo

FilelOPermission

Registro Interfaz de usuario Web

RegistryPermission UlPermission WebPermission

Cmo crear una sencilla solicitud de cdigo de permiso


En esta seccin comp re nder lo sencillo que es solicitar permisos mediante codigo para realizar una accin especfica. En este ejemplo, intentaremos leer una clav e del registro, que indica a nombre de quien esta registrado el sistema o p e r a tivo en uso. Al usar la clase R e g i s t r y P e r m i s s i o n . debe especificar el tipo de acceso solicitado al registro (leer, escribir y similares) y la clave especfica a la que se quiere acceder. Por lo general, si slo necesita un acceso de lectura a una clave concreta del registro, slo debe solicitar permiso de lectura. De este modo se as egura de que no va a sobrescribir informacin del registro accidentalmente y de que codigos posteriores, posiblemente malintencionados, puedan c ambi ar la in formacin. Adems, siempre debe envolver sus solicitudes de permiso con algn tipo de controlador de errores. Si el entorno de ejecucin comn rechaza la solici

807

tud de permiso, se inicia una SenurityException. Si efecta esta solicitud en un bloque try/catch. no obtendr ni nguna advertencia porque el error es controlado Aunque puede saber que posee este tipo de permiso en su equipo, no puede predecir las directivas de seguridad que pueden bloquear este acceso en otros equipos o redes. 7'ras crear una solicitud de permiso, solo tiene que llamar al mtodo Dernand ( ) de la clase ReqistryPcrmiss ion. Si Dernand ( ) se ejecuta sin producir nin guna excepcin, se ha acept ado su solicitud de permiso. El listado 37.3 contiene el e| cmpl o de aplicacin.
Listado 37.3. Solicitud de permiso con un controlador de errores estructurado
u.sm q usm q usm q -ia s s System ; M i c r o s o f t . Wi n 32 ; , j y s t e m . S e c u n t y . P e r m i s s i o n s ; C a s s i vo
ld

stati c M am st rrng [ ] arqs)

f
t ry

{
P e q is t ryPer.iiussron "HPEY _LOCAL r e g P e r m i s s i on = new Po - a i s t r y P e r rn r s s i o n ( P e g i s t c y P e r m i s s i o n A c c e s s . A l l A c c e s s , M A C H I N E \ \ S O F T W A P E \ \ M i c r o s o f t: \ \ W m d o w s
o n " }

IiT \ \ r u r r e n t V e r s i

r e q Fe r ra s s i o n . P e m a n d ( ) ;

}
va t r;h ( E x c e p t 1 on e )

Con. ' ; o 1 e . Wr i t- e L, i n e ( e . M e s s a q e ) ; r e 1.11 r n ;

I
P e q i s t. r y K e y i " S C FT W AP E \ \M i c r o s t ry myP. e q K e y - P e q i s t r y . L o c a l Ma c h i n o ;
o

my P r- cj l'e y - m y P e g K e y . i . ' p e n S u b K e y i t \ \W i ndows NT \ \ C u r r e n t V e r s i 0 1 1 " ) ;

f
0 b ]ect. o V d l u e - m y R e q K e y . G e t . V a l e ( " R c g i s t c e d O wn e r " '1 ; C o n s c ; i e . Wt i t e l , i n e ( "C>S P e q 1 s t e r e d Owner : { ! } " , o V a 1 n e . T o S t 1 m q m > ; r;ri t. c h ( i - I u l l P e e t e n c e E c e p t 1011)

{ ) } ) No olvide que aunque la directiva de s eg u n d a d N E T permita a este codigo ejecutarse, la directiva de s e g u n d a d del sistema operativo subyacente tambin

808

debe concederle permiso para ejecutarse. Tras solicitar los permisos para la clave del registro adecuada, slo tiene que leer la clave F^eqi st. redowner y mostrar la informacin en la ventana de consola.

Denegacin de permisos
Al igual que en el mtodo Demand. tambin puede llamar al mtodo Dony ;). que elimina los permisos par a una operacin. Por lo general, es aconsejable elimi nar antes de hacer la llamada cualquier permiso que sepa que no va a necesitar. Puede solicitar permisos a medida que el cdigo los vaya necesitando. Use el mt od o Den y ( ) cuando hava completado una operacin y sepa que ya no van a ser necesarias mas operaciones. La denegacin de permisos tiene varias funciones. Por ejemplo, si esta usando biblioteca de terceros, querr asegurarse de que. tras mani pul ar el registro, nin gn otro codigo pueda hacerlo. La denegacin de permisos es un modo de co n se guirlo. El cdigo del listado 37.4 usa una versin modificada del ejemplo anterior par a denegar en primer lugar un permiso de registro. I ras negar el permiso, intenta leer la clave de registro, lo que da como resultado una SecurityException. Si quiere deshacer una operacin Deny en el codigo. solo tiene que usar el mtodo Revert Deny ( ) par a eliminar la denegacin de permiso; y cualquier intento posterior de leer la clave del registro solicitada se llevar a cabo con xito.
Listado 37.4. Denegacin de permisos a los que no desea que se acceda
u sin g u sin g u sin g cla ss System ; M icro so ft.W in 3 2 ; S y ste m .S e c u rity .P e rm is s io n s ; Ci as s 1 voi d M a i n ( s t r i n g [] a rgs )

{
s ta tic

{
try

{
R e g istry P e rm issio n re g P e rm issio n new R e g stry P e rm is s io n (R e g is try P e rm iss io n A c c e s s.A llA c c e ss , " HKE Y _LOCAL_MACH I N E \ \ S OFTWARE \ \ M i c r os o f t \ \ W m d o w s N T \ \ C u r r e n t V e r s i o n ") ; re g P e rm is sio n .D e n y ();

}
catch (E x ce p tio n e)

{
C o n so l .W n t e L in e (e.M essaqe) ; return;

809

R e g istryK ey

m y R e g K e y = Re g i s t r y . L o c a l M a c h m e ; NT \ \ C u r r e n t V e r s i o n " ) ;

my R e g K e y = m y R e g K e y . O p e n S u b K e y ( " S O F T W A R E \ \ M i c r os o f t \ \ W m d o w s try

{
O b je ct o V a l u e = m y R e g K e y . G e t V a l u e ( " R e g i s t e r e d O w n e r ") ; R e g istere d Owner: C o n s o l e . W r i t e L m e ("OS { 0 } " , o V a l e . T o S t r i n g () ) ;

}
catch (N ul I R e f e r e n c e E x c e p t i o n )

{ } } } Si est ejecutando este ejemplo en Visual Studio. la aplicacin deber detener se en las lneas de mani pul aci n del registro. Al ejecutar esta aplicacin desde la consola se genera una larga lista de errores de excepcin que indican cual es el problema.

Cmo usar permisos basados en atributos


Las solicitudes de permisos de atributo son un modo de asegurarse de que tiene suficientes permisos par a v a n o s recursos antes de ejecutar la aplicacin real men te. JIT y C'LR analizan los atributos cuando se compila la aplicacin Ln el listado 37.5. usa RcqistryPermi ssi onAttri bute y Demanci en Secur i tyAct ion. Si se concede este permiso en el tiempo de compilacin, la aplicacin no se ejecuta. No se t rata siempre del mejor modo de codificar una aplicacin; por lo general tendr modos mas eficaces de controlar errores de este tipo. Por ejemplo, al crear un p rog ram a de chat en red. no es aconsejable evitar que el p ro gr am a se ejecute cuando no tiene derechos de E/S de archivos, ya que siempre puede solicitar al usuario los par met ros de las operaciones. No o b s t a n te. sera logico no permitir que la aplicacin se ejecute si no tiene acceso a o p e r a ciones de red. Este tipo de peticin de seguridad es crucial para la operacion de dicha aplicacin.
Listado 37.5. Cmo usar permisos de atributo
u sin g u sin g u sin g System ; M icro so ft.W in 3 2 ; S y s te m .S e c u n ty .P e rm issio n s;

[R eg .s tr y P e r m is s io n A t t r i b u t e ( S e c u r it yAc tio n .D e m a n d ) ] cla ss C1ass 1 voi d Mam (s trm g [] a r gs )

{
s ta tic

810

R e g istryK e y

m y R e g K e y = Re g i s t r y . L o c a l M a c h i n e ; N T W C u rren t V ersi n " . ;

m yRegKey=m yRegKey. OpenSubKey ( " SOFTWARE \ \ M i c r os o f t \ W i n d o w s try

{
O b je ct o V a l u e - m y R e g K e y . G e t V a 1 u e ( R e g i s t e r e d w n e r "> ;

Con s o l . W r i t e L m e ("OS
{ 0 } " , oVa l u c . T o S t n n g ( ) ) ;

P.egistered

Ovmer :

)
catch (N u l 1 Re f e r e n c e E x c e p t i o n )

{ } ) }

Directiva de seguridad
Las directivas de seguridad son el corazn de la s e gu nd a d bas ada en pruebas. Despus de que se obtiene una p ru e ba de un ensambl ado, ese codigo es asignado a un grupo de codigo. Este grupo de codigo. a su vez. tiene un conjunto de p e rmi sos que definen lo que el codigo puede y no puede hacer. No solo puede modificar la directiva de s eg u n d a d par a que se ajuste a sus necesidades, puede modificarla a varios niv eles y puede crear grupos de codigo personalizados que complementen las directiv as de seguridad que ha definido.

Niveles de directiva de seguridad


Elay cuatro niveles de directivas de seg und ad: empresa, equipo, dominio de aplicacin y usuario. Todos estos niveles tienen que concordar con un permiso de seguridad o el permiso sera denegado, como muest ra la figura 37.5.

Figura 37.5. Los niveles de se solapan para determinar un nivel de seguridad final

811

Si cambi a las directivas de su equipo para permitir ciertos tipos de o per aci o nes de. por ejemplo, el cdigo des carga do de Internet, su admi ni str ador de red puede a plicar una directiv a de seguridad de empresa para prohibir esas operaciones.

Grupos de cdigo
Todos los niveles de directivas de seguridad contienen grupos de codigo que. a su vez contienen zonas par a cada g rupo de cdigo. Este resultado es un ajuste de configuracin de s eg u n d a d muy detallado a lo largo de todos los niv eles de di rec tivas v permite que haya diferentes tipos de seguridad en cada nivel de directiva, dependiendo de la zona del codigo en cuestin. Inmediatamente dentro del g rup o de cdigo se sita un nodo A l l C o d c . C omo el propio nombre indica, estos conjuntos de permisos se aplican a todo el codigo. Ade ma s de este nodo A l l C o d e . puede agregar ms nodos para sat isfa cer sus necesidades. Por ejemplo, puede crear nodos par a el codigo que recibe de los consultores o de cualquier otro tipo de fuente. Cuando evale niveles de segu nda d, no olv idc el modo en el que la directiva de codigo se evala realmente. Los permisos para un ens ambl ado se unen a cada nivel de directiva de segundad. Al unir todos estos permisos, debe t rabaj ar con nn enorme conjunto de permisos. C ada uno de estos conjuntos de permisos se solapan para que se pueda realizar una comparaci n y el valor mas restrictivo para cada permiso se usa par a el conjunto de permisos final.

Conjuntos de permisos con nombre


Un conjunto de permisos con nombre es un conjunto de permisos al que los admi ni stradores o los progr amadore s pueden as oc ia r un grupo de cdigo. Un conjunto de permisos con nombre consiste en. al menos, iin permiso y nn nombre v nna descripcin para ese conjnnto de permisos en particular. Los admi ni st rado res pueden usar conjmitos de permisos con nombre para establecer o modificar la directiva de seguridad par a grupos de cdigo, de forma parecida a como se nsan los grupos de Wi ndows NT para gestionar los grupos de usuarios. Puede asociar mas de un g ru p o con el mismo conjunto de permisos con nombre. La tabla 37 2 describe el conjunto de permisos con nombre integrado p r o p o r cionado por el entorno comn de ej ec u ci n.
Tabla 37.2. Conju ntos de permisos con nombre integrados

C o n ju n to d e p e r m is o s

D e sc rip ci n

Nothing Execute

Sin permisos (no se puede ejecutar cdigo) Permiso para ejecutarse, pero no para utilizar re cursos protegidos

812

Conjunto de permisos

Descripcin

Internet

Conjunto de permisos de directiva predetermina do, adecuado para contenido de origen descono cido Conjunto de permisos de directiva predetermina do establecido en una empresa Todos los permisos estndar (integrados) excep to el permiso de omitir la comprobacin Acceso completo a todos los recursos

Locallntranet Everything Fu IIT rust

Cmo alterar directivas de seguridad


Antes de experi ment ar realmente con tcnicas de codificado para solicitar y denegar permisos, debera familiarizarse con las herramientas disponibles para modificar las configuraciones de seguridad. Las configuraciones de s e gu n da d estudiadas hasta ahora se guar dan en archivos XML. La directiva de s egu n da d del equipo se g uar da en el archivo security .confia ubi cado en el directorio \WINNT\Microsof t .NET\ Framewor k\v:-: . \CONFIG. Las con figuraciones de seguridad del usuario se encuentran en secur ity.confiq. ubicado en el directorio \Documents and Sett inqsV-Nombro de usua-

r io:-\Applicat ion

Data\Microsof t:\CLR

Security

Conf iq\

Puede dirigirse al Panel de control, sel ecci onar Herramientas adm inis trativas y a cont inuacin, sel ecci onar Configuracin de Microsoft . N E T Fram ework p a r a m o d i f i c a r t odas sus ne c es i da de s de c o nf i g ur a c i n . Esta her rami ent a, no solo tiene varios asistentes integrados que facilitan el p roces o de c onf igur aci n, sino que resulta mu ch o mas sencilla de u sar que un editor de X ML Tras abrir la herramienta de configuracin, expanda el nodo Directiva de se g u n d a d en tiempo de ejecucin, como se muest ra en la figura 37.6. Aqu puede ver realmente los diferentes niveles de s e g un d ad , los grupos de cdigo para cada nivel, los conjuntos de permisos y los ensambl ados de directiv a. La operacin de agr egar nuevos grupos de cdigos es muy sencilla. Haga clic con el botn derecho del ratn en el cua dro izquierdo y seleccione Nuevo. Se abrir un asistente que solicitar el nombre de este nuevo g rup o de codigo y preguntara si debe ser creado como un gru po va existente o si tiene permisos personalizados (vase figura 37.7). Este asistente le gua a travs de todos los permisos disponibles e incluso le ofrece la opcion de empaqu et ar la directiva de seguridad par a distribuirla en su empresa.

813

Archivo
* -

Accin

Ver

Ayuda

.NET 'l o r i ig u r d t io n g Mi P l So) C a c h e d e e n s a m b la d o s o j E n s a m b la d o :- c o n fig u r a d o s ] S e r v ic io , r e m o to s ' D ire c tiv a d e s e g u n d a d e n tie m p o d e e ie c u c io n

%
+

E m p r e s a ______________

de cdigo + -*hGrupos ;............... :


'. c m iu n to s d e p e rm is o s _ l E n s a m b la d o s d e d ir e c t iv a E l, E q u ip o + + _ ^ l g r u p o s d e c d ig o j ^ J C c in iu n to s d e p e rm is o ? _ l E n s a m b la d o s d e d ir e c t iv a + + U s u a rio _ ^ l 'j r cipo s d e c d ig o _$J C o r n u n to s d e p e rm is o s E n s a m b la d o s d e d ir e c t iv a _T 7| A p lic a c io n e s

Figura 37.6. Herramienta de configuracin de Microsoft .NET Framework

&
Grupo de cdigo Vendor_Zone

-jg| x|

?jxj!
F- -jn.Li. a-j IJI,t il,,-. C i enera! | Condicion de pertenencia Cori|unlo de permis'

' % ..

E lt ' . i !
-

Nombre del grupo de cdigo-; I-

4^

i, - 1 , il |[ I s>

.
.

O *O

.u-.-k

Descripcin del grupo de cdigos: Tc l. ::,r,e i-:- js e d b c-c- cor jir-"C h

- ...
|,. . Icn

<> ;r .v ., JU"

-..
Vendor_Zone T a re a s

C l,c -*J " 't l!" --W o ...I, , h , . i foCOM 1- ... -,

....

_ se cumple la condicion de pertenencia: Este nivel de directiva solo te nd r los permisos del coniunto de permisos asociado a este grupo de cdigos f Los niveles de directiva por debajo de este nive! no se evaluaran

Aceprar

Caricela!

Apln: ai

Figura 37.7. Un asistente le ayuda a crear directivas de seguridad personalizadas

Resumen
N E T Framework se basa en una inmensa cantidad de codigo de s eg u nd a d que vigila cada aspeeto de una aplicacin o usuario. Este entorno de s eg u nd a d permi-

814

te al pro gr amado r y al administrador de empresa controlar lo que permite realizar a una aplicacin. Hemos estudiado las seguridades de identidad de usuario y de acceso a codigo. Si se usan conjuntamente con la seguridad del sistema operativo subyacente, puede crear aplicaciones mas seguras.

815

Parte VI

Apndices

817

A Manual de XML

A menos que haya vivido en una cueva durante los ltimos aos, ya habr odo hablar de XML. Sin lugar a dudas. X M L ha recibido inu> buenas crticas, mas de las que merece. Sin embargo, a pesar de lo que pueda haber odo en algn lustroso folleto de marketing, no es probable que XML. solucione el hambre del mundo, t raiga la paz mundial o cure todas las enfermedades. Tras leer esta seccin, d o minara las bases de X M L y sus estndares asociados, como esquemas > espacios de nombre. Ln pocas palabras. X M L es un dialecto S G M L simplificado diseado para la mteroperabilidad y esta considerado el ASCII del futuro. Ln la ultima decada. ASCII ha sido el estndar tradicional para el intercambio de datos de texto, pero esta siendo desplazado rpidamente por XML. como el nuevo estndar. A lo largo de esta seccin, apr ndel a a apreci ar la rara elegancia de XML: su combinacin nica de pura sencillez y potencia en bruto. Tambi n aprender que otros estndares complementan a XML. La familia XML de estndares compl e mentarios ha crecido mucho en los ltimos aos, de modo que. para abrc\ a i . solo le most raremos los estndares mas relevantes.

Objetivos de diseo de XML


X ML es un lenguaje de marcado que es extensiblc. Por supuesto, esto no es un gran descubrimiento dado que sus siglas significan (Lxtensible Markup Language.

819

lenguaje de mare ado extensible). pero merece la pena sealar este hecho evidente porque capta la esencia de XML. Jixlensihlc significa que puede agr egar nuev as pal abras al lenguaje para que se adecen a sus propsitos especificos. Un lengua je marcado incluye smbolos especiales en un document o para cumplir alguna funcin especfica. Esta funcin vara de un lenguaje de marcado a otro. Uno de los puntos fuertes de X M L es que sus funciones son muy amplias: sirve como lenguaje universal de texto para los datos estructurados. El Lenguaje de marc ad o de hipertexto ( H T ML ) . Lenguaje est ndar universal de marcado ( S G M L) y Formato de texto enriquecido (RTF) son otros ejemplos de lenguajes de marc ad o de los que seguramente h a b a odo hablar.

N O T A : Como XM L es un lenguaje informtico universal, se ha acuado el trmino "Esperanto para ordenadores" com o un modo de referirse a XM L. ste es un buen sm il, excepto que el esperanto no suele considerarse un xito.

Antes de introducirnos en la sintaxis y la gra m tic a de XML. merece la pena ex ami na r los diez objetivos del diseo de X ML como los estipularon sus c r e a do res. Estos objetivos se enumer an a continuacin y se explican con detalle mas adelante. Algunos de estos objetivos son de nat ural eza bastante tecnica y se aclarar an mas tarde en este apndice, cuando al gunos de los trminos que mencionan (por ejemplo, definicin de tipo de documento) sean explicados. Sin embargo, la m a yor parte de estos objetivos propor ci onan un importante entendimiento de las pretensiones de XML 1 2 3 4. 5. 6. 7. X . X M L debe ser facilmente utilizable en Internet. X ML debe admitir una ampl ia variedad de aplicaciones. X ML debe ser compatible con S G M L Debe ser sencillo escribir pro gr amas que procesen documentos XML. El numero de caractersticas opcionales en X M L debe mantenerse al mni mo. preferentemente a cero. Los documentos X ML deben ser legibles para las personas y ra zo nabl e mente claros. El diseo de XML debe ser pre para do rapidamente. El d isco de XML debe ser formal y conciso.

* -). Los document os X ML deben ser fciles de crear. 10. La concisin del marc ado XML es de mnima importancia.

820

Objetivo 1: XML debe ser fcilmente utilizable en Internet


Este objetiv o no quiere decir que los documentos X ML deban ser legibles para la actual generacin de navegadores. En vez de eso. este objetivo se refiere a una imagen ms amplia: tener en cuenta las necesidades de las aplicaciones di st ri bui das que se ejecutan en un entorno de red a gran escala, como Internet. Los servi cios We b cumplen este objetivo. Respecto a los navegadores que admiten XML. Internet Explorer 5.x y posteriores, ademas de Netscape Navigator 6.x admiten XML

Objetivo 2: XML debe admitir una amplia variedad de aplicaciones


Este segundo objetivo puede entenderse como una co nt ra part i da del primero. XML esta diseado par a funcionar perfectamente en Internet, pero no se limita a Internet. La prueba de que este objetivo se ha conseguido es la gran cantidad de dominios de aplicacin existentes fuera de la red. en las que se emplea XML. como publicaciones, intercambio de datos y aplicaciones de base de datos. A d e mas. la l apida aceptacin de X ML se ha visto facilitada por una proliferacin de herramientas: herramientas de autor, filtros sencillos, motores de pantalla, m ot o res de formateo y conversores.

Objetivo 3: XML debe ser compatible con SGML


Este objetivo se formulo para que las herramientas S G M L pudieran procesar (es decir, analizar) documentos XML. Este objetivo consta de 4 objetivos s e c u n darios: 1. 2. 3 Las herramientas S G M L sern capaces de leer v escribir datos XML. Las instancias X ML son documentos S G M L tal cual, sin cambios en la instancia. Para cualquier document o XML. se puede generar una definicin de tipo de documento (DT D) tal que S G M L pueda producir "el mismo analisis" que un procesador XML. X ML debe tener esencialmente la misma potencia expresiva que SGML..

4.

Aunque este objetivo (y sus objetivos secundarios) garant izan que un d o c u mento X ML tambin sea un documento S GM L, lo contrario no se produce: un document o S G M L NO es un documento X M L Esto es debido a que X ML no incluye muchas de las complejas caractersticas de SGML.

821

Objetivo 4: Debe ser sencillo escribir programas que procesen documentos XML
Este objetivo se media originalmente con la prueba de que un licenciado en informtica debera ser capaz de escribir un procesador X M L bsico en una o dos semanas. A postenori. este objetivo cuantitativo ha resultado demasiado ambi ci o so. pero la gran cantidad de procesadores XML disponibles (la mayoria gratuitos) es un claro indicador de que se ha conseguido este objetiv o cualitativ amente. Sin embargo, la reciente proliferacin de estndares relacionados con X M L ( X ML Schema. X-Path. X-Link. etc.) ha hecho que se comente que X ML no ha logrado al ca nzar este objetivo concreto.

Objetivo 5: El nmero de caractersticas opcionales en XML debe mantenerse al mnimo, preferentemente a cero
Este objetivo se formulo para gar ant izar que existe una caracterstica coheren te entre todos los procesadores X ML porque solo habr una caracterstica posible que impleinentar. Por tanto, cada procesador X M L existente debe ser ca paz de leer todos los document os X ML existentes (siempre que pueda decodificar sus caracteres). S GML, por otra parte, tiene muchas caractersticas opcionales en su especificacin. En la practica, esto significa que la posibilidad de i ntercambiar un document o S GML, creado con un procesador S G ML , a otro depende de las c a ractersticas opcionales i mplementadas en cada procesador.

Objetivo 6: Los documentos XML deben ser legibles para las personas y razonablemente claros
Este objetiv o habla por s mismo y tiene la ventaja de que se puede emplear un editor de texto, incluso uno muv bsico como el Bloc de notas, para crear XML fu ncional.

Objetivo 7: El diseo de XML debe ser preparado rpidamente


Este objetivo se formulo para ganar la carrera por publicar un estndar. Los creadores de X ML se dieron cuenta de que si esperaban demasiado, otra o rg ani zacin podra encontrar otro estndar

822

Objetivo 8: El diseo de XML debe ser formal y conciso


Este objetivo esta muy relacionado con el objetivo de facilitar la programacin (el n 4). Un formato de datos es fcil de usar por el usuario solamente si el p ro g ra ma do r puede entender fcilmente la especificacin. Para conseguirlo, la especificacin X M L usa una notacin empl eada por los cientficos informticos cuando describen los lenguajes informticos: Extended Backus-Naur Form (EBNF) EB NF es un conjunto de reglas, llamadas producciones C ad a regla describe un fragment o especifico de sintaxis Un document o es vlido si puede ser reducido a una sola regla especfica, sin ni nguna entrada libre, mediante la repetida aplicacin de las reglas

Objetivo 9: Los documentos XML deben ser fciles de crear


Este objetivo ampla los objetivos 4 y 6. Aunque un editor de texto es perfecto para pequeos documentos XML. los documentos grandes se crean mas fcilmen te usando las herramientas especficas. Este objetivo expresa la intencin de dise ar X ML para que sea sencillo p ro gr a ma r y crear sistemas de edicin XML.

Objetivo 10: La concisin del marcado XML es de mnima importancia


Este objetivo indica que. cuando se deba elegir entre la claridad y la concisin, se prefiera la claridad.

Breve leccin de HTML


Como H T M L es muy parecido a XML. le ofrecemos una breve sinopsis de este lenguaje. Si ya conoce H T M L , la curva de aprendizaje de X M L sera menos p r o nunciada. (Si no conoce H T M L , no se preocupe, le explicaremos todo paso a paso.) Para simplificar la presentacin, nuestra explicacin de H T M L omite a l gunos detalles (por ejemplo, puede sugerir que algo es necesario c uando en reali dad es opcional) y se limita a lo que tiene en comn con XML. Por supuesto, ya es consciente de la principal diferencia entre los dos lenguajes: X M L es extensible mientras que H T M L no lo es (esto se explicara posteriormente). H T M L es el lenguaje usado par a describir pginas Web. Una p a g in a Web es un document o que contiene marc ado re s especiales, llamados elupieias. que dcfi-

823

non como debe ser present ado el contenido en un n avegador Web. Un m ar cad or inicial y un marc ado r final (a partir de ahora los l lamaremos etiquetas) rodean al contenido, por ejemplo: <etiqueta>contenido<7 etiqueta X La etiqueta inicial, el contenido y la etiqueta final reciben el nombre de e le mentos. La etiqueta inicial y la etiqueta final estn rodeadas por comillas a n gu l a res ( v ' '* ). La etiqueta final usa la misma pal abr a contenida en la etiqueta inicial precedida por una barra diagonal ( / ). De modo que si la etiqueta inicial es font o la etiqueta final debe ser </font>. Ln XML. las etiquetas distinguen entre mavuscul as y minsculas, de modo que las pal abr as usadas en las etiquetas ini cial v final deben tener los mismos caracteres. Por tanto, en XML. no puede usar font ' (con / minscula) en la etiqueta inicial y <7Font> (con b mayscul a) en la etiqueta final. Ln H TM L, las etiquetas no distinguen entre mayscul as y mi n s culas. de modo que se aceptan etiquetas con diferente liso de maysculas y mi ns culas. Ln H T ML , las etiquetas que se pueden usar estn predefinidas. Ejemplos de etiquetas H T M L son h l U:hl.-> y < / h l >) para Header 1 y b (<b> y < /b ) para negrita. Conocer H T ML significa saber cuando usar cada etiqueta predefinida. Por ejemplo, par a que la p a l ab r a "Abbrevi at ion" a p a re z ca en negrita en el nav egador, escribira ' b Abbreviat ion</b >. C uan do el navegador lee esta combinacin de etiqueta y contenido, elimina las etiquetas y muestra el contenido en negrita. Una combinacin aleatoria de etiquetas H T M L y contenido no suele producir un documento HTML, valido. Una pagina H T M L debe tener una cierta estructura El contenido del document o debe estar entre < h t m l > y < / h t m l > y consta de una cabecera y un cuerpo. Cada una de estas secciones esta delimitada por etique tas (llamadas, evidentemente, cabecera y cuerpo) y tienen contenido, que puede estar rodeado por etiquetas de presentacin. El listado A. 1 muestra la estructura de un d ocument o HTML., Casual ment e, este listado tambin muest ra como se incrustan comentarios en lina pagina HTML: < ! --EL COMENTARIO SE SITUA

AQUI
N O T A : Los comentarios se pasan por alto y no afectan a la presentacin de la pgina en el navegador. Slo se usan para mostrar informacin al lector humano del cdigo fuente HTM L. A lgunos com entarios contienen cdigos especiales que pueden comprender programas especficos (Por ejem plo el servidor W eb), pero esto queda fuera del alcance de esta breve exp li cacin de HTML.

Listado A.1. Estructura de un documento HTML


ht mi h ead

824

- ! --S IT U E / h c d el " > - Id o el y ' - ! - SITUE

AQU

EL

CONTENIDO

DE

I,A

CABECERA

AQUI

EL

CONTENIDO

DEL

CUERDO

- / b o el y ,/htm l

H T M L tambin consta de un mecani smo para agr egar mas informacin a una etiqueta, llamados atributos. Un atributo especifica una propiedad que pertenece a una etiqueta, como el t amao de una fuente Por ejemplo para que la palabra "Meaning" ap arez ca con t amao 4. debera escribir
f ont s i ~ e - " 4 -M eaiiing/ fo n t

C omo puede ver en el ejemplo anterior, los at ri but os se escriben en la etiqueta inicial \ hay un espacio de separacin entre el nombre de la etiqueta \ el nombre del atributo. Estos toman la forma
n o mb r e a t r i bu t o -v a l o r c: a el e : a

o mos tran do el elemento por completo:


- e ticjiie ta nombre a trib u to valo r oatkna <- o r . t f-u. i
do-

/ - - r i qwr-t. a -

En H TM L, estn predefinidos los atributos que puede usar con cada etiqueta, igual que las etiquetas. La etiqueta fuente, por ejemplo, tiene un atributo de t a m a o. Los valores de atributo deben estar entre comillas dobles o sencillas (no im porta cual de las dos use. mientras las comillas de apert ura sean del mismo tipo que las de cierre). Una etiqueta puede contener mas de un atributo Cada atributo esta separado por un espacio. Por ejemplo, quizas quiera especificar el borde, altura y anchura de una tabla, por ejemplo

En realidad. H TML tambin acepta \ alores de atributo que no estn entre comillas. XML. por el contrario, necesita las comillas H a b a observado una tendencia: XML, tiene un conjunto de reglas mas estricto que HTML. El listado A . 2 muestra un sencillo document o HTM L, mezclando etiquetas (algunas con uno o mas atributos) con contenido. En caso de que este intentando descifrar las etiquetas H T M L de este documento, aqu se muestra la creacin de una tabla H T M L (una tabla H TML tiene el aspecto de una tabla en un procesador de texto). La tabla esta encerrada en una etiqueta t o o i o . Cada fila esta encerrada en una etiqueta - t r (fila de tabla). En cada fila se crea una celda usando la etiqueta < t d (divisor de tabla). El resto del documento H T M L se explica por s mismo. (No se preocupe si no entiende algn detalle al leer este documento H TM L. Esta seccin es sobre XML. de modo que trata H T M L de un modo superficial.)

825

Listado A.2. Un s e n c i l l o d o c u m e n t o H T M L
'lit ml head.title .-A G lo ssa ry in HT ML <' / 1 1 1 1 e >

'/head
body a 'h 1 >G 1 os s a r y < / h 1 > cl l v a 1 l g n = " 1 e f t " w i d t h - " 35 S" he l g h t = " 1 1 0 " > <tab.le b o r d e r - " 1 " t r - td " b.-"" f o n t - td

w id t h -"125"

h e lg h t="22">

s l z e = " 4 " > A b b r e v i a t l o n < / f o n t :>< / b : h e lg h t = "22">

w idth="234"

- b "' f o u t </ td > / 1. r t r td

s l ze= " 4 " >M eam ng< / f o n t x /b >

w id th = " 125 " ADO

h e i g h t . - " 2 2 ">

" / t d , td w id t h - 234" ' b > A ' / b > ct.ive h e ig h t -" 22"> b :> D < / b > a t a < b > 0 < / b > b j e c t. s

" t. r -'t d w i d t . h = " 1 2 5" he i g h t = " 2 2 " > SOAP " / t d rtd i
cj t.

wi d t h = " 2 3 4 "

he i gh t = " 2 2 " > - b . - G < ' / b > b j e c t <b>A< / b > c c e s s < b' * P-

b -S- / b - i m p l e oo 'o L / t d "/ t r t r :> 'td w i d t h = " 1 2 5 " UDA - td w i d t h = 2 34 "

he i g h t = " 2 2 " >

h e i. g h t = " 2 2 " > 'b > P < / b > a t a < b > A< / b > c c e s s

- b >U < . / b ii i v e r s a 1 7td/ 1 r t r ' td w i d t h - " 125"

h e ig h t = "22">

ZML
/ td - td wi dt . h = " 2 34 " he i g h t = " 2 2 " > <b>M< / b > a r k u p <b>L</b>anguage
c - ' . b ' / . <

/b .-te n sib le

/ t r> < :/ tabl e>

< / el i v >
/ bod y > / h t m 1 .>

XML = HTML con etiquetas definidas por el usuario


Ahora estudiaremos X ML y expl icaremos los detalles que no se explicaron con anterioridad, de modo que pueda crear su pri mer document o XML. Un d oc u mento XML consta de tres partes: prologo, cuerpo y epilogo. Solo es necesario el cuerpo del documento. L1 prologo y el epilogo pueden omitirse. Lsta es la est ructura basica de un documento XML: Prlogo:
Dc c l a r a c i o n - !--S itu Document !-Srtue XM L (o p c io n a l! lo s lo s co m en tarios co m e n tario s - -- -- (o pt.io nal) aqu Type aqu

D e cla ra tio n

Cuerpo:
Document !-Elem ent aqu el documento "Document > S itu /D o cum ent >

Eplogo:
' !-S itu aqu lo s co m e n tario s-- >

Un document o X M L comienza con un prlogo. Si excluimos los comentarios opcionales, el prologo contiene dos elementos principales (que tambin son opcio nales). La declaracin X M L necesita un atributo, que s i r\ e para especificar la versin de la especificacin X M L a la que se ajusta el documento. La declaracin X ML tambin tiene dos atributos opcionales: uno para especificar la codificacin de ca rcter usada y otro para especificar si el document o depende de una defini cin de tipo de document o (DTD). A continuacin tiene un ejemplo de una dec la racin X ML completa que usa los tres atributos.
- ?xml v ers i o n = " 1.0" encoding-"UTF- 8 " st a n d a l o n e - yes " ? -

Los atributos de la declaracin X ML deben usarse en el orden que aparece en el ejemplo. El atributo de versin es obligatorio y debe tener el valor "1.0". La

827

codificacin de carcter de los document os X ML y las definiciones de tipo de document o se explican mas adelante. F1 elemento de document o debe estar entre la etiqueta de raiz. En el ejemplo anterior, esta etiqueta de raz es la etiqueta < D o c u m e n t o , pero puede usar cu a l quier etiqueta para encerrar al elemento de documento. Por ultimo, todas las etiquetas de un document o X M L deben anidarse adecuadament e. Si un elemento esta contenido en otro elemento recibe el nombre de secundario \ el elemento cont enedor recibe el nombre c /)rim a n o . Aqu tiene un ejemplo:
'B o o k ( : a t e y o r y - " C h e s s " ' .7 y s t e n r / T ; t 1 e . N i mn o v / i t s c h - ' / A u t . h o r T i t l e -My /Book

' Aut h or A r on

Hn el ejemplo anterior la etiqueta < B o o k > es primaria para dos secundarias, los elementos A u t h o r y Ti t l e . La anidacin correcta requiere que los elementos secundari os esten siempre contenidos en sus elementos primarios. Fn otras pal abras, la etiqueta final de un elemento secundario no puede aparecer despus de la etiqueta final de su elemento primario, como en el siguiente ej em plo:
Book T i t. 1 e - I rnp r o p e r
/BoX;

I l e s t r.cj

ir*

X ML

E x p la in e d

F'l epilogo, que solo puede contener comentarios (ademas de espacios en b l an co e instrucciones de proceso), suele omitirse. Va esta preparado para un primer acercami ent o a un document o XML. como el most rado en el listado A . 3. Los nmeros de linea no forman parte del documento y solo aparecen para poder hacer una explicacin linea a lnea posterior mas sencilla.
L is ta d o A .3. Sencillo documento XML
_ : ;-:ii i X : 1 X ! 7 : : 7 : 7: c : X i: 11: 17: I X 14 : 1 7 : ve r s on " I . u" enood i n y - " UTF
o"

stancia 1 one - " y e s " ? PGB - -'

I,i s t a - B lin io s :on,p lado e i X Book 1 XB X -'X -/.MI,

s o b r e XMI. r e c o m e n d a d o s - - e M ar:;; del 17, 7 iXX) p o r

4 : XMBBooks '/ 7 ' / - 7 7 4 7 - c-; " By E a mp 1 e - / T i t 1 e > Ha r ch a 1 / Au t h o r L e v e 1 opr nent *. / C a t e q o r y Ti t le

C a t e q o r y - Web A u t h o r ' B e m i t -/B o o k > Book

1 .7 B U - " i - 8 1 < i .3 - 1 1 - 0 " > XML o/T it le

T i t 1 e -P r o f e s s i on a 1 - ' l a t e y o r y I n t e r n e t

- (7a t e q o r y ' I n t e r n e t ' , / C a t e g o r y > P r o y r a mm i i i c j \ / C a t e g o r y > ' C a i - e g o r y "*XMT,< / C a t e g o r y ^ ' A u t ho r P r ohard Anders one/ Author >

828

le : 17: 18: 19: 20: 2] : 22: 2 3 : 2 4: 23 : 2 r : 27 : 28: 2G: 3 (.) : 31 : : 33 :


i

\A uthor>M ark

B u b e c k - /A uthor -

<Author>M i chael Kay-' / A u t h o r - ;A u t h o r >S t e v e n L iv in g s t o n e - /A u tlio r <Author>Br a n A u t h o r >D d i e r A u t h o r >S t e p h e n < A u th o r> N ik o la < Au t h o r > B r u c e < Au t h o r > P e t e r < Au t h o r > K e v r n -o / B o o k > < Book I S BN = " 0 - 7 3 5 > : - 5 < : 2 - c- " m A c t i o n - / T i 1 1 e .*.T i 1 1 e > X ML -"Author > J o n a t h a n L o e s gen< / A u t h o r M artin '7A u th o r> M o h r/A u th o r
0 : u < /A uth o r

P e a t -" / A u t h o r P m n o c k -' / A u t h o r S t a r k / 7 Au t h o r W i l l i a m s ' - ' / A u t h o r -

< "C a t e g o r y > I n t e r n e t < / C a t e g o r y - C a t e g o r y >XML- ' / C a t e g o r y > --Author -> W illia m ' /Book > / XMLBooks> J. Pardy- /Aut.hoi -

34:

La linca ldcl listado A . 3 contiene una declaracin completa X M L que incluye los tres atributos. Las lineas 2 y 3 son comentarios usados en este caso para indicar la funcin de este documento. A continuacin esta el cuerpo del d ocumen to XML. empezando por la linea 4 v terminando en la linea 34 Hste documento no tiene epilogo, como suele ser habitual. El elemento de document o esta entre la etiqueta - . . X M L B o o k s ( l a etiqueta de inicio esta en la linea 4. la etiqueta final en la linea 34). El elemento de documento tiene tres secundarios, cada uno encerrado entre una etiqueta ' - B o o k \ El secundario 1 empieza en la linea 5 > finaliza en la linea L ). El secundario 2 empieza en la linea 10 5 y finaliza en la linea 27. El secundario 3 empieza en la lnea 28 5 y finaliza en la lnea 33. C ada elemento Roo): - tiene un atributo ISBN y una cantidad de secundarios: uno Ti t i - . uno o mas - . C a t e g o r y > y uno o mas A u t h o r . Aqu puede apreciarse una ventaja significativa de XML sobre los tradicionales archivos de texto: XML esta bien preparado para tratar con las estructuras primario/secundario. Como creador del documento, merece la pena sealar que yo invent las eti quetas y los atributos usados en este documento ( XMLBo ok s. Book. ISBN. Title. C a t e g o r y . A u t h o r ) . Po r e j em p lo , o t ro a u t o r p o d r a h a b e r p r e f e r i d o u s a r S h e 1 v i n q C a t e q o r y> en lugar de " - C a t e g o r y - ' . Tambi n puede hacerlo usted mismo si esta especificacin X ML llega a al ca nzar el objetivo numero 6 (los documentos X ML deben ser legibles par a las personas y razonablemente claros).

Definiciones de tipo de documento


El document o X M L mos trado en el listado A . 3 tiene una est ructur a mas defi nida que la est ructura impuesta por XML. Una definicin de tipo de document o

829

( DTD) propor ci ona un modo de cspccificar esta estructura, el modelo de datos correspondiente al modelo de datos. Se puede realizar la compar aci n con un esquema de base de datos que defina el modelo de datos de una base de datos. Esta compar aci n funciona perfectamente porque tanto una base de datos como un document o X ML contienen datos estructurados. La DTD es el esquema co rr es pondiente al document o XML. El listado A.4 muestra la DTD correspondiente al listado A.?.
Listado A .4. Esquema DTD correspondiente al documento XML
?y .m ! vcisin " 1 . 11" ?

! - -

El

o 1 e r nen t o es una

s u p e rio r , lista de lib ro s (Book+j >

ZHLEoks, ! ELEMENT ! y Un

XMLBook.s Rook 1

elem ento 1 T itle , Author Book

co n tien e 1 o mas ! ELEMENT !-Un

mas

Category,

(T it 1e , C a te g o ry 4 ' , Author+) > 1 a trib u to Ib


#

Book

tiene ISBN

re q u e rid o

!ATTL IS T !-Los

Book

PEQU I RED > Category, y Author

elem ento s texto --

T itle ,

co n tien en ! ELEMENT ! ELEMENT ! ELEMENT

T i t le ( # PC D A T A ) > C a t e go r y ( # PC D A T A ) Author (#PCDATA)

La est ructura de la DTD es muy parecida a la de Extended B acku s- Naur Form menci onada anteriormente. La DTD es un conjunto de reglas sucesivas que d es criben como en sa mb la r los datos en el modelo de document os XML. Cada regla describe un elemento especfico o un at ri but o que el modelo puede contener. Un document o X ML es vlido si puede reducirse a una sola regla especifica de la D I D . sin ni nguna entrada libre, mediante la repetida aplicacin de las reglas. A continuacin tiene una descripcin de la sintaxis usada en esta DTD. O b s e r ve que la D TD usa una sintaxis diferente de la de los documentos XML. C ad a elemento se describe us ando una lnea de descripcin de elemento.
- ! ELEMENT elem ent name (elem ent content)>

element n a m e us a la e t i q u e t a p a r a i d en t i f i c a r c a d a el eme nto . En e l e m e n t c o n t e n t , debe colocar otros elementos o # PCDATA para indicar

que el elemento contiene texto. Los elementos hoja son elementos que no tienen s e c u n d a r i o s . Es tos e le me n t o s suel en e s p e c i f i c a r s e c om o c o n t e n e d o r e s de # PC DATA. Los caracteres especiales tras un nombre de elemento indican la cardinalidad de los elementos contenidos. La cardinalidad indica cuntos de estos elementos

830

pueden existir y si el elemento es opcional o necesario. Ha\ cuatro modos de indicar cardinalidad. Un elemento contenido sin ningn simbolo especial (como T i t ; o en el listado A. 4) debe a pa rec er exact ament e una vez en el elemento que se define (cardinalidad: 1). Un elemento contenido seguido por un signo de interrogacin ( ., ) es opci o nal y solo puede apa rec er una vez en el elemento (cardinalidad: ().. 1). Los siguientes dos modos definen elementos repetidos, uno para los requeridos y otro p ar a los opcionales. Un elemento contenido seguido por un signo de adicin (4 ) (como Boo k .y A u t h o r en el listado A . 4) es n e c es ar io y puede a p a r e c e r repetido (cardinalidad: 1..N). Un elemento contenido seguido por un ast erisco (*) (como C a t . e g o r y en el listado A. 4) es opcional y puede aparecer repetido (cardinality: 0..N).
!ATT L IS T elem ent ame a ttrib u te ame a ttrib u te conten opt. i o n a i 1 1 y '>

Las listas de atributo se definen en una lnea separada, e l e m e n t a m e es de nuevo la etiqueta a la que pertenece el atributo, a t t r i b u t e _ rame es el nombre del at ri but o (Por ejemplo. ISBN en el listado A . 4). L1 contenido del at ri buto se define usando una serie de pal abr as clave. La mas comn es ( DATA que indica que el atributo recibe datos de carcter. La opcionalidad se indica mediante la pal abra clave # R E Q U I R E D para los atributos necesarios y # I M P L I E D para los atributos opcionales.

Esquemas XML
El 2 de Mavo del 200 1. el consejo encargado de controlar los estndares XML anuncio que un importante miembro de la familia X ML haba alcanzado el estatus de est ndar (una recomendacin propuesta, como www . w3 . o r c j lo llama). Este est ndar recibe el nombre de Esquemas X ML v esta destinado a reemplazar a la DT D como el sistema preferido de validar d ocument os XML. Esquemas X ML ofrece dos ventajas evidentes sobre la DTD: Un esquema X M L es un document o X ML Los esquemas XML permite especificar las caractersticas de datos (como tipo, t amao y precisin) de los elementos y atributos Un document o de es que ma tiene este aspecto:

831

- ?

in 1

v e r s ion - " 1 . 0 "

eneoclm g= "U T F -8 " ? >

- x sd : s chema ! .Situ

xinlns : x s d - " h t t p : / / aqu el contenido

www w 3 . o r g / 2

0 0 1 / X M L S c h e m a " .>

del

e sq u e m a -->

,sd : s c h e m a

El atributo x m i n s : : : s d de 1 elemento de esquema es una declaracin de n o m bre de espacio, que est udi aremos en la siguiente seccin. Observe que el valor de este at ri but o ha cambi ado a lo largo del tiempo, de modo que si se encuentra con un esquema con un valor diferente en este atributo (por ejemplo, www . w3 . e r g / / : n i u / i u / . >]L , s c h e m a ). ese esquema fue creado correctamente de acuerdo con una \ c i s i n de borr ador del estndar Esquema XME. El contenido del esquema consta de definiciones para los elementos y atributos que el esquema puede contener. Un elemento se define como se indica a con ti nu a cin
x s d : elomenf. ! - 1 1 ue aqu "ame- " t h e E i e m e n t 1
o s l l a m e

" del e i emento

d e ta lle s

e s p e c il ic o s

/ x s d : e 1 ' Cl i ent

v un at ri but o se definen como se indica a continuacin


! / s d : a t. t i b u t e ' d t Ur sd : aqu n a r n e = " t: h e A t t c i b u t e N a m e " ' io s o e ta lle s e sp e cfico s del atubuto-

a t n b u t. o

Puede a gr egar document aci n con comentarios o insertar un elemento de a n o tacin dentro del elemento o definicin de atributo. El elemento de anotacion contiene un elemento de documentacin en el que puede explicar los detalles es pe cficos del elemento o del at ri but o
x..: o : a 11 n t <i : , ' i x s I : do - un- !';* a
t

e n r-'ome f x p l ar.at i o n h e re...- / x y d : d o c u m e n t at u s o

/ x s o : d i n i ">t a t : n n -

-orno

Puede a gr u pa r los elementos y los atributos insertndolos en una etiqueta . f ::'/yr, .


'mp 1 x . T y p c / x s d : c a u i d --x.T y r ; -

xs d :

Fste tipo de agrupacin es necesario cada vez que se encuentra con una defini cin de elemento como la siguiente:
! ELXMEMT Boc-k T i t 1 p , C a t e q o r y * , A u t h o r t ) '

Los elementos a gr upados en una secuencia deben ser most rados en el orden en el que estn definidos

832

<xsd :seq u en ce> < / x s d : sequence>

As. si define un elemento Book como se indica a continuacin, el elemento Book debe contener los elementos Title. Category y Author exact ament e en este orden (por ejemplo. Title. Author y Category no sera vlido).
< x s d : elem ent name="Book"> x s d : c omp1 e x T yp e > < x s d : sequence> < xsd :e le m en t < x s d : elem ent < x s d : elem ent
< /

n a m e = " T i t l e "> name = " C a t e g o r y " / > name="A u th o r"/>

< / xs d :element >

xsd:sequence>

< / x s d : c om plexType> < / x s d : ele m e n t>

Se considera que la cardinalidad de los elementos es uno. Si quiere crear un e le m e n t o r e p et i do r, p u e d e h a c e r l o a g r e g a n d o el a t r i b u t o m a z O c c u r s = "unbounded" a la definicin del elemento. Si quiere cr ear un elemento o p ci o nal. puede hacerlo agregando el atributo minOccurs= " 0 " a la definicin del elemento. Por supuesto, puede c ombi nar estos atributos par a crear un elemento repetidor opcional. Finalmente, puede especi fi car el tipo de datos de un elemento con el at ri but o type= "xsd :datatype " . En nuestro ejemplo, slo usamos el tipo de datos de cadena. El esquema X M L permite una gran variedad de tipos de datos, como entero, largo, fecha, hora, doble, flotante, etc.El listado A . 5 enumer a el esquema X M L correspondiente a la DT D menci onada anteriormente. La extensin de a r chivo de esquemas X M L es xsd y por eso a veces se les llama XSD.
Listado A.5. E squema XML correspondiente a DTD
<?xm l v e rsio n = "1.0 " W3C para e n c o d x n g = " U T F - 8 " ?> una lis t a de lib ro s -->

< ! --Esquem a < x s d : s chema

x m l n s : x s d = " h t t p : / / www. w 3 . o r g / 2 0 0 1 / XMLS c h e m a "> n a m e = " X M L B o o k s "> to p -le v e l elem ent,

< x s d : elem ent

< x s d :a n n o t a t i o n >
< x s d : d o cu m e n t tio n > T h e

XMLBooks, is a list of </xsd:annotation>


< x s d : co m p lexType>

b o o k s .</ x s d :d o c u m e n t a t ion>

< x s d :s e q u e n c e >
<xsd :e le m en t name="Book" m a x O c c u r s = " u n b o u n d e d "> Book more elem ent co n ta in s i

< x s d :a n n o t a t i o n >
< x s d : do cu m en tatio n> A T itle , 1 or more Category, and 1 or x s d : d o cu m e n tatio n > < / x s d : a n n o ta tio n > < x s d : com p lexT ype> A u th o r.</

833

<xs d : sequence> < x s d : elem ent n am e = "Title " typ e="xsd :strin g " > T itle , Category, < x s d : a n n o ta tio n > < x s d : docu m en tatio n>Th e and Author e lem ents co n tain < /x sd :an n o ta tio n > < / x sd :ele m e n t> < xsd :e le m en t ty p e = " x sd :strin g " m in O c c u r s = "0" < x s d : elem ent ma x O c c u r s = " u n b o u n d e d " / > </x s d : sequence> <x sd :a ttrib u te u se = "re q u ire d " name = " I S B N " type = " x s d :s t rin g " id = "isb n "> < x s d : a n n o ta tio n > < x s d : docum entat 1 on>A a t t r i b u t e . < / x s d : d o cu m e n t a t 1 on> < /x sd :a n n o ta tio n > < / xs d : a ttrib u te > < / x s d : co m p lexType> < / x s d : elem ent> < / x s d : s e qu en c e> < / x s d : co m p lexType> < / x s d : e l e me n t > ' ' / x s d : s c h e ma > Book has 1 req u ire d nam e="Category" m axOccurs = "unbounded" /> nam e="Author" type = " x s d : s t r in g " t e x t . < / x s d : d o cum en tatio n>

El listado A . 6 mues tra cmo un document o X M L puede hacer referencia a su esquema X M L asociado.
Listado A .6. Docum ento XML que hace referencia a su esquema XML asociado
<?xm l v e r s io n = " 1.0 " e n c o d i n g s " U T F -8 " ?>

<XMLBooks < B o ok

x m l n s : x s i = " h t t p : / / www. w 3 . o r g / 2 0 0 1 / XMLS c h e m a - i n s t a n c e "

x s i : n o N a m e s p a c e S c h e m a L o c a t i o n = " . / B o o k s . x s d ">

IS B N = " 0 - 7 8 9 7 - 2 2 4 2 - 9 " >


By E x a m p le < /T itle > D e v e l opment < / C a t e g o r y > M a r c h a K /A uth or>

< T 1 1 1 e >XML

< C a t e g o r y ) - We b <A u t h o r >B e n o it < / Book >

<Bo o k

I S B N = " 0 - 7 3 5 6 - 0 5 6 2 - 9 ">
m A c tio n < /T itle >

<T itle > X M L

<C ateg ory>Internet</Category> ^Catego ry;-X M L</Catego ry> < A u t h o r > W i 1 1 1 am < / Book> < /XM LBooks > J. Pardy</Author>

Espacios de nombre XML


La extensibilidad de X M L es. a la vez, una bendicin y una maldicin Al permitir a cualquier persona crear sus propias etiquetas se corre el riesgo de crear

834

una nueva torre de Babel. Afortunadamente, los progr amadores de los estndares X M L percibieron el peligro e idearon una solucin, llamada espacios de nombre. Ya conoce el concepto de los espacios de nombres graci as a su estudio de C# (el mismo concepto aparece en C + +. Java y otros lenguajes NET) La implementacin varia un poco entre un caso y otro, pero la idea es siempre la misma. Se asocia un nombre nico a un prefijo y se usa este prefijo par a calificar los nombres que podran colisionar sin el prefijo. C omo X M L esta basado en Web. los diseadores decidieron us ar URL como los nombres nicos. El espacio de nombres usado en un es que ma X M L se especifica agregando el atributo targetNamespace= "www .myurl .com" al esquema. Este espacio de nombres se define agr egando un at ri but o especial xmlns al elemento de es quema. Puede anexar el prefijo de espacio de nombres usando dos puntos para separar el atributo xmlns de prefix. El di seador del esquema debe a s e g u r a r se de que el valor de este atributo es nico. Esto suele conseguirse usando la URL de la compaa.
x m l n s : p r e f i x = " h t t p : / / www. myu r 1 . com"

Ti as definir un prefijo de espacio de nombres, debe anexarlo a todos los ele mentos contenidos en el espacio de nombres.
? xm. l ve rsio n ^ " 1.0 " encoding=" U T F -8" ? > E s q u e m a W3 C p a r a u n a l i s t a de l i b r o s

<. X s d : s c h e m a t a r g e t Na me s p a c e = " w w w . m y u r 1 . c o m x m lns : x s d = " h t t p : / / ww w,w3. o r g / 2 0 0 1 / X M L S c h e m a " x m l n s : b o o k = " www. myu r 1 . c o m " > < x s d : e 1 ement name = " XM LB o o ks " > to p -le v e l elem ent, < x s d : a n n o t a 1 1 on> < x s d : d o cu m en ttio n>The XMLBooks, is a lis t of < / x s d : a n n o ta tio n > < x s d : c omp1 e x T yp e > <x s d : sequence> < x s d : elem ent name = " Boo k " ma x O c c u r s = " u n b o u n d e d " > Book more elem ent co n tain s 1 < x s d : a n n o t a 1 1 on> < x s d : document at i on>A T itle , 1 or more Category, and 1 or x s d : docum entt io n > < / x s d : a n n o ta tio n > < x s d : c om plex T yp e > <xsd :sequ en ce> <xsd :e le m en t name = " T i t l e " t yp e = "x s d : s t r i n g " > T itle , Category, < x s d : a n n o ta tio n > < x s d : document at i on>The and Author elem ents co n tain < / x s d : a n n o ta tio n > < /x sd :ele m e n t > <xsd :e le m en t t ype= "xsd : s t r m g " mmOccur s = "0" nam e="Category" m axOccurs = "unbounded"/-t e x t . < / x s d : d o cu m e n t tio n> A u th o r.< / b o o k s . < / x s d : d o cu m en tatio n ^

835

<xsd :e le m en t m axOccurs = "unbounded"/> < /x s d : sequence> < xsd : a ttrib u te u se = "re q u ire d " id = "isb n ">

nam e="Author"

ty p e = "x sd :strin g "

nam e=ISBN "

typ e="xsd : s trin g "

< x s d : a n n o ta tio n > < x s d : do cu m en ta tio n> A a t t r i b u t e . < / xs d : do cum ent a t i on> < / x s d : a n n o tat io n > < /x sd :a ttrib u te > < / x s d : com plexType> < / x s d : e lem en t> < /x sd :se q u e n ce > < / x s d : c omp1 e x T y p e > < /x sd :e le m e n t > < / x s d : schema> Book has i re q u ire d

El siguiente document o X M L mu es tra cmo cr ear un document o X M L que haga referencia a un esquema usando nombres de espacio. Esto se consigue a g r e gando tres atributos al elemento de raz. El primer atributo define el prefijo usado por el espacio de nombres y la cadena nica a soc ia da a este espacio de nombres. El segundo atributo especifica qu versin del es que ma X M L se est usando. Por ltimo, el tercer atributo le indica qu espacio de nombres est usando el esquema X M L y dnde est ubi cado el es que ma XML.
<?xm l v e rsio n = "1.0 " e n c o d i n g = "U T F - 8 " ?> < b o o k : XMLBooks x m l n s : b o o k = " www. m y u r l . c o m " x m l n s : x s i = " h t t p : / / w w w . w 3 . o r g / 2 0 0 1 / XMLS c h e m a - m s t a n c e " x s i : s c h e m a L o c a t i o n = " www. m y u r l . com <Book I S B N = " 0 - 7 8 9 7 - 2 2 4 2 - 9 "> By E x a m p le < /T itle > Deve 1 o p m e n t < /C a te g o ry > M archa1 < /A u th o r> < Title > X M L . \B o o k s . xsd">

< C at egory>W eb <A utho r>B eno it < /Bo ok> <Book

I S B N = " 0 - 7 3 5 6 - 0 5 6 2 - 9 "> m A c tio n < /T itle >

< Title > X M L

<C ateg ory>In ternet</Categ ory> <Category>XM L</Category> < A u th o r> W lllia m < / Book> < / b o o k : XMLBooks > J. Pardy</Author>

Como la mayor a de los elementos de un documento X M L pertenecen al mismo espacio de nombres, se puede crear un espacio de nombres predet ermi nado y omitir el prefijo del espaci o de nombres, por ejemplo, x m l n s ="www . m y u r l . c o m " . Para terminar, se pueden incluir varias declaraciones de espacios de n o m bres en el mi smo document o XML. Esto se consigue a gr egando todos los a t r i b u tos de espacio de nombres al elemento de raz. No obstante tenga en cuenta que un document o slo puede a pu n ta r a un es que ma XML.

836

S-ar putea să vă placă și