Está en la página 1de 237

Tutorial C#

Introduccion a C#
Origen y necesidad de un nuevo lenguaje
Caractersticas de C#
Programacion con C#
Hola Mundo!
Puntos de entrada
Compilacin en lnea de comandos
Compilacin con Visual Studio
undamentos de C#
Comentarios
Identi!icadores
Pala"ras reservadas
#iterales
Operadores
Instrucciones
Concepto de instruccin
Instrucciones "$sicas
%strcuturas de control&
Instruccin i!
Instruccin s'itc(
Instruccin '(ile
Instruccin do&&&'(ile
Instruccin !or
Instruccin !oreac(
)e!inicin de clases
Conceptos de clase y o"jeto
Sinta*is de de!inicin de clases
Creacin de o"jetos
Operador ne'
Constructor por de!ecto
+e!erencia al o"jeto actual con t(is
Herencia y m,todos virtuales
Concepto de (erencia
#lamadas por de!ecto al constructor "ase
M,todos virtuales
Clases a"stractas
System&O"ject
Polimor!ismo
Concepto de polimor!ismo
M,todos gen,ricos
Operador is
-cceso a la clase "ase
)o'ncasting
Clases y m,todos sellados
Ocultacin de miem"ros
Miem"ros de tipo
%ncapsulacin
%spacios de nom"res
Concepto de espacio de nom"res
)e!inicin de espacios de nom"res
Importacin de espacios de nom"res
Sentencia using
%speci!icacin de alias
%spacio de nom"res distri"uidos
Varia"les y tipos de datos
)e!inicin de varia"les
.ipos de datos "$sicos
.a"las unidimensionales
.a"las multidimensionales
#a clase System&-rray
Cadenas de te*to
Constantes
Orden de iniciali/acin de varia"les
M,todos
M,todos e*ternos
Constructores
)estructores
Propiedades
Indi/adores
+ede!inicin de operadores
)elegados y eventos
Concepto de delegado
)e!inicin de delegados
Manipulacin de o"jetos delegados
#a clase Multicast)elegate
#a clase System Multicast)elegate
#lamadas asncronas
#lamadas asncronas
Implementacin interna de los delegados
%ventos
Concepto de evento
Sinta*is "$sica de de!inicin de eventos
Sinta*is completa de de!inicin de eventos
%structuras
Concepto de estructura
)i!erencias entre clases y estructuras
0o*ing y un"o*ing
Constructores de estructuras
%numeraciones
Concepto de enumeracin
)e!inicin de enumeraciones
1so de enumeraciones
#a clase System&%num
%numeraciones de !lags
Inter!aces
Concepto de inter!a/
)e!inicin de inter!aces
Implementacin de inter!aces
-cceso a miem"ros de una inter!a/
-cceso a miem"ros de inter!aces y "o*ing
%*cepciones
Concepto de e*cepcin&
#a clase System&%*ception
%*cepciones prede!inidas comunes
#an/amiento de e*cepciones& Instruccin t(ro'
Captura de e*cepciones& Instruccin try
Instruccin t(ro'
Otras instrucciones
Instrucciones c(ec2ed y unc(ec2ed
Instruccin loc2
Instruccin using
Instruccin !i*ed
-tri"utos
Concepto de atri"uto
1tili/acin de atri"utos
)e!inicin de nuevos atri"utos
%speci!icacin del nom"re del atri"uto
%speci!icacin del uso de un atri"uto
%speci!icacin de par$metros v$lidos
#ectura de atri"utos en tiempo de ejecucin
-tri"utos de compilacin
Pseudoatri"utos
Cdigo inseguro
Concepto de cdigo inseguro
Compilacin de cdigos inseguros
Marcado de cdigos inseguros
)e!inicin de punteros
Manipulacin de punteros
O"tencin de direccin de memoria& Operador 3
-cceso a contenido de puntero& Operador 4
-cceso a miem"ro de contenido de puntero& Operador 56
Conversiones de punteros
-ritm,tica de punteros
Operadores relacionados con cdigo inseguro
Operador si/eo!& O"tencin de tama7o de tipo
Operador stac2alloc& Creacin de ta"las en pila&
ijacin de varia"les apuntadas
8ovedades de C# 9&:
;en,ricos
Concepto de gen,ricos
1sos de los gen,ricos
Sinta*is
#imitaciones
+estricciones
Valores por de!ecto
-m"ig<edades
.ipos parciales
Iteradores
Mejoras en la manipulacin de delegados
In!erencia de delegados
M,todos annimos
Captura de varia"les e*ternas
Covarian/a y contravarian/a de delegados
.ipos anula"les
Concepto
Sinta*is
Conversiones
Operaciones con nulos
Operador de !usin =>>?
Modi!icadores de visi"ilidad de "lo@ues get y set
Clases est$ticas
+e!erencias a espacios de nom"res
-lias glo"al y cali!icador AA
-lias e*ternos
Supresin temporal de avisos
-tri"utos condicionales
Incrustacin de ta"las en estructuras
Modi!icaciones en el compilador
Control de la versin del lenguaje
Control de la plata!orma de destino
%nvo autom$tico de errores a Microso!t
Concreti/acin de avisos a tratar como errores
Visi"ilidad de los recursos
irma de ensam"lados
Introduccion a C#
Origen y necesidad de un nuevo lenguaje
C# (ledo en ingls C Sharp y en espaol C Almohadilla) es el nuevo lenguaje de propsi!o
general diseado por "icroso#! para su pla!a#orma $%&'$ Sus principales creadores son Sco!!
(il!amu!h y Anders )ejls*erg+ s!e ,l!imo !am*in conocido por ha*er sido el diseador del
lenguaje 'ur*o -ascal y la herramien!a .A/ /elphi$
-un@ue es posi"le escri"ir cdigo para la plata!orma &8%. en muc(os otros lenguajesB C# es el
Cnico @ue (a sido dise7ado espec!icamente para ser utili/ado en ellaB por lo @ue programarla usando
C# es muc(o m$s sencillo e intuitivo @ue (acerlo con cual@uiera de los otros lenguajes ya @ue C#
carece de elementos (eredados innecesarios en &8%.& Por esta ra/nB se suele decir @ue C# es el
lenguaje nativo de .NET
#a sinta*is y estructuracin de C# es muy parecida a la de CDD o EavaB puesto @ue la intencin de
Microso!t es !acilitar la migracin de cdigos escritos en estos lenguajes a C# y !acilitar su aprendi/aje
a los desarrolladores (a"ituados a ellos& Sin em"argoB su sencille/ y el alto nivel de productividad son
compara"les con los de Visual 0asic&
1n lenguaje @ue (u"iese sido ideal utili/ar para estos menesteres es EavaB pero de"ido a pro"lemas
con la empresa creadora del mismo 5Sun5B Microso!t (a tenido @ue desarrollar un nuevo lenguaje @ue
a7adiese a las ya pro"adas virtudes de Eava las modi!icaciones @ue Microso!t tena pensado a7adirle
para mejorarlo aCn m$s y (acerlo un lenguaje orientado al desarrollo de componentes&
%n resumenB C# es un lenguaje de programacin @ue toma las mejores caractersticas de lenguajes
pree*istentes como Visual 0asicB Eava o CDD y las com"ina en uno solo& %l (ec(o de ser relativamente
reciente no implica @ue sea inmaduroB pues Microso!t (a escrito la mayor parte de la 0C# us$ndoloB
por lo @ue su compilador es el m$s depurado y optimi/ado de los incluidos en el .NET Framework
SDK
Caractersticas de C#
Con la idea de @ue los programadores m$s e*perimentados puedan o"tener una visin general del
lenguajeB a continuacin se recoge de manera resumida las principales caractersticas de C# -lguna de
las caractersticas a@u se7aladas no son e*actamente propias del lenguaje sino de la plata!orma &8%.
en generalB y si a@u se comentan es por@ue tienen una repercusin directa en el lenguajeA
Sencillez: C# elimina muc(os elementos @ue otros lenguajes incluyen y @ue son innecesarios en
&8%.& Por ejemploA
o %l cdigo escrito en C# es autocontenidoB lo @ue signi!ica @ue no necesita de !ic(eros
adicionales al propio !uente tales como !ic(eros de ca"ecera o !ic(eros I)#
o %l tama7o de los tipos de datos "$sicos es !ijo e independiente del compiladorB sistema
operativo o m$@uina para @uienes se compile =no como en CDD?B lo @ue !acilita la
porta"ilidad del cdigo&
o 8o se incluyen elementos poco Ctiles de lenguajes como CDD tales como macrosB
(erencia mCltiple o la necesidad de un operador di!erente del punto =.? acceder a
miem"ros de espacios de nom"res =::?
Modernidad: C# incorpora en el propio lenguaje elementos @ue a lo largo de los a7os (a ido
demostr$ndose son muy Ctiles para el desarrollo de aplicaciones y @ue en otros lenguajes como
Eava o CDD (ay @ue simularB como un tipo "$sico decimal @ue permita reali/ar operaciones de
alta precisin con reales de F9G "its =muy Ctil en el mundo !inanciero?B la inclusin de una
instruccin foreach @ue permita recorrer colecciones con !acilidad y es amplia"le a tipos
de!inidos por el usuarioB la inclusin de un tipo "$sico string para representar cadenas o la
distincin de un tipo bool espec!ico para representar valores lgicos&
rientaci!n a objetos: Como todo lenguaje de programacin de propsito general actualB C#
es un lenguaje orientado a o"jetosB aun@ue eso es m$s "ien una caracterstica del C.S @ue de
C#& 1na di!erencia de este en!o@ue orientado a o"jetos respecto al de otros lenguajes como CDD
es @ue el de C# es m$s puro en tanto @ue no admiten ni !unciones ni varia"les glo"ales sino @ue
todo el cdigo y datos (an de de!inirse dentro de de!iniciones de tipos de datosB lo @ue reduce
pro"lemas por con!lictos de nom"res y !acilita la legi"ilidad del cdigo&
C# soporta todas las caractersticas propias del paradigma de programacin orientada a
o"jetosA enca"sulaci!nB herencia y "olimorfismo&
%n lo re!erente a la encapsulacin es importante se7alar @ue aparte de los tpicos
modi!icadores "ublicB "rivate y "rotectedB C# a7ade un cuarto modi!icador llamado internalB
@ue puede com"inarse con "rotected e indica @ue al elemento a cuya de!inicin precede slo
puede accederse desde su mismo ensam"lado&
+especto a la (erencia 5a di!erencia de CDD y al igual @ue Eava5 C# slo admite (erencia simple
de clases ya @ue la mCltiple provoca m$s @ue"raderos de ca"e/a @ue !acilidades y en la mayora
de los casos su utilidad puede ser simulada con !acilidad mediante (erencia mCltiple de
inter!aces& )e todos modosB esto vuelve a ser m$s "ien una caracterstica propia del C.S @ue de
C#&
Por otro lado y a di!erencia de EavaB en C# se (a optado por (acer @ue todos los m,todos sean
por de!ecto sellados y @ue los rede!ini"les (ayan de marcarse con el modi!icador virtual
=como en CDD?B lo @ue permite evitar errores derivados de rede!iniciones accidentales& -dem$sB
un e!ecto secundario de esto es @ue las llamadas a los m,todos ser$n m$s e!icientes por
de!ecto al no tenerse @ue "uscar en la ta"la de !unciones virtuales la implementacin de los
mismos a la @ue se (a de llamar& Otro e!ecto secundario es @ue permite @ue las llamadas a los
m,todos virtuales se puedan (acer m$s e!icientemente al contri"uir a @ue el tama7o de dic(a
ta"la se redu/ca&
rientaci!n a com"onentes: #a propia sinta*is de C# incluye elementos propios del dise7o de
componentes @ue otros lenguajes tienen @ue simular mediante construcciones m$s o menos
complejas& %s decirB la sinta*is de C# permite de!inir cmodamente "ro"iedades =similares a
campos de acceso controlado?B eventos =asociacin controlada de !unciones de respuesta a
noti!icaciones? o atributos =in!ormacin so"re un tipo o sus miem"ros?
#esti!n autom$tica de memoria: Como ya se comentB todo lenguaje de &8%. tiene a su
disposicin el recolector de "asura del C#+& %sto tiene el e!ecto en el lenguaje de @ue no es
necesario incluir instrucciones de destruccin de o"jetos& Sin em"argoB dado @ue la destruccin
de los o"jetos a trav,s del recolector de "asura es indeterminista y slo se reali/a cuando ,ste se
active Hya sea por !alta de memoriaB !inali/acin de la aplicacin o solicitud e*plcita en el
!uente5B C# tam"i,n proporciona un mecanismo de li"eracin de recursos determinista a trav,s
de la instruccin using&
Seguridad de ti"os: C# incluye mecanismos @ue permiten asegurar @ue los accesos a tipos de
datos siempre se realicen correctamenteB lo @ue permite evita @ue se produ/can errores di!ciles
de detectar por acceso a memoria no perteneciente a ningCn o"jeto y es especialmente necesario
en un entorno gestionado por un recolector de "asura& Para ello se toman medidas del tipoA
o Slo se admiten conversiones entre ti"os com"atibles& %sto esB entre un tipo y
antecesores suyosB entre tipos para los @ue e*plcitamente se (aya de!inido un operador
de conversinB y entre un tipo y un tipo (ijo suyo del @ue un o"jeto del primero
almacenase una re!erencia del segundo =do%ncasting? O"viamenteB lo Cltimo slo
puede compro"arlo en tiempo de ejecucin el C#+ y no el compiladorB por lo @ue en
realidad el C#+ y el compilador cola"oran para asegurar la correccin de las
conversiones&
o 8o se pueden usar variables no inicializadas& %l compilador da a los campos un valor
por de!ecto consistente en ponerlos a cero y controla mediante an$lisis del !lujo de
control del !uente @ue no se lea ninguna varia"le local sin @ue se le (aya asignado
previamente algCn valor&
o Se comprue"a @ue todo acceso a los elementos de una tabla se realice con ndices @ue
se encuentren dentro del rango de la misma&
o Se puede controlar la "roducci!n de desbordamientos en operaciones aritm,ticasB
in!orm$ndose de ello con una e*cepcin cuando ocurra& Sin em"argoB para conseguirse
un mayor rendimiento en la aritm,tica estas compro"aciones no se (acen por de!ecto al
operar con varia"les sino slo con constantes =se pueden detectar en tiempo de
compilacin?
o - di!erencia de EavaB C# incluye delegadosB @ue son similares a los punteros a !unciones
de CDD pero siguen un en!o@ue orientado a o"jetosB pueden almacenar re!erencias a
varios m,todos simult$neamenteB y se comprue"a @ue los m,todos a los @ue apunten
tengan par$metros y valor de retorno del tipo indicado al de!inirlos&
o Pueden de!inirse m,todos @ue admitan un nCmero inde!inido de par$metros de un cierto
tipoB y a di!erencia lenguajes como CICDDB en C# siempre se comprue"a @ue los valores
@ue se les pasen en cada llamada sean de los tipos apropiados&
Instrucciones seguras: Para evitar errores muy comunesB en C# se (an impuesto una serie de
restricciones en el uso de las instrucciones de control m$s comunes& Por ejemploB la guarda de
toda condicin (a de ser una e*presin condicional y no aritm,ticaB con lo @ue se evitan errores
por con!usin del operador de igualdad =&&? con el de asignacin =&?J y todo caso de un s%itch
(a de terminar en un brea' o goto @ue indi@ue cu$l es la siguiente accin a reali/arB lo @ue evita
la ejecucin accidental de casos y !acilita su reordenacin&
Sistema de ti"os unificado: - di!erencia de CDDB en C# todos los tipos de datos @ue se de!inan
siempre derivar$nB aun@ue sea de manera implcitaB de una clase "ase comCn llamada
S(stem.bjectB por lo @ue dispondr$n de todos los miem"ros de!inidos en ,sta clase =es decirB
ser$n Ko"jetosL?
- di!erencia de EavaB en C# esto tam"i,n es aplica"le a los tipos de datos "$sicos -dem$sB
para conseguir @ue ello no tenga una repercusin negativa en su nivel de rendimientoB se (a
incluido un mecanismo transparente de bo)ing y unbo)ing con el @ue se consigue @ue slo
sean tratados como o"jetos cuando la situacin lo re@uieraB y mientras tanto puede aplic$rseles
optimi/aciones espec!icas&
%l (ec(o de @ue todos los tipos del lenguaje deriven de una clase comCn !acilita enormemente
el dise7o de colecciones gen,ricas @ue puedan almacenar o"jetos de cual@uier tipo&
E)tensibilidad de ti"os b$sicos: C# permite de!inirB a trav,s de estructurasB tipos de datos
para los @ue se apli@uen las mismas optimi/aciones @ue para los tipos de datos "$sicos& %s
decirB @ue se puedan almacenar directamente en pila =luego su creacinB destruccin y acceso
ser$n m$s r$pidos? y se asignen por valor y no por re!erencia& Para conseguir @ue lo Cltimo no
tenga e!ectos negativos al pasar estructuras como par$metros de m,todosB se da la posi"ilidad
de pasar re!erencias a pila a trav,s del modi!icador de par$metro ref&
E)tensibilidad de o"eradores: Para !acilitar la legi"ilidad del cdigo y conseguir @ue los
nuevos tipos de datos "$sicos @ue se de!inan a trav,s de las estructuras est,n al mismo nivel @ue
los "$sicos prede!inidos en el lenguajeB al igual @ue CDD y a di!erencia de EavaB C# permite
rede!inir el signi!icado de la mayora de los operadores 5incluidos los de conversinB tanto para
conversiones implcitas como e*plcitas5 cuando se apli@uen a di!erentes tipos de o"jetos&
#as rede!iniciones de operadores se (acen de manera inteligenteB de modo @ue a partir de una
Cnica de!inicin de los operadores ** y ++ el compilador puede deducir autom$ticamente como
ejecutarlos de manera pre!ijas y posti!jaJ y de!iniendo operadores simples =como *?B el
compilador deduce cmo aplicar su versin de asignacin compuesta =DM? -dem$sB para
asegurar la consistenciaB el compilador vigila @ue los operadores con opuesto siempre se
rede!inan por parejas =por ejemploB si se rede!ine &&B tam"i,n (ay @ue rede!inir ,&?
.am"i,n se da la posi"ilidadB a trav,s del concepto de indizadorB de rede!inir el signi!icado del
operador -. para los tipos de dato de!inidos por el usuarioB con lo @ue se consigue @ue se pueda
acceder al mismo como si !uese una ta"la& %sto es muy Ctil para tra"ajar con tipos @ue actCen
como colecciones de o"jetos&
E)tensibilidad de modificadores: C# o!receB a trav,s del concepto de atributosB la posi"ilidad
de a7adir a los metadatos del mdulo resultante de la compilacin de cual@uier !uente
in!ormacin adicional a la generada por el compilador @ue luego podr$ ser consultada en
tiempo ejecucin a trav,s de la li"rera de re!le*in de &8%. & %stoB @ue m$s "ien es una
caracterstica propia de la plata!orma &8%. y no de C#B puede usarse como un mecanismo para
de!inir nuevos modi!icadores&
/ersionable: C# incluye una "ol0tica de versionado @ue permite crear nuevas versiones de
tipos sin temor a @ue la introduccin de nuevos miem"ros provo@uen errores di!ciles de
detectar en tipos (ijos previamente desarrollados y ya e*tendidos con miem"ros de igual
nom"re a los reci,n introducidos&
Si una clase introduce un nuevo m,todo cuyas rede!iniciones de"an seguir la regla de llamar a
la versin de su padre en algCn punto de su cdigoB di!cilmente seguiran esta regla miem"ros
de su misma signatura de!inidos en clases (ijas previamente a la de!inicin del mismo en la
clase padreJ o si introduce un nuevo campo con el mismo nom"re @ue algCn m,todo de una
clase (ijaB la clase (ija dejar$ de !uncionar& Para evitar @ue esto ocurraB en C# se toman dos
medidasA
o Se o"liga a @ue toda rede!inicin de"a incluir el modi!icador overrideB con lo @ue la
versin de la clase (ija nunca sera considerada como una rede!inicin de la versin de
miem"ro en la clase padre ya @ue no incluira override& Para evitar @ue por accidente un
programador incluya este modi!icadorB slo se permite incluirlo en miem"ros @ue tengan
la misma signatura @ue miem"ros marcados como rede!ini"les mediante el modi!icador
virtual& -s adem$s se evita el error tan !recuente en Eava de creerse (a"er rede!inido un
miem"roB pues si el miem"ro con override no e*iste en la clase padre se producir$ un
error de compilacin&
o Si no se considera rede!inicinB entonces se considera @ue lo @ue se desea es ocultar el
m,todo de la clase padreB de modo @ue para la clase (ija sea como si nunca (u"iese
e*istido& %l compilador avisar$ de esta decisin a trav,s de un mensaje de aviso @ue
puede suprimirse incluyendo el modi!icador ne% en la de!inicin del miem"ro en la
clase (ija para as indicarle e*plcitamente la intencin de ocultacin&
Eficiente: %n principioB en C# todo el cdigo incluye numerosas restricciones para asegurar su
seguridad y no permite el uso de punteros& Sin em"argoB y a di!erencia de EavaB en C# es posi"le
saltarse dic(as restricciones manipulando o"jetos a trav,s de punteros& Para ello "asta marcar
regiones de cdigo como inseguras =modi!icador unsafe? y podr$n usarse en ellas punteros de
!orma similar a cmo se (ace en CDDB lo @ue puede resultar vital para situaciones donde se
necesite una e!iciencia y velocidad procesamiento muy grandes&
Com"atible: Para !acilitar la migracin de programadoresB C# no slo mantiene una sinta*is
muy similar a CB CDD o Eava @ue permite incluir directamente en cdigo escrito en C#
!ragmentos de cdigo escrito en estos lenguajesB sino @ue el C#+ tam"i,n o!receB a trav,s de los
llamados 1latform Invocation Services =1Invo'e?B la posi"ilidad de acceder a cdigo nativo
escrito como !unciones sueltas no orientadas a o"jetos tales como las )##s de la -PI NinO9&
8tese @ue la capacidad de usar punteros en cdigo inseguro permite @ue se pueda acceder con
!acilidad a este tipo de !uncionesB ya @ue ,stas muc(as veces esperan reci"ir o devuelven
punteros&
.am"i,n es posi"le acceder desde cdigo escrito en C# a o"jetos COM& Para !acilitar estoB el
.NET Framework SDK incluye una (erramientas llamadas tlbim" y regasm mediante las @ue es
posi"le generar autom$ticamente clases pro*y @ue permitanB respectivamenteB usar o"jetos
COM desde &8%. como si de o"jetos &8%. se tratase y registrar o"jetos &8%. para su uso desde
COM&
inalmenteB tam"i,n se da la posi"ilidad de usar controles -ctiveP desde cdigo &8%. y
viceversa& Para lo primero se utili/a la utilidad a)im"B mientras @ue para lo segundo se usa la
ya mencionada regasm&
1rogramacion con C#
Aplicacin bsica Hola Mundo!
0$sicamente una aplicacin en C# puede verse como un conjunto de uno o m$s !ic(eros de cdigo
!uente con las instrucciones necesarias para @ue la aplicacin !uncione como se desea y @ue son
pasados al compilador para @ue genere un ejecuta"le& Cada uno de estos !ic(eros no es m$s @ue un
!ic(ero de te*to plano escrito usando caracteres 1nicode y siguiendo la sinta*is propia de C#&
Como primer contacto con el lenguajeB nada mejor @ue el tpico programa de iniciacin KQHola
Mundo!L @ue lo Cnico @ue (ace al ejecutarse es mostrar por pantalla el mensaje QHola Mundo! Su
cdigo esAR9S
1: class HolaMundo
2: {
3: static void Main()
4: {
5: System.Console.WriteLine("Hola Mundo!");
6: }
7: }
.odo el cdigo escrito en C# se (a de escri"ir dentro de una de!inicin de claseB y lo @ue en la lnea
2: se dice es @ue se va a de!inir una clase =class? de nom"re HolaMundoF cuya de!inicin estar$
comprendida entre la llave de apertura de la lnea 3: y su correspondiente llave de cierre en la lnea
lnea 4:
)entro de la de!inicin de la clase =lnea 5:? se de!ine un m,todo de nom"re Main cuyo cdigo es el
indicado entre la llave de apertura de la lnea 6: y su respectiva llave de cierre =lnea 7:? 1n m,todo no
es m$s @ue un conjunto de instrucciones a las @ue se les asocia un nom"reB de modo @ue para
posteriormente ejecutarlas "aste re!erenciarlas por su nom"re en ve/ de tener @ue rescri"irlas&
#a partcula @ue antecede al nom"re del m,todo indica cu$l es el tipo de valor @ue se devuelve tras la
ejecucin del m,todoB y en este caso es void @ue signi!ica @ue no se devuelve nada& Por su parteB los
par,ntesis colocados tras el nom"re del m,todo indican cu$les son los par$metros @ue ,ste tomaB y el
@ue est,n vacos signi!ica @ue el m,todo no toma ninguno& #os par$metros de un m,todo permiten
modi!icar el resultado de su ejecucin en !uncin de los valores @ue se les d, en cada llamada&
#a pala"ra static @ue antecede a la declaracin del tipo de valor devuelto es un modificador del
signi!icado de la declaracin de m,todo @ue indica @ue el m,todo est$ asociado a la clase dentro de la
@ue se de!ine y no a los o"jetos @ue se creen a partir de ella& Main=? es lo @ue se denomina el "unto de
entrada de la aplicacinB @ue no es m$s @ue el m,todo por el @ue comen/ar$ su ejecucin& 8ecesita del
modi!icador static para evitar @ue para llamarlo (aya @ue crear algCn o"jeto de la clase donde se (aya
de!inido&
inalmenteB la lnea 8: contiene la instruccin con el cdigo a ejecutarB @ue lo @ue se (ace es
solicitar la ejecucin del m,todo 9rite:ine;< de la clase Console de!inida en el espacio de nom"res
S(stem pas$ndole como par$metro la cadena de te*to con el contenido QHola Mundo! 8tese @ue las
cadenas de te*tos son secuencias de caracteres delimitadas por comillas do"les aun@ue dic(as comillas
no !orman parte de la cadena& Por su parteB un espacio de nom"res puede considerarse @ue es para las
clases algo similar a lo @ue un directorio es para los !ic(erosA una !orma de agruparlas&
%l m,todo 9rite:ine;< se usar$ muy a menudo en los pr*imos temasB por lo @ue es conveniente
se7alar a(ora @ue una !orma de llamarlo @ue se utili/ar$ en repetidas ocasiones consiste en pasarle un
nCmero inde!inido de otros par$metros de cual@uier tipo e incluir en el primero su"cadenas de la
!orma TiU& Con ello se consigue @ue se muestre por la ventana de consola la cadena @ue se le pasa como
primer par$metro pero sustituy,ndole las su"cadenas TiU por el valor convertido en cadena de te*to del
par$metro @ue ocupe la posicin iD9 en la llamada a 9rite:ine;<& Por ejemploB la siguiente instruccin
mostrara .engo V a7os por pantalla si * valiese VA
System.Console.WriteLine("Tengo {0} aos", x);

Para indicar cmo convertir cada o"jeto en un cadena de te*to "asta rede!inir su m,todo ToString;<B
aun@ue esto es algo @ue no se ver$ (asta el Tema 5: Clases&
-ntes de seguir es importante resaltar @ue C# es sensi"le a las mayCsculasB los @ue signi!ica @ue no
da igual la capitali/acin con la @ue se escri"an los identi!icadores& %s decirB no es lo mismo escri"ir
Console @ue COnsole o CO8SO#%B y si se (ace de alguna de las dos Cltimas !ormas el compilador
producir$ un error de"ido a @ue en el espacio de nom"res S(stem no e*iste ninguna clase con dic(os
nom"res& %n este sentidoB ca"e se7alar @ue un error comCn entre programadores acostum"rados a Eava
es llamar al punto de entrada main en ve/ de MainB lo @ue provoca un error al compilar ejecuta"les en
tanto @ue el compilador no detectar$ ninguna de!inicin de punto de entrada&
Puntos de entrada
Wa se (a dic(o @ue el "unto de entrada de una aplicacin es un m,todo de nom"re Main @ue
contendr$ el cdigo por donde se (a de iniciar la ejecucin de la misma& Hasta a(ora slo se (a visto
una versin de Main=? @ue no toma par$metros y tiene como tipo de retorno voidB pero en realidad
todas sus posi"les versiones sonA
static void Main()
static int Main()
static int Main(string[] args)
static void Main(string[] args)
Como se veB (ay versiones de Main=? @ue devuelven un valor de tipo int& 1n int no es m$s @ue un
tipo de datos capa/ de almacenar valor enteros comprendidos entre H9&FXY
F
XGO&ZXG y 9&FXY
F
XGO&ZXYB y
el nCmero devuelto por Main=? sera interpretado como cdigo de retorno de la aplicacin& [ste valor
suele usarse para indicar si la aplicacin a terminado con ,*ito =generalmente valor :? o no =valor
segCn la causa de la terminacin anormal?B y en el Tema 8: Mtodos se e*plicar$ como devolver
valores&
.am"i,n (ay versiones de Main=? @ue toman un par$metro donde se almacenar$ la lista de
argumentos con los @ue se llam a la aplicacinB por lo @ue slo es Ctil usar estas versiones del punto
de entrada si la aplicacin va a utili/ar dic(os argumentos para algo& %l tipo de este par$metro es
string-.B lo @ue signi!ica @ue es una ta"la de cadenas de te*to =en el Tema 5: Claes se e*plicar$
detenidamente @u, son las ta"las y las cadenas?B y su nom"re 5@ue es el @ue (a"r$ de usarse dentro del
cdigo de Main=? para (acerle re!erencia5 es args en el ejemploB aun@ue podra d$rsele cual@uier otro
Compilacin en lnea de comandos
1na ve/ escrito el cdigo anterior con algCn editor de te*tos Hcomo el =loc de Notas de Nindo's5 y
almacenado en !ormato de te*to plano en un !ic(ero HolaMundo&csROSB para compilarlo "asta a"rir una
ventana de consola =MS5)OS en Nindo's?B colocarse en el directorio donde se encuentre y pas$rselo
como par$metro al compilador asA
CA\NI8)ONS\Microso!t&8%.\rame'or2\v9&:&V:Y9Y6csc HolaMundo&cs
csc.e)e es el compilador de C# incluido en el &8%. rame'or2 S)] para Nindo's de Microso!t&
-un@ue en principio el programa de instalacin del S)] lo a7ade autom$ticamente al pat( para poder
llamarlo sin pro"lemas desde cual@uier directorioB si lo (a instalado a trav,s de VS&8%. esto no
ocurrir$ y de"er$ con!igur$rselo ya sea manualmenteB o "ien ejecutando el !ic(ero por lotes
Common4>Tools>vsvars53.bat @ue VS&8%. incluye "ajo su directorio de instalacinB o a"riendo la
ventana de consola desde el icono ?erramientas de /isual Studio.NET @ S0mbolo del sistema de
/isual Studio.NET correspondiente al grupo de programas de VS&8%. en el menC Inicio de Nindo's
@ue no (ace m$s @ue a"rir la ventana de consola y llamar autom$ticamente a vsvars53.bat& %n
cual@uier casoB si usa otros compiladores de C# puede @ue varie la !orma de reali/ar la compilacinB
por lo @ue lo @ue a@u se e*plica en principio slo ser$ v$lido para los compiladores de C# de
Microso!t para Nindo's&
.ras la compilacin se o"tendra un ejecuta"le llamado HolaMundo&e*e cuya ejecucin producira la
siguiente salida por la ventana de consolaA
Hola Mundo!
Si la aplicacin @ue se vaya a compilar no utili/ase la ventana de consola para mostrar su salida sino
una inter!a/ gr$!ica de ventanasB entonces (a"ra @ue compilarla pasando al compilador la opcin At
con el valor %ine)e antes del nom"re del !ic(ero a compilar& Si no se (iciese as se a"rra la ventana
de consola cada ve/ @ue ejecutase la aplicacin de ventanasB lo @ue suele ser indesea"le en este tipo de
aplicaciones& -sB para compilar Ventanas&cs como ejecuta"le de ventanas sera conveniente escri"irA
CA\NI8)ONS\Microso!t&8%.\rame'or2\v9&:&V:Y9Y6csc ItA'ine*e Ventanas&cs

8tese @ue aun@ue el nom"re %ine)e d, la sensacin de @ue este valor para la opcin At slo permite
generar ejecuta"les de ventanasB en realidad lo @ue permite es generar ejecuta"les sin ventana de
consola asociada& Por tantoB tam"i,n puede usarse para generar ejecuta"les @ue no tengan ninguna
inter!a/ asociadaB ni de consola ni gr$!ica&
Si en lugar de un ejecuta"le 5ya sea de consola o de ventanas5 se desea o"tener una li"reraB entonces
al compilar (ay @ue pasar al compilador la opcin At con el valor librar(& Por ejemploB siguiendo con el
ejemplo inicial (a"ra @ue escri"irA
CA\NI8)ONS\Microso!t&8%.\rame'or2\v9&:&V:Y9Y6csc ItAli"rary HolaMundo&cs
%n este caso se generara un !ic(ero HolaMundo&dll cuyos tipos de datos podran utili/arse desde
otros !uentes pasando al compilador una re!erencia a los mismos mediante la opcin Ar& Por ejemploB
para compilar como ejecuta"le un !uente -&cs @ue use la clase HolaMundo de la li"rera
HolaMundo&dll se escri"iraA
CA\NI8)ONS\Microso!t&8%.\rame'or2\v9&:&V:Y9Y6csc IrAHolaMundo&dll -&cs
%n general Ar permite re!erenciar a tipos de!inidos en cual@uier ensam"ladoB por lo @ue el valor @ue
se le indi@ue tam"i,n puede ser el nom"re de un ejecuta"le& -dem$sB en cada compilacin es posi"le
re!erenciar mCltiples ensam"lados ya sea incluiyendo la opcin Ar una ve/ por cada uno o incluiyendo
mCltiples re!erencias en una Cnica opcin Ar usando comas o puntos y comas como separadores& Por
ejemploB las siguientes tres llamadas al compilador son e@uivalentesA
CA\NI8)ONS\Microso!t&8%.\rame'or2\v9&:&V:Y9Y6csc
IrAHolaMundo&dllJOtro&dllJOtroM$s&e*e -&cs
CA\NI8)ONS\Microso!t&8%.\rame'or2\v9&:&V:Y9Y6csc
IrAHolaMundo&dllBOtro&dllBOtroM$s&e*e -&cs
CA\NI8)ONS\&&&&\v9&:&V:Y9Y6csc ItAHolaMundo&dll IrAOtro&dll IrAOtroM$s&e*e -&cs
Hay @ue se7alar @ue aun@ue no se indi@ue nadaB en toda compilacin siempre se re!erencia por
de!ecto a la li"rera mscorlib.dll de la 0C#B @ue incluye los tipos de uso m$s !recuente& Si se usan tipos
de la 0C# no incluidos en ella (a"r$ @ue incluir al compilar re!erencias a las li"reras donde est,n
de!inidos =en la documentacin del S)] so"re cada tipo de la 0C# puede encontrar in!ormacin so"re
donde se de!ini?
.anto las li"reras como los ejecuta"les son ensam"lados& Para generar un mdulo de cdigo @ue no
!orme parte de ningCn ensam"lado sino @ue contenga de!iniciones de tipos @ue puedan a7adirse a
ensam"lados @ue se compilen posteriormenteB el valor @ue (a de darse al compilar a la opcin At es
module& Por ejemploA
CA\NI8)ONS\Microso!t&8%.\rame'or2\v9&:&V:Y9Y6csc ItAmodule HolaMundo&cs

Con la instruccin anterior se generara un mdulo llamado HolaMundo&netmodule @ue podra ser
a7adido a compilaciones de ensam"lados incluy,ndolo como valor de la opcin Aaddmodule& Por
ejemploB para a7adir el mdulo anterior a la compilacin del !uente li"rera #i"&cs como li"rera se
escri"iraA
CA\NI8)ONS\&&&\v9&:&V:Y9Y6csc ItAli"rary IaddmoduleAHolaMundo&netmodule #i"&cs

-un@ue (asta a(ora todas las compilaciones de ejemplo se (an reali/ado utili/ando un Cnico !ic(ero
de cdigo !uenteB en realidad nada impide @ue se puedan utili/ar m$s& Por ejemploB para compilar los
!ic(eros -&cs y 0&cs en una li"rera -&dll se ejecutaraA
CA\NI8)ONS\Microso!t&8%.\rame'or2\v9&:&V:Y9Y6csc ItAli"rary -&cs 0&cs
8tese @ue el nom"re @ue por de!ecto se d, al ejecuta"le generado siempre es igual al del primer
!uente especi!icado pero con la e*tensin propia del tipo de compilacin reali/ada =.e)e para
ejecuta"lesB .dll para li"reras y .netmodule para mdulos? Sin em"argoB puede especi!ic$rse como
valor en la opcin Aout del compilador cual@uier otro tal y como muestra el siguiente ejemplo @ue
compila el !ic(ero -&cs como una li"rera de nom"re #i"&e*eA
CA\NI8)ONS\Microso!t&8%.\rame'or2\v9&:&V:Y9Y6csc ItAli"rary IoutA#i"&e*e -&cs
V,ase @ue aun@ue se (aya dado un nom"re terminado en .e)e al !ic(ero resultanteB ,ste sigue siendo
una li"rera y no un ejecuta"le e intentar ejecutarlo producira un mensaje de error& O"viamente no
tiene muc(o sentido darle esa e*tensinB y slo se le (a dado en este ejemplo para demostrar @ueB
aun@ue recomenda"leB la e*tensin del !ic(ero no tiene por@u, corresponderse realmente con el tipo de
!ic(ero del @ue se trate&
- la (ora de especi!icar !ic(eros a compilar tam"i,n se pueden utili/ar los caracteres de comodn
tpicos del sistema operativo& Por ejemploB para compilar todos los !ic(eros con e*tensin &cs del
directorio actual en una li"rera llamada Varios&dll se (araA
CA\NI8)ONS\Microso!t&8%.\rame'or2\v9&:&V:Y9Y6csc ItAli"rary IoutAvarios&dll 4&cs
Con lo @ue (ay @ue tener cuidadoB y en especial al compilar varios !uentesB es con @ue no se
compilen a la ve/ m$s de un tipo de dato con punto de entradaB pues entonces el compilador no sa"ra
cu$l usar como inicio de la aplicacin& Para orientarloB puede especi!icarse como valor de la opcin
Amain el nom"re del tipo @ue contenga el Main=? (a usar como punto de entrada& -sB para compilar
los !ic(eros -&cs y 0&cs en un ejecuta"le cuyo punto de entrada sea el de!inido en el tipo PrincipalB
(a"ra @ue escri"irA
CA\NI8)ONS\Microso!t&8%.\rame'or2\v9&:&V:Y9Y6csc ImainAPrincipal -&cs 0&cs
#gicamenteB para @ue esto !uncione -&cs o 0&cs tiene @ue contener alguna de!inicin de algCn tipo
llamado Principal con un Cnico m,todo v$lido como punto de entrada =o"viamenteB si contiene varios
se volvera a tener el pro"lema de no sa"er cu$l utili/ar?
Compilacin con Visual Studio.NE
Para compilar una aplicacin en Visual Studio&8%. primero (ay @ue incluirla dentro de algCn
proyecto& Para ello "asta pulsar el "otn Ne% 1roject en la p$gina de inicio @ue se muestra nada m$s
arrancar dic(a (erramientaB tras lo @ue se o"tendr$ una pantalla con el aspecto mostrado en la
Ilustraci!n 2&
%n el recuadro de la ventana mostrada eti@uetado como 1roject T("es se (a de seleccionar el tipo
de proyecto a crear& O"viamenteB si se va a tra"ajar en C# la opcin @ue (a"r$ @ue escoger en la misma
ser$ siempre Visual C# Projects&
%n el recuadro Tem"lates se (a de seleccionar la plantilla correspondiente al su"tipo de proyecto
dentro del tipo indicado en 1roject T("es @ue se va a reali/ar& Para reali/ar un ejecuta"le de consolaB
como es nuestro casoB (ay @ue seleccionar el icono eti@uetado como Console -pplication& Si se
@uisiese reali/ar una li"rera (a"ra @ue seleccionar Class #i"raryB y si se @uisies reali/ar un ejecuta"le
de ventanas (a"ra @ue seleccionar Nindo's -pplication& 8tese @ue no se o!rece ninguna plantilla
para reali/ar mdulosB lo @ue se de"e a @ue desde Visual Studio&8%. no pueden crearse&
Por CltimoB en el recuadro de te*to Name se (a de escri"ir el nom"re a dar al proyecto y en :ocation
el del directorio "ase asociado al mismo& 8tese @ue "ajo de :ocation aparecer$ un mensaje
in!ormando so"re cual ser$ el directorio donde !inalmente se almacenar$n los arc(ivos del proyectoB
@ue ser$ el resultante de concatenar la ruta especi!icada para el directorio "ase y el nom"re del
proyecto&
R -mpliar ImagenS
Ilustracin F A Ventana de creacin de nuevo proyecto en Visual Studio&8%.
1na ve/ con!iguradas todas estas opcionesB al pulsar "otn B Visual Studio crear$ toda la
in!raestructura adecuada para empe/ar a tra"ajar cmodamente en el proyecto& Como puede apreciarse
en la Ilustraci!n 3 B esta in!raestructura consistir$ en la generacin de un !uente @ue servir$ de plantilla
para la reali/acin de proyectos del tipo elegido =en nuestro casoB aplicaciones de consola en C#?A
R -mpliar ImagenS
Ilustracin 9 A Plantilla para aplicaciones de consola generada por Visual Studio&8%.
- partir de esta plantillaB escri"ir el cdigo de la aplicacin de ejemplo es tan sencillo con
simplemente teclear System&Console&Nrite#ine=KQHola Mundo!L? dentro de la de!inicin del m,todo
Main=? creada por Visual Studio&8%.& Claro est$B otra posi"ilidad es "orrar toda la plantilla y
sustituirla por el cdigo para HolaMundo mostrado anteriormente&
Sea (aga como se (agaB para compilar y ejecutar tras ello la aplicacin slo (ay @ue pulsar
CTC:*D8 o seleccionar Eebug @ Start 9ithout Eebugging en el menC principal de Visual
Studio&8%.& Para slo compilar el proyectoB entonces (ay @ue seleccionar =uild @ Cebuild Fll& )e
todas !ormasB en am"os casos el ejecuta"le generado se almacenar$ en el su"directorio 0in\)e"ug del
directorio del proyecto&
%n el e*tremo derec(o de la ventana principal de Visual Studio&8%. puede encontrar el denominado
Solution E)"lorer =si no lo encuentraB seleccione /ie% @ Solution E)"lorer?B @ue es una (erramienta
@ue permite consultar cu$les son los arc(ivos @ue !orman el proyecto& Si selecciona en ,l el icono
correspondiente al proyecto en @ue estamos tra"ajando y pulsa /ie% @ 1ro"ert( 1ages o"tendr$ una
(oja de propiedades del proyecto con el aspecto mostrado en la Ilustraci!n 5 A
R -mpliar ImagenS
Ilustracin O A Hoja de propiedades del proyecto en Visual Studio&8%.
%sta ventana permite con!igurar de manera visual la mayora de opciones con las @ue se llamar$ al
compilador en lnea de comandos& Por ejemploB para cam"iar el nom"re del !ic(ero de salida =opcin
Aout? se indica su nuevo nom"re en el cuadro de te*to Common 1ro"erties @ #eneral @ Fssembl(
NameB para cam"iar el tipo de proyecto a generar =opcin At? se utili/a Common 1ro"erties @ #eneral
@ ut"ut T("e =como ver$ si intenta cam"iarloB no es posi"le generar mdulos desde Visual
Studio&8%.?B y el tipo @ue contiene el punto de entrada a utili/ar =opcin Amain? se indica en Common
1ro"erties @ #eneral @ Startu" bject
inalementeB para a7adir al proyecto re!erencias a ensam"lados e*ternos =opcin Ar? "asta seleccionar
1roject @ Fdd Ceference en el menC principal de VS&8%.&
Dundamentos de C#
Comentarios
1n comentario es te*to @ue se incluye en el cdigo !uente para !acilitarsu lectura a los
programadores y cuyo contenido esB por de!ectoB completamenteignorado por el compilador& Suelen
usarse para incluir in!ormacin so"re elautor del cdigoB para aclarar el signi!icado o el por@u, de
determinadassecciones de cdigoB para descri"ir el !uncionamiento de los m,todos de lasclasesB etc&
%n C# (ay dos !ormas de escri"ir comentarios& #a primera consiste en encerrar todo el te*to @ue se
desee comentar entre caracteres AG y GA & %stos comentarios pueden a"arcar tantas lneas como sea
necesario& PorejemploA
/* Texto */

/* Esto es un comentario que ejemplifica cmo se escribe
comentarios que ocupen varias lneas*/
-(ora "ienB (ay @uetener cuidado con el (ec(o de @ue no es posi"le anidar comentarios de este tipo&
%s decirB no vale escri"ir comentarios como el siguienteA
NO ES CORRECTO!
/* Comentario contenedor /* Comentario contenido */ */
%sto se de"e a @ue como el compilador ignora todo el te*to contenido en un comentario y slo "usca
la secuencia 4I @ue marca su !inalB ignorar$ el segundo I4 y cuando llegue al primer 4I considerar$ @ue
(a aca"ado el comentario a"ierto con el primer I4 =no el a"ierto con el segundo? y pasar$ a "uscar
cdigo& Como el 4I slo lo admite si (a detectado antes algCn comentario a"ierto y aCn no cerrado =no
mientras "usca cdigo?B cuando llegue al segundo 4I considerar$ @ue (a (a"ido un error ya @ue
encontrar$ el 4I donde espera"a encontrar cdigo
)ado @ue muc(as veces los comentarios @ue se escri"en son muy cortos y no suelen ocupar m$s de
una lneaB C# o!rece una sinta*is alternativa m$s compacta para la escritura este tipo de comentarios en
las @ue se considera como indicador del comien/o del comentario la pareja de caracteres II y como
indicador de su !inal el !in de lnea& Por tantoB la sinta*is @ue siguen estos comentarios esA
// <texto>

W un ejemplo de su uso esA
// Este comentario ejemplifica como escribir comentarios de una sola lnea
%stos comentarios de una sola lnea s @ue pueden anidarse sin ningCn pro"lema& Por ejemploB el
siguiente comentario es per!ectamente v$lidoA
// Comentario contenedor // Comentario contenido

Identificadores
-l igual @ue en cual@uier lenguaje de programacinB en C# un identi!icador no es m$s @ueB como su
propio nom"re indicaB un nom"re con el @ue identi!icaremos algCn elemento de nuestro cdigoB ya sea
una claseB una varia"leB un m,todoB etc&
.picamente el nom"re de un identi!icador ser$ una secuencia de cual@uier nCmero de caracteres
al!anum,ricos Hincluidas vocales acentuadas y e7es5 tales @ue el primero de ellos no sea un nCmero&
Por ejemploB identi!icadores v$lidos seranA -rri"aB ca7aB COP:B $^_`B etcJ pero no lo seran OcomB F9YB
etc&
Sin em"argoB y aun@ue por motivos de legi"ilidad del cdigo no se recomiendaB C# tam"i,n permite
incluir dentro de un identi!icador caracteres especiales imprimi"les tales como sm"olos de di,resisB
su"rayadosB etc& siempre y cuando estos no tengan un signi!icado especial dentro del lenguaje. 1or
ejemploB tam"i,n seran identi!icadores v$lidosB a"arco_B cb2 y -c0J pero no C# =# indica inicio de
directiva de preprocesado? o a!" =! indica operacin lgica KnotL?
inalmenteB C# da la posi"ilidad de poder escri"ir identi!icadores @ue incluyan caracteres 1nicode
@ue no se puedan imprimir usando el teclado de la m$@uina del programador o @ue no sean
directamente v$lidos de"ido a @ue tengan un signi!icado especial en el lenguaje& Para elloB lo @ue
permite es escri"ir estos caracteres usando secuencias de escapeB @ue no son m$s @ue secuencias de
caracteres con las sinta*isA
>uHd0gitoIHd0gitoIHd0gitoIHd0gitoI
>JHd0gitoIHd0gitoIHd0gitoIHd0gitoIHd0gitoIHd0gitoIHd0gitoIHd0gitoI
%stos dgitos indican es el cdigo 1nicode del car$cter @ue se desea incluir como parte del
identi!icadorB y cada uno de ellos (a de ser un dgito (e*adecimal v$lido& =:5dB a5! -5? Hay @ue
se7alar @ue el car$cter u (a de escri"ise en minCscula cuando se indi@uen caracteres 1nicode con X
dgitos y en mayCscula cuando se indi@uen con caracteres de oc(o& %jemplos de identi!icadores v$lidos
son C\u::ZX =e@uivale a C#B pues ZX es el cdigo de # en 1nicode? a\1::::::OO" =e@uivale a a!"?
Palabras reservadas
-un@ue antes se (an dado una serie de restricciones so"re cu$les son los nom"res v$lidos @ue se
pueden dar en C# a los identi!icadoresB !alta todava por dar unaA los siguientes nom"res no son v$lidos
como identi!icadores ya @ue tienen un signi!icado especial en el lenguajeA
abstract, as, base,
bool, break, byte, case,
catch, char, checked, class, const, continue,
decimal, default, delegate, do, double,
else, enum, event, explicit, extern,
false, finally, fixed, float, for, foreach,
goto,
if, implicit, in, int, interface, internal, is,
lock, long,
namespace, new, null,
object, operator, out, override,
params, private,protected, public,
readonly, ref, return,
sbyte, sealed, short, sieof, stackalloc, static, string, struct, switch,
this, throw, true, try, typeof,
uint, ulong, unchecked, unsafe, ushort, using,
virtual, void, while

-parte de estas pala"ras reservadasB si en !uturas implementaciones del lenguaje se decidiese incluir
nuevas pala"ras reservadasB Microso!t dice @ue dic(as pala"ras (a"ran de incluir al menos dos
sm"olos de su"rayado consecutivos =aa? Por tantoB para evitar posi"les con!lictos !uturos no se
recomienda dar a nuestros identi!icadores nom"res @ue contengan dic(a secuencia de sm"olos&
-un@ue directamente no podemos dar estos nom"res a nuestros identi!icadoresB C# proporciona un
mecanismo para (acerlo indirectamente y de una !orma muc(o m$s legi"le @ue usando secuencias de
escape& %ste mecanismo consiste en usar el car$cter e para pre!ijar el nom"re coincidente con el de
una pala"ra reservada @ue @ueramos dar a nuestra varia"le& Por ejemploB el siguiente cdigo es v$lidoA
class @class
{
static void @static(bool @bool)
{
if (@bool)
Console.WriteLine("cierto");
else
Console.WriteLine("falso");
}
}
#o @ue se (a (ec(o en el cdigo anterior (a sido usar e para declarar una clase de nom"re class con
un m,todo de nom"re static @ue toma un par$metro de nom"re "oolB aCn cuando todos estos nom"res
son pala"ras reservadas en C#&
Hay @ue precisar @ue aun@ue el nom"re @ue nosotros escri"amos sea por ejemplo eclassB el nom"re
con el @ue el compilador va a tratar internamente al identi!icador es solamente class& )e (ec(oB si desde
cdigo escrito en otro lenguaje adaptado a &8%. distinto a C# (acemos re!erencia a ,ste identi!icador y
en ese lenguaje su nom"re no es una pala"ra reservadaB el nom"re con el @ue de"eremos re!erenciarlo
es classB y no eclass =si tam"i,n !uese en ese lenguaje pala"ra reservada (a"ra @ue re!erenciarlo con
el mecanismo @ue el lenguaje incluyese para elloB @ue @ui/$s tam"i,n podra consistir en usar e como
en C#?
%n realidadB el uso de e no se tiene por@u, limitar a preceder pala"ras reservadas en C#B sino @ue
podemos preceder cual@uier nom"re con ,l& Sin em"argoB (acer esto no se recomiendaB pues es
considerado como un mal ($"ito de programacin y puede provocar errores muy sutiles como el @ue
muestra el siguiente ejemploA
class A
{
int a; // (1)
int @a; // (2)
public static void Main()
{}
}

Si intentamos compilar este cdigo se producir$ un error @ue nos in!ormar$ de @ue el campo de
nom"re a (a sido declarado mCltiples veces en la clase -& %sto se de"e a @ue como e no !orma parte
en realidad del nom"re del identi!icador al @ue precedeB las declaraciones marcadas con comentarios
como =F? y =9? son e@uivalentes&
Hay @ue se7alar por Cltimo una cosa respecto al car$cter eA slo puede preceder al nom"re de un
identi!icadorB pero no puede estar contenido dentro del mismo& %s decirB identi!icadores como
iVO99e!ie&us&es no son v$lidos&
Literales
1n literal es la representacin e*plcita de los valores @ue pueden tomar los tipos "$sicos del
lenguaje& - continuacin se e*plica cu$l es la sinta*is con @ue se escri"en los literales en C#
desglos$ndolos segCn el tipo de valores @ue representanA
#iterales enterosA 1n nCmero entero se puede representar en C# tanto en !ormato decimal como
(e*adecimal& %n el primer caso "asta escri"ir los dgitos decimales =:5d? del nCmero unos tras
otrosB mientras @ue en el segundo (ay @ue preceder los dgitos (e*adecimales =:5dB a5!B -5?
con el pre!ijo :*& %n am"os casos es posi"le preceder el nCmero de los operadores D H para
indicar si es positivo o negativoB aun@ue si no se pone nada se considerar$ @ue es positivo&
%jemplos de literales enteros son :B VB DFVB 59OB :*F-B 5:*FaB etc
%n realidadB la sinta*is completa para la escritura de literales enteros tam"i,n puede incluir un su!ijo
@ue indi@ue el tipo de dato entero al @ue (a de pertenecer el literal& %sto no lo veremos (asta el Tema 7:
Variables ti!os de datos&
#iterales realesA #os nCmeros reales se escri"en de !orma similar a los enterosB aun@ue slo se
pueden escri"ir en !orma decimal y para separar la parte entera de la real usan el tradicional
punto decimal =car$cter .? .am"i,n es posi"le representar los reales en !ormato cient!icoB
us$ndose para indicar el e*ponente los caracteres e %& %jemplos de literales reales son :&:B
V&FB 5V&FB DFV&9FB O&:9eF:B 9&:9e59B dG&G%DFB etc&
-l igual @ue ocurra con los literales enterosB los literales reales tam"i,n pueden incluir su!ijos @ue
indi@uen el tipo de dato real al @ue pertenecenB aun@ue nuevamente no los veremos (asta el Tema 7:
Variables ti!os de datos
#iterales lgicosA #os Cnicos literales lgicos v$lidos son true y !alseB @ue respectivamente
representan los valores lgicos cierto y !also&
#iterales de car$cterA Pr$cticamente cual@uier car$cter se puede representar encerr$ndolo entre
comillas simples& Por ejemploB faf =letra a?B f f =car$cter de espacio?B f>f =sm"olo de
interrogacin?B etc& #as Cnicas e*cepciones a esto son los caracteres @ue se muestran en la .a"la
X&FB @ue (an de representarse con secuencias de escape @ue indi@uen su valor como cdigo
1nicode o mediante un !ormato especial tal y como se indica a continuacinA
Car$cter Cdigo de escape 1nicode Cdigo de escape especial
Comilla simple \u::9Y \f
Comilla do"le \u::99 \g
Car$cter nulo \u:::: \:
-larma \u:::Y \a
+etroceso \u:::G \"
Salto de p$gina \u:::C \!
8ueva lnea \u:::- \n
+etorno de carro \u:::) \r
.a"ulacin (ori/ontal \u:::d \t
.a"ulacin vertical \u:::0 \v
0arra invertida \u::VC \\
Tabla 6.2: C!digos de esca"e es"eciales
%n realidadB de la ta"la anterior (ay @ue mati/ar @ue el car$cter de comilla do"le tam"i,n puede
aparecer dentro de un literal de cadena directamenteB sin necesidad de usar secuencias de
escape& Por tantoB otros ejemplos de literales de car$cter v$lidos ser$n f\>fB f>fB f\!fB f\u::::fB f\\fB f\ffB etc&
-parte de para representar los caracteres de la ta"la anteriorB tam"i,n es posi"le usar los cdigos de
escape 1nicode para representar cual@uier cdigo 1nicodeB lo @ue suele usarse para representar
literales de caracteres no incluidos en los teclados est$ndares&
Eunto al !ormato de representacin de cdigos de escape 1nicode ya vistoB C# incluye un !ormato
a"reviado para representar estos cdigos en los literales de car$cter si necesidad de escri"ir siempre
cuatro dgitos aCn cuando el cdigo a representar tenga muc(os ceros en su parte i/@uierda& %ste
!ormato consiste en preceder el cdigo de \* en ve/ de \u& )e este modoB los literales de car$cter
h\1:::::::GiB f\u:::GfB f\*:::GfB f\*::GfB f\*:Gf y f\*Gf son todos e@uivalentes& Hay @ue tener en cuenta
@ue este !ormato a"reviado slo es v$lido en los literales de car$cterB y no a la (ora de dar nom"res a
los identi!icadores&
#iterales de cadenaA 1na cadena no es m$s @ue una secuencia de caracteres encerrados entre
comillas do"les& Por ejemplo >HolaB mundo>B >camin>B etc& %l te*to contenido dentro estos
literales puede estar !ormado por cual@uier nCmero de literales de car$cter concatenados y sin
las comillas simplesB aun@ue si incluye comillas do"les ,stas (an de escri"irse usando
secuencias de escape por@ue si no el compilador las interpretara como el !inal de la cadena&
-parte del !ormato de escritura de literales de cadenas antes comentadoB @ue es el comCnmente
utili/ado en la mayora de lenguajes de programacinB C# tam"i,n admite uno nuevo consistente en
precederlos de un sm"olo eB caso en @ue todo el contenido de la cadena sera interpretado tal cualB sin
considerar la e*istencia de secuencias de escape& - este tipo de literales se les conoce como literales de
cadena planos o literales ver"atim y pueden incluso ocupar varias lneas& #a siguiente ta"la recoge
algunos ejemplos de cmo se interpretanA
#iteral de cadena Interpretado como&&&
>Hola\tMundo> Hola Mundo
eLHola\tMundo> Hola\tMundo
e>Hola
Mundo>
Hola
Mundo
eLLLHola MundoLLg KHola MundoL
Tabla 6.3: Ejem"los de literales de cadena "lanos
%l Cltimo ejemplo de la ta"la se (a aprovec(ado para mostrar @ue si dentro de un literal de cadena
plano se desea incluir caracteres de comilla do"le sin @ue sean con!undidos con el !inal de la cadena
"asta duplicarlos&
#iteral nuloA %l literal nulo es un valor especial @ue se representa en C# con la pala"ra reservada
null y se usa como valor de las varia"les de o"jeto no iniciali/adas para as indicar @ue
contienen re!erencias nulas&
Operadores
0n operador en C# es un sm*olo #ormado por uno o m1s carac!eres 2ue permi!e reali3ar una
de!erminada operacin en!re uno o m1s da!os y produce un resul!ado$
- continuacin se descri"en cu$les son los operadores incluidos en el lenguaje clasi!icados segCn el
tipo de operaciones @ue permiten reali/arB aun@ue (ay @ue tener en cuenta @ue C# permite la
rede!inicin del signi!icado de la mayora de los operadores segCn el tipo de dato so"re el @ue se
apli@uenB por lo @ue lo @ue a@u se cuenta se corresponde con los usos m$s comunes de los mismosA
"eraciones aritmKticasA #os operadores aritm,ticos incluidos en C# son los tpicos de suma
=*?B resta =+?B producto =G?B divisin =A? y mdulo =L? .am"i,n se incluyen operadores de
Kmenos unarioL =M? y Km$s unarioL =*?
+elacionados con las operaciones aritm,ticas se encuentran un par de operadores llamados
chec'ed y unchec'ed @ue permiten controlar si se desea detectar los des"ordamientos @ue
puedan producirse si al reali/ar este tipo de operaciones el resultado es superior a la capacidad
del tipo de datos de sus operandos& %stos operadores se usan asA
checked (<expresinAritmtica>)

unchecked(<expresinAritmtica>)
-m"os operadores calculan el resultado de je*presin-ritm,tica6 y lo devuelven si durante el c$lculo
no se produce ningCn des"ordamiento& Sin em"argoB en caso de @ue (aya des"ordamiento cada uno
actCa de una !orma distintaA chec'ed provoca un error de compilacin si je*presin-ritm,tica6 es una
e*presin constante y una e*cepcin S(stem.verflo%E)ce"tion si no lo esB mientras @ue unchec'ed
devuelve el resultado de la e*presin aritm,tica truncado para @ue @uepa en el tama7o esperado&
Por de!ectoB en ausencia de los operadores chec'ed y unchec'ed lo @ue se (ace es evaluar las
operaciones aritm,ticas entre datos constantes como si se les aplicase chec'ed y las operaciones entre
datos no constantes como si se les (u"iese aplicado unchec'ed&
"eraciones l!gicas: Se incluyen operadores @ue permiten reali/ar las operaciones lgicas
tpicasA KandL =NN y N?B KorL =OO y O?B KnotL =,? y K*orL =P?
#os operadores NN y OO se di!erencia de N y O en @ue los primeros reali/an evaluacin pere/osa y los
segundos no& #a evaluacin pere/osa consiste en @ue si el resultado de evaluar el primer operando
permite deducir el resultado de la operacinB entonces no se evalCa el segundo y se devuelve dic(o
resultado directamenteB mientras @ue la evaluacin no pere/osa consiste en evaluar siempre am"os
operandos& %s decirB si el primer operando de una operacin NN es !also se devuelve false
directamenteB sin evaluar el segundoJ y si el primer operando de una OO es cierto se devuelve true
directamenteB sin evaluar el otro&
"eraciones relacionales: Se (an incluido los tradicionales operadores de igualdad =&&?B
desigualdad =,&?B Kmayor @ueL =I?B Kmenor @ueL =H?B Kmayor o igual @ueL =I&? y Kmenor o igual
@ueL =jM?
"eraciones de mani"ulaci!n de bitsA Se (an incluido operadores @ue permiten reali/ar a
nivel de "its operaciones KandL =N?B KorL =O?B KnotL =Q?B K*orL =P?B despla/amiento a i/@uierda
=44? y despla/amiento a derec(a =II? %l operador HH despla/a a i/@uierda rellenando con
cerosB mientras @ue el tipo de relleno reali/ado por II depende del tipo de dato so"re el @ue se
aplicaA si es un dato con signo mantiene el signoB y en caso contrario rellena con ceros&
"eraciones de asignaci!n: Para reali/ar asignaciones se usa en C# el operador &B operador
@ue adem$s de reali/ar la asignacin @ue se le solicita devuelve el valor asignado& Por ejemploB
la e*presin a M " asigna a la varia"le a el valor de la varia"le " y devuelve dic(o valorB
mientras @ue la e*presin c M a M " asigna a las varia"les c y a el valor de " =el operador & es
asociativo por la derec(a?
.am"i,n se (an incluido operadores de asignacin compuestos @ue permiten a(orrar tecleo a la (ora
de reali/ar asignaciones tan comunes comoA
temperatura = temperatura + 15; // Sin usar asignacin compuesta
temperatura += 15; // Usando asignacin compuesta
#as dos lneas anteriores son e@uivalentesB pues el operador compuesto *& asigna a su primer
operando el valor @ue tena m$s el de su segundo operando =o seaB le suma el segundo operando? Como
se veB permite compactar "astante el cdigo&
-parte del operador de asignacin compuesto *&B tam"i,n se o!recen operadores de asignacin
compuestos para la mayora de los operadores "inarios ya vistos& %stos sonA *&B +&B G&B A&B L&B N&B O&B
P&B HH& y II&& 8tese @ue no (ay versiones compuestas para los operadores "inarios NN y OO&
Otros dos operadores de asignacin incluidos son los de incremento=**? y decremento =++? %stos
operadores permitenB respectivamenteB aumentar y disminuir en una unidad el valor de la varia"le so"re
el @ue se aplican& -sB estas lneas de cdigo son e@uivalentesA
temperatura = temperatura+1;//Sin usar asignacin compuesta ni incremento
temperatura += 1; //Usando asignacin compuesta
temperatura++; //Usando incremento

Si el operador ** se coloca tras el nom"re de la varia"le =como en el ejemplo? devuelve el valor de la
varia"le antes de incrementarlaB mientras @ue si se coloca antesB devuelve el valor de ,sta tras
incrementarlaJ y lo mismo ocurre con el operador ++& Por ejemploA
c = b++; // Se asigna a c el valor de b y luego se incrementa b
c = ++b; // Se incrementa el valor de b y luego se asigna a c
#a ventaja de usar los operadores ** y ++ es @ue en muc(as m$@uinas son m$s e!icientes @ue el resto de
!ormas de reali/ar sumas o restas de una unidadB pues el compilador puede traducirlos en una Cnica
instruccin en cdigo m$@uinaRVS&
"eraciones con cadenas: Para reali/ar operaciones de concatenacin de cadenas se puede
usar el mismo operador @ue para reali/ar sumasB ya @ue en C# se (a rede!inido su signi!icado
para @ue cuando se apli@ue entre operandos @ue sean cadenas o @ue sean una cadena y un
car$cter lo @ue (aga sea concatenarlos& Por ejemploB >Hola>D> mundo> devuelve >Hola
mundo>B y >Hola mund> D fof tam"i,n&
"eraciones de acceso a tablas: 1na tabla es un conjunto de ordenado de o"jetos de tama7o
!ijo& Para acceder a cual@uier elemento de este conjunto se aplica el operador post!ijo -. so"re la
ta"la para indicar entre corc(etes la posicin @ue ocupa el o"jeto al @ue se desea acceder dentro
del conjunto& %s decirB este operador se usa asA
-Hposicin%lemento6.
1n ejemplo de su uso en el @ue se asigna al elemento @ue ocupa la posicin O en una ta"la de nom"re
ta"laPrue"a el valor del elemento @ue ocupa la posicin FG de dic(a ta"la es el siguienteA
tablaPrueba[3] = tablaPrueba[18];
#as ta"las se estudian detenidamente m$s adelante
"erador condicional: %s el Cnico operador incluido en C# @ue toma O operandosB y se usa
asA
<condicin> ! <expresin1> " <expresin2>
%l signi!icado del operando es el siguienteA se evalCa jcondicin6 Si es cierta se devuelve el resultado
de evaluar je*presinF6B y si es !alsa se devuelve el resultado de evaluar jcondicin96& 1n ejemplo de
su uso esA
b = (a>0)? a : 0; // Suponemos a y b de tipos enteros

%n este ejemploB si el valor de la varia"le a es superior a : se asignar$ a " el valor de aB mientras @ue en
caso contrario el valor @ue se le asignar$ ser$ :&
Hay @ue tener en cuenta @ue este operador es asociativo por la derec(aB por lo @ue una e*presin como
a>"Ac>dAe es e@uivalente a a>"A=c>dAe?
8o (ay @ue con!undir este operador con la instruccin condicional if @ue se tratar$ en el Tema
8:"#str$%%io#esB pues aun@ue su utilidad es similar al de ,staB R devuelve un valor e if no&
"eraciones de delegados: 1n delegado es un o"jeto @ue puede almacenar en re!erencias a
uno o m$s m,todos y a trav,s del cual es posi"le llamar a estos m,todos& Para a7adir o"jetos a
un delegado se usan los operadores * y *&B mientras @ue para @uit$rselos se usan los operadores
M y +&& %stos conceptos se estudiar$n detalladamente en su correspondiente tema&
"eraciones de acceso a objetos: Para acceder a los miem"ros de un o"jeto se usa el operador
.B cuya sinta*is esA
<objeto>#<miembro>
Si a es un o"jetoB ejemplos de cmo llamar a di!erentes miem"ros suyos sonA
a.b = 2; // Asignamos a su propiedad a el valor 2
a.f(); // Llamamos a su mtodo f()
a.g(2); // Llamamos a su mtodo g() pasndole como parmetro
// el valor entero 2

8o se preocupe si no conoce los conceptos de m,todosB propiedadesB eventos y delegados en los @ue se
"asa este ejemploB pues se e*plican detalladamente en temas posteriores&
"eraciones con "unteros: 1n "untero es una varia"le @ue almacena una re!erencia a una
direccin de memoria& Para o"tener la direccin de memoria de un o"jeto se usa el operador NB
para acceder al contenido de la direccin de memoria almacenada en un puntero se usa el
operador GB para acceder a un miem"ro de un o"jeto cuya direccin se almacena en un puntero
se usa +IB y para re!erenciar una direccin de memoria de !orma relativa a un puntero se le
aplica el operador -. de la !orma punteroRdespla/amientoS& .odos estos conceptos se e*plicar$n
m$s a !ondo en el Tema &8: C'di(o i#se($ro&
"eraciones de obtenci!n de informaci!n sobre ti"os: )e todos los operadores @ue nos
permiten o"tener in!ormacin so"re tipos de datos el m$s importante es t("eofB cuya !orma de
uso esA
typeof(<nombreTipo>)
%ste operador devuelve un o"jeto de tipo S(stem.T("e con in!ormacin so"re el tipo de nom"re
jnom"re.ipo6 @ue podremos consultar a trav,s de los miem"ros o!recidos por dic(o o"jeto& %sta
in!ormacin incluye detalles tales como cu$les son sus miem"rosB cu$l es su tipo padre o a @u, espacio
de nom"res pertenece&
Si lo @ue @ueremos es determinar si una determinada e*presin es de un tipo u otroB entonces el
operador a usar es isB cuya sinta*is es la siguienteA
<expresin> is <nombreTipo>
%l signi!icado de este operador es el siguienteA se evalCa je*presin6& Si el resultado de ,sta es del tipo
cuyo nom"re se indica en jnom"re.ipo6 se devuelve trueJ y si noB se devuelve false& Como se ver$ en
el Tema 5: ClasesB este operador suele usarse en m,todos polimr!icos&
inalmenteB C# incorpora un tercer operador @ue permite o"tener in!ormacin so"re un tipo de datoA
sizeof %ste operador permite o"tener el nCmero de "ytes @ue ocupar$n en memoria los o"jetos de un
tipoB y se usa asA
sieof(<nombreTipo>)
sizeof slo puede usarse dentro de cdigo inseguroB @ue por a(ora "asta considerar @ue son /onas de
cdigo donde es posi"le usar punteros& 8o ser$ (asta el Tema &8: C'di(o i#se($ro cuando lo
trataremos en pro!undidad&
-dem$sB sizeof slo se puede aplicar so"re nom"res de tipos de datos cuyos o"jetos se puedan
almacenar directamente en pila& %s decirB @ue sean estructuras =se ver$n en el Tema &)? o tipos
enumerados =se ver$n en el Tema &*?
"eraciones de creaci!n de objetosA %l operador m$s tpicamente usado para crear o"jetos es
ne%B @ue se usa asA
new <nombreTipo>(<parametros>)
%ste operador crea un o"jeto de jnom"re.ipo6 pas$ndole a su m,todo constructor los par$metros
indicados en jpar$metros6 y devuelve una re!erencia al mismo& %n !uncin del tipo y nCmero de estos
par$metros se llamar$ a uno u otro de los constructores del o"jeto& -sB suponiendo @ue aF y a9 sean
varia"les de tipo -vinB ejemplos de uso del operador ne% sonA
Avin a1 = new Avin(); // Se llama al constructor sin parmetros
// de Avin
Avin a2 = new Avin("Caza"); // Se llama al constructor de Avin que
// toma como parmetro una cadena
%n caso de @ue el tipo del @ue se (aya solicitado la creacin del o"jeto sea una claseB ,ste se crear$ en
memoria din$micaB y lo @ue ne% devolver$ ser$ una re!erencia a la direccin de pila donde se almacena
una re!erencia a la direccin del o"jeto en memoria din$mica& Sin em"argoB si el o"jeto a crear
pertenece a una estructura o a un tipo enumeradoB entonces ,ste se crear$ directamente en la pila y la
re!erencia devuelta por el ne% se re!erir$ directamente al o"jeto creado& Por estas ra/onesB a las clases
se les conoce como ti"os referencia ya @ue de sus o"jetos en pila slo se almacena una re!erencia a la
direccin de memoria din$mica donde verdaderamente se encuentranJ mientras @ue a las estructuras y
tipos enumerados se les conoce como ti"os valor ya sus o"jetos se almacenan directamente en pila&
C# proporciona otro operador @ue tam"i,n nos permite crear o"jetos& [ste es stac'allocB y se usa asA
stackalloc <nombreTipo>[<nElementos>]
%ste operador lo @ue (ace es crear en pila una ta"la de tantos elementos de tipo jnom"re.ipo6 como
indi@ue jn%lementos6 y devolver la direccin de memoria en @ue ,sta (a sido creada& Por ejemploA
int * p = stackalloc[100]; // p apunta a una tabla de 100 enteros.
stac'alloc slo puede usarse para iniciali/ar punteros a o"jetos de tipos valor declarados como
varia"les locales&
"eraciones de conversi!n: Para convertir unos o"jetos en otros se utili/a el operador de
conversinB @ue no consiste m$s @ue en preceder la e*presin a convertir del nom"re entre
par,ntesis del tipo al @ue se desea convertir el resultado de evaluarla& Por ejemploB si l es una
varia"le de tipo long y se desea almacenar su valor dentro de una varia"le de tipo int llamada iB
(a"ra @ue convertir previamente su valor a tipo int asA

i = (int) l; // Asignamos a i el resultado de convertir el valor de l
// a tipo int
#os tipos int y long est$n prede!inidos en C# y permite almacenar valores enteros con signo& #a
capacidad de int es de O9 "itsB mientras @ue la de long es de ZX "its& Por tantoB a no ser @ue (agamos
uso del operador de conversinB el compilador no nos dejar$ (acer la asignacinB ya @ue al ser mayor la
capacidad de los longB no todo valor @ue se pueda almacenar en un long tiene por@u, poderse
almacenar en un int& %s decirB no es v$lidoA
i = l; //ERROR: El valor de l no tiene porqu caber en i
%sta restriccin en la asignacin la impone el compilador de"ido a @ue sin ella podran producirse
errores muy di!ciles de detectar ante truncamientos no esperados de"ido al @ue el valor de la varia"le
!uente es superior a la capacidad de la varia"le destino&
%*iste otro operador @ue permite reali/ar operaciones de conversin de !orma muy similar al ya visto&
[ste es el operador asB @ue se usa asA
<expresin> as <tipoDestino>
#o @ue (ace es devolver el resultado de convertir el resultado de evaluar je*presin6 al tipo indicado
en jtipo)estino6 Por ejemploB para almacenar en una varia"le p el resultado de convertir un o"jeto t a
tipo tipo Persona se (araA
p = t as Persona;
#as Cnicas di!erencias entre usar uno u otro operador de conversin sonA
o as slo es aplica"le a tipos re!erencia y slo a a@uellos casos en @ue e*istan
conversiones prede!inidas en el lenguaje& Como se ver$ m$s adelanteB esto slo incluye
conversiones entre un tipo y tipos padres suyos y entre un tipo y tipos (ijos suyos&
1na consecuencia de esto es @ue el programador puede de!inir cmo (acer conversiones de tipos por ,l
de!inidos y otros mediante el operador ;<B pero no mediante as&%sto se de"e a @ue as Cnicamente indica
@ue se desea @ue una re!erencia a un o"jeto en memoria din$mica se trate como si el o"jeto !uese de
otro tipoB pero no implica conversin ninguna& Sin em"argoB ;< s @ue implica conversin si el
jtipo)estino6 no es compati"le con el tipo del o"jeto re!erenciado& O"viamenteB el operador se
aplicar$ muc(o m$s r$pido en los casos donde no sea necesario convertir&
o %n caso de @ue se solicite (acer una conversin inv$lida as devuelve null mientras @ue
;< produce una e*cepcin S(stem.InvalidCastE)ce"tion&
Instrucciones
Conce"to de instrucci!n
.oda accin @ue se pueda reali/ar en el cuerpo de un m,todoB como de!inir varia"les localesB llamar
a m,todosB asignaciones y muc(as cosas m$s @ue veremos a lo largo de este temaB son instrucciones&
#as instrucciones se agrupan !ormando bloSues de instruccionesB @ue son listas de instrucciones
encerradas entre llaves @ue se ejecutan una tras otra& %s decirB la sinta*is @ue se sigue para de!inir un
"lo@ue de instrucciones esA
{
<listaInstrucciones>
}

.oda varia"le @ue se de!ina dentro de un "lo@ue de instrucciones slo e*istir$ dentro de dic(o
"lo@ue& .ras ,l ser$ inaccesi"le y podr$ ser destruida por el recolector de "asura& Por ejemploB este
cdigo no es v$lidoA
public void f();
{
{ int b; }
b = 1; // ERROR: b no existe fuera del bloque donde se declar
}
#os "lo@ues de instrucciones pueden anidarseB aun@ue si dentro de un "lo@ue interno de!inimos una
varia"le con el mismo nom"re @ue otra de!inida en un "lo@ue e*terno se considerar$ @ue se (a
producido un errorB ya @ue no se podr$ determinar a cu$l de las dos se estar$ (aciendo re!erencia cada
ve/ @ue se utilice su nom"re en el "lo@ue interno&
Instrucciones bsicas
!e"iniciones de #ariables locales
%n el Tema 7: Variables ti!os de datos se vio @ue las variables locales son varia"les @ue se
de!inen en el cuerpo de los m,todos y slo son accesi"les desde dic(os cuerpos& +ecu,rdese @ue la
sinta*is e*plicada para de!inirlas era la siguienteA
<modificadores> <tipoVariable> <nombreVariable> = <valor>$
.am"i,n ya entonces se vio @ue podan de!inirse varias varia"les en una misma instruccin
separando sus pares nom"re5valor mediante comasB como en por ejemploA
int a=5, b, c=-1;

Asi$naciones
1na asignaci!n es simplemente una instruccin mediante la @ue se indica un valor a almacenar en
un dato& #a sinta*is usada para ello esA
<destino> % <origen>$
%n temas previos ya se (an dado numerosos ejemplos de cmo (acer estoB por lo @ue no es necesario
(acer a(ora mayor (incapi, en ello&
%lamadas a m&todos
%n el Tema 8: Mtodos ya se e*plic @ue una llamada a un mKtodo consiste en solicitar la
ejecucin de sus instrucciones asociadas dando a sus par$metros ciertos valores& Si el m,todo a llamar
es un m,todo de o"jetoB la sinta*is usada para ello esA
<objeto>#<nombreMtodo>(<valoresParmetros>)$
W si el m,todo a llamar es un m,todo de tipoB entonces la llamada se reali/a conA
<nombreTipo>.<nombreMtodo>(<valoresParmetros>)$

+ecu,rdese @ue si la llamada al m,todo de tipo se (ace dentro de la misma de!inicin de tipo donde
el m,todo !ue de!inidoB la seccin +#ombreTi!o,. de la sinta*is es opcional&
'nstruccin nula
#a instrucci!n nula es una instruccin @ue no reali/a nada en a"soluto& Su sinta*is consiste en
escri"ir un simple punto y coma para representarla& O seaB esA
$
Suele usarse cuando se desea indicar e*plcitamente @ue no se desea ejecutar nadaB lo @ue es Ctil para
!acilitar la legi"ilidad del cdigo oB como veremos m$s adelante en el temaB por@ue otras instrucciones
la necesitan para indicar cu$ndo en algunos de sus "lo@ues de instrucciones componentes no se (a de
reali/ar ninguna accin&
Estructuras de control
#as instrucciones condicionales son instrucciones @ue permiten ejecutar "lo@ues de instrucciones
slo si se da una determinada condicin& %n los siguientes su"apartados de este epgra!e se descri"en
cu$les son las instrucciones condicionales disponi"les en C#
'nstruccin i"
#a instrucci!n if permite ejecutar ciertas instrucciones slo si de da una determinada condicin& Su
sinta*is de uso es la sinta*isA
if (<condicin>){
<instruccionesIf>}
else{
<instruccionesElse>}
%l signi!icado de esta instruccin es el siguienteA se evalCa la e*presin jcondicin6B @ue (a de
devolver un valor lgico& Si es cierta =devuelve true? se ejecutan las jinstruccionesI!6B y si es !alsa
=false? se ejecutan las jinstrucciones%lse6 #a rama else es opcionalB y si se omite y la condicin es
!alsa se seguira ejecutando a partir de la instruccin siguiente al if& %n realidadB tanto jinstruccionesI!6
como jinstrucciones%lse6 pueden ser una Cnica instruccin o un "lo@ue de instrucciones&
1n ejemplo de aplicacin de esta instruccin es esta variante del HolaMundoA
using System;
class HolaMundoIf
{
public static void Main(String[] args)
{
if (args.Length > 0){
Console.WriteLine("Hola {0}!", args[0]);}
else{
Console.WriteLine("Hola mundo!");}
}
}
Si ejecutamos este programa sin ningCn argumento veremos @ue el mensaje @ue se muestra es QHola
Mundo!B mientras @ue si lo ejecutamos con algCn argumento se mostrar$ un mensaje de "ienvenida
personali/ado con el primer argumento indicado&
'nstruccin s(itc)
#a instrucci!n s%itch permite ejecutar unos u otros "lo@ues de instrucciones segCn el valor de una
cierta e*presin& Su estructura esA
switch (<expresin>)
{
case <valor1>: <bloque1>
<siguienteAccin>
case <valor2>: <bloque2>
<siguienteAccin>
...
default: <bloqueDefault>
<siguienteAccin>
}
%l signi!icado de esta instruccin es el siguienteA se evalCa & Si su valor es se ejecuta el B si es se
ejecuta B y as para el resto de valores especi!icados& Si no es igual a ninguno de esos valores y se
incluye la rama defaultB se ejecuta el J pero si no se incluye se pasa directamente a ejecutar la
instruccin siguiente al s%itch&
#os valores indicados en cada rama del s%itch (an de ser e*presiones constantes @ue produ/can
valores de algCn tipo "$sico enteroB de una enumeracinB de tipo char o de tipo string& -dem$sB no
puede (a"er m$s de una rama con el mismo valor&
%n realidadB aun@ue todas las ramas de un s%itch son opcionales siempre se (a de incluir al menos
una& -dem$sB la rama default no tiene por@u, aparecer la Cltima si se usaB aun@ue es recomenda"le @ue
lo (aga para !acilitar la legi"ilidad del cdigo&
%l elemento marcado como jsiguiente-ccin6 colocado tras cada "lo@ue de instrucciones indica
@u, es lo @ue (a de (acerse tras ejecutar las instrucciones del "lo@ue @ue lo preceden& Puede ser uno de
estos tres tipos de instruccionesA
goto case <valori>;
goto default;
break;

Si es un goto case indica @ue se (a de seguir ejecutando el "lo@ue de instrucciones asociado en el
s%itch a la rama del jvalori6 indicadoB si es un goto default indica @ue se (a de seguir ejecutando el
"lo@ue de instrucciones de la rama defaultB y si es un brea' indica @ue se (a de seguir ejecutando la
instruccin siguiente al s'itc(&
%l siguiente ejemplo muestra cmo se utili/a s%itchA
using System;
class HolaMundoSwitch
{
public static void Main(String[] args)
{
if (args.Length > 0)
switch(args[0])
{
case "Jos":
Console.WriteLine("Hola Jos. Buenos das");
break;
case "Paco":
Console.WriteLine("Hola Paco. Me alegro de verte");
break;
default:
Console.WriteLine("Hola {0}", args[0]);
break;
}
else
Console.WriteLine("Hola Mundo");
}
}
%ste programa reconoce ciertos nom"res de personas @ue se le pueden pasar como argumentos al
lan/arlo y les saluda de !orma especial& #a rama default se incluye para dar un saludo por de!ecto a las
personas no reconocidas&
Para los programadores (a"ituados a lenguajes como CDD es importante resaltarles el (ec(o de @ueB
a di!erencia de dic(os lenguajesB C# o"liga a incluir una sentencia brea' o una sentencia goto case al
!inal de cada rama del s%itch para evitar errores comunes y di!ciles de detectar causados por olvidar
incluir brea'T al !inal de alguno de estos "lo@ues y ello provocar @ue tras ejecutarse ese "lo@ue se
ejecute tam"i,n el siguiente&
Instrucciones iterativas
#as instrucciones iterativas son instrucciones @ue permiten ejecutar repetidas veces una instruccin
o un "lo@ue de instrucciones mientras se cumpla una condicin& %s decirB permiten de!inir "ucles donde
ciertas instrucciones se ejecuten varias veces& - continuacin se descri"en cu$les son las instrucciones
de este tipo incluidas en C#&
'nstruccin ()ile
#a instrucci!n %hile permite ejecutar un "lo@ue de instrucciones mientras se de una cierta
instruccin& Su sinta*is de uso esA
while (<condicin>)
{
<instrucciones>
}
Su signi!icado es el siguienteA Se evalCa la jcondicin6 indicadaB @ue (a de producir un valor lgico&
Si es cierta =valor lgico true? se ejecutan las jinstrucciones6 y se repite el proceso de evaluacin de
jcondicin6 y ejecucin de jinstrucciones6 (asta @ue deje de serlo& Cuando sea !alsa =false? se pasar$
a ejecutar la instruccin siguiente al %hile& %n realidad jinstrucciones6 puede ser una Cnica instruccin
o un "lo@ue de instrucciones&
1n ejemplo cmo utili/ar esta instruccin es el siguienteA
using System;
class HolaMundoWhile
{
public static void Main(&tring[] args)
{
int actual = 0;
if (args.Length > 0)
while (actual < args.Length)
{
Console.WriteLine("Hola {0}!", args[actual]);
actual = actual + 1;
}
else
Console.WriteLine("Hola mundo!");
}
}
%n este casoB si se indica m$s de un argumento al llamar al programa se mostrar$ por pantalla un
mensaje de saludo para cada uno de ellos& Para ello se usa una varia"le actual @ue almacena cu$l es el
nCmero de argumento a mostrar en cada ejecucin del %hile& Para mantenerla siempre actuali/ada lo
@ue se (ace es aumentar en una unidad su valor tras cada ejecucin de las jinstrucciones6 del "ucle&
Por otro ladoB dentro de las jinstrucciones6 de un %hile pueden utili/arse las siguientes dos
instrucciones especialesA
brea'TA Indica @ue se (a de a"ortar la ejecucin del "ucle y continuarse ejecutando por la
instruccin siguiente al %hile&
continueTA Indica @ue se (a de a"ortar la ejecucin de las jinstrucciones6 y reevaluarse la
jcondicin6 del "ucleB volvi,ndose a ejecutar las jinstrucciones6 si es cierta o pas$ndose a
ejecutar la instruccin siguiente al %hile si es !alsa&
'nstruccin do...()ile
#a instruccin do...%hile es una variante del %hile @ue se usa asA
do {
<instrucciones>
} while(<condicin>);

#a Cnica di!erencia del signi!icado de do...%hile respecto al de %hile es @ue en ve/ de evaluar
primero la condicin y ejecutar jinstrucciones6 slo si es ciertaB do...%hile primero ejecuta las
jinstrucciones6 y luego mira la jcondicin6 para ver si se (a de repetir la ejecucin de las mismas& Por
lo dem$s am"as instrucciones son igualesB e incluso tam"i,n puede incluirse brea'T y continueT entre
las jinstrucciones6 del do...%hile&
do ... %hile est$ especialmente destinado para los casos en los @ue (aya @ue ejecutar las
jinstrucciones6 al menos una ve/ aCn cuando la condicin sea !alsa desde el principioB como ocurre en
el siguiente ejemploA

using System;
class HolaMundoDoWhile
{
public static void Main()
{
&tring ledo;
do
{
Console.WriteLine("Clave: ");
ledo = Console.ReadLine();
}
while (ledo != "Jos");
Console.WriteLine("Hola Jos");
}
}
%ste programa pregunta al usuario una clave y mientras no introdu/ca la correcta =Eos,? no
continuar$ ejecut$ndose& 1na ve/ @ue introducida correctamente dar$ un mensaje de "ienvenida al
usuario&
'nstruccin "or
#a instrucci!n for es una variante de %hile @ue permite reducir el cdigo necesario para escri"ir los
tipos de "ucles m$s comCnmente usados en programacin& Su sinta*is esA
for (<inicializacin>; <condicin>; <modificacin>){
<instrucciones>
}
%l signi!icado de esta instruccin es el siguienteA se ejecutan las instrucciones de jiniciali/acin6B
@ue suelen usarse para de!inir e iniciali/ar varia"les @ue luego se usar$n en jinstrucciones6& #uego se
evalCa jcondicin6B y si es !alsa se continCa ejecutando por la instruccin siguiente al forJ mientras
@ue si es cierta se ejecutan las jinstrucciones6 indicadasB luego se ejecutan las instrucciones de
jmodi!icacin6 5@ue como su nom"re indica suelen usarse para modi!icar los valores de varia"les @ue
se usen en jinstrucciones65 y luego se reevalCa jcondicin6 repiti,ndose el proceso (asta @ue ,sta
Cltima deje de ser cierta&
%n jiniciali/acin6 puede en realidad incluirse cual@uier nCmero de instrucciones @ue no tienen
por@u, ser relativas a iniciali/ar varia"les o modi!icarlasB aun@ue lo anterior sea su uso m$s (a"itual&
%n caso de ser varias se (an de separar mediante comas =U?B ya @ue el car$cter de punto y coma =T?
(a"itualmente usado para estos menesteres se usa en el for para separar los "lo@ues de
jiniciali/acin6B jcondicin6 y jmodi!icacin6 -dem$sB la instruccin nula no se puede usar en este
caso y tampoco pueden com"inarse de!iniciones de varia"les con instrucciones de otros tipos&
Con jmodi!icacin6 pasa algo similarB ya @ue puede incluirse cdigo @ue nada tenga @ue ver con
modi!icaciones pero en este caso no se pueden incluir de!iniciones de varia"les&
Como en el resto de instrucciones (asta a(ora vistasB en jinstrucciones6 puede ser tanto una Cnica
instruccin como un "lo@ue de instrucciones& -dem$sB las varia"les @ue se de!inan en jiniciali/acin6
ser$n visi"les slo dentro de esas jinstrucciones6&
#a siguiente clase es e@uivalente a la clase HolaMundoN(ile ya vista solo @ue (ace uso del for para
compactar m$s su cdigoA
using System;
class HolaMundoFor
{
public static void Main(&tring[] args)
{
if (args.Length > 0)
for (int actual = 0; actual < args.Length; actual++) {
Console.WriteLine("Hola {0}!", args[actual]);
}
else
Console.WriteLine("Hola mundo!");
}
}
-l igual @ue con %hileB dentro de las jinstrucciones6 del for tam"i,n pueden incluirse instrucciones
continueT y brea'T @ue puedan alterar el !uncionamiento normal del "ucle&
'nstruccin "oreac)
#a instrucci!n foreach es una variante del for pensada especialmente para compactar la escritura de
cdigos donde se realice algCn tratamiento a todos los elementos de una coleccinB @ue suele un uso
muy (a"itual de for en los lenguajes de programacin @ue lo incluyen& #a sinta*is @ue se sigue a la
(ora de escri"ir esta instruccin foreach esA
foreach (<tipoElemento> <elemento> in <coleccin>) {
<instrucciones>
}
%l signi!icado de esta instruccin es muy sencilloA se ejecutan jinstrucciones6 para cada uno de los
elementos de la jcoleccin6 indicada& jelemento6 es una varia"le de slo lectura de tipo
jtipo%lemento6 @ue almacenar$ en cada momento el elemento de la coleccin @ue se est, procesando
y @ue podr$ ser accedida desde jinstrucciones6&
%s importante se7alar @ue jcoleccin6 no puede valer null por@ue entonces saltara una e*cepcin
de tipo S(stem.NullCeferenceE)ce"tionB y @ue jtipo%lemento6 (a de ser un tipo cuyos o"jetos
puedan almacenar los valores de los elementos de jcoleccin6
%n tanto @ue una ta"la se considera @ue es una coleccinB el siguiente cdigo muestra cmo usar for
para compactar aCn m$s el cdigo de la clase HolaMundoor anteriorA
using System;
class HolaMundoForeach
{
public static void Main(&tring[] args)
{
if (args.Length > 0)
foreach(&tring arg in args) {
Console.WriteLine("Hola {0}!", arg);
}
else
Console.WriteLine("Hola mundo!");
}
}
#as ta"las multidimensionales tam"i,n pueden recorrerse mediante el foreachB el cual pasar$ por sus
elementos en orden tal y como muestra el siguiente !ragmento de cdigoA
int[,] tabla = { {1,2}, {3,4} };
foreach (int elemento in tabla)
Console.WriteLine(elemento);
Cuya salida por pantalla esA
F
9
O
X
%n generalB se considera @ue una coleccin es todo a@uel o"jeto @ue implemente las inter!aces
IEnumerable o IEnumerator del espacio de nom"res S(stem.Collections de la 0C#B @ue est$n
de!inidas como sigueA
interface '(numerable
{
[C#]
'(numerator GetEnumerator();
}
interface '(numerator
{
[C#]
object Current {get;}
[C#]
bool MoveNext();
[C#]
void Reset();
}
%l m,todo Ceset;< (a de implementarse de modo @ue devuelva el enumerador reiniciado a un estado
inicial donde aCn no re!erencie ni si@uiera al primer elemento de la coleccin sino @ue sea necesario
llamar a MoveNe)t;< para @ue lo (aga&
%l m,todo MoveNe)t;< se (a de implementar de modo @ue (aga @ue el enumerador pase a apuntar al
siguiente elemento de la coleccin y devuelva un "ooleano @ue indi@ue si tras avan/ar se (a alcan/ado
el !inal de la coleccin&
#a propiedad Current se (a de implementar de modo @ue devuelva siempre el elemento de la
coleccin al @ue el enumerador est, re!erenciando& Si se intenta leer Current (a"i,ndose ya recorrido
toda la coleccin o (a"i,ndose reiniciado la coleccin y no (a"i,ndose colocado en su primer elemento
con MoveNe)t;<B se (a de producir una e*cepcin de tipo
S(stem.E)ce"tion.S(stemE)ce"tion.Invalid"erationE)ce"tion
Otra !orma de conseguir @ue foreach considere @ue un o"jeto es una coleccin v$lida consiste en
(acer @ue dic(o o"jeto siga el "atr!n de colecci!n& %ste patrn consiste en de!inir el tipo del o"jeto de
modo @ue sus o"jetos cuenten con un m,todo pC"lico #etEnumerator;< @ue devuelva un o"jeto no
nulo @ue cuente con una propiedad pC"lica llamada Current @ue permita leer el elemento actual y con
un m,todo pC"lico bool MoveNe)t;< @ue permita cam"iar el elemento actual por el siguiente y
devuelva false slo cuando se (aya llegado al !inal de la coleccin&
%l siguiente ejemplo muestra am"os tipos de implementacionesA
using System;
using System.Collections;
class Patron
{
private int actual = -1;
public Patron GetEnumerator()
{
return this;
}

public int Current
{
get {return actual;}
}

public bool MoveNext()
{
bool resultado = true;
actual++;
if (actual==10)
resultado = false;
return resultado;
}
}
class Interfaz:'(numerable,'(numerator
{
private int actual = -1;
public object Current
{
get {return actual;}
}

public bool MoveNext()
{
bool resultado = true;
actual++;
if (actual==10)
resultado = false;
return resultado;
}

public '(numerator GetEnumerator()
{
return this;
}

public void Reset()
{
actual = -1;
}
}
class Principal
{
public static void Main()
{
Patron obj = new Patron();
Interfaz obj2 = new Interfaz();
foreach (int elem in obj)
Console.WriteLine(elem);
foreach (int elem in obj2)
Console.WriteLine(elem);
}
}
8tese @ue en realidad en este ejemplo no (ara !alta implementar IEnumerableB puesto @ue la clase
Inter!a/ ya implementa IEnumerator y ello es su!iciente para @ue pueda ser recorrida mediante
foreach&
#a utilidad de implementar el patrn coleccin en lugar de la inter!a/ IEnumerable es @ue as no es
necesario @ue Current devuelva siempre un objectB sino @ue puede devolver o"jetos de tipos m$s
concretos y gracias a ello puede detectarse al compilar si el jtipo%lemento6 indicado puede o no
almacenar los o"jetos de la coleccin&
Por ejemploB si en el ejemplo anterior sustituimos en el Cltimo foreach el jtipo%lemento6 indicado
por PatrnB el cdigo seguir$ compilando pero al ejecutarlo saltar$ una e*cepcin
S(stem.InvalidCastE)ce"tion& Sin em"argoB si la sustitucin se (u"iese (ec(o en el penCltimo
foreachB entonces el cdigo directamente no compilara y se nos in!ormara de un error de"ido a @ue
los o"jetos int no son converti"les en o"jetos Patrn&
.am"i,n (ay @ue tener en cuenta @ue la compro"acin de tipos @ue se reali/a en tiempo de
ejecucin si el o"jeto slo implement la inter!a/ IEnumerable es muy estrictaB en el sentido de @ue si
en el ejemplo anterior sustituimos el jtipo%lemento6 del Cltimo foreach por b(te tam"i,n se lan/ar$ la
e*cepcin al no ser los o"jetos de tipo int implcitamente converti"les en b(tes sino slo a trav,s del
operador ;< Sin em"argoB cuando se sigue el patrn de coleccin las compro"aciones de tipo no son tan
estrictas y entonces s @ue sera v$lido sustituir int por b(te en jtipo%lemento6&
%l pro"lema de slo implementar el patrn coleccin es @ue este es una caracterstica propia de C# y
con las instrucciones foreach =o e@uivalentes? de lenguajes @ue no lo soporten no se podra recorrer
colecciones @ue slo siguiesen este patrn& 1na solucin en estos casos puede ser (acer @ue el tipo del
o"jeto coleccin implemente tanto la inter!a/ IEnumerable como el patrn coleccin& O"viamente esta
inter!a/ de"era implementarse e*plcitamente para evitarse con!lictos derivados de @ue sus miem"ros
tengan signaturas coincidentes con las de los miem"ros propios del patrn coleccin&
Si un o"jeto de un tipo coleccin implementa tanto la inter!a/ IEnumerable como el patrn de
coleccinB entonces en C# foreach usar$ el patrn coleccin para recorrerlo&
Eefinici!n de clases
Conceptos de clase y objeto
C# es un lenguaje orientado a o"jetos puroRZSB lo @ue signi!ica @ue todo con lo @ue vamos a tra"ajar
en este lenguaje son o"jetos& 1n objeto es un agregado de datos y de m,todos @ue permiten manipular
dic(os datosB y un programa en C# no es m$s @ue un conjunto de o"jetos @ue interaccionan unos con
otros a trav,s de sus m,todos&
1na clase es la de!inicin de las caractersticas concretas de un determinado tipo de o"jetos& %s
decirB de cu$les son los datos y los m,todos de los @ue van a disponer todos los o"jetos de ese tipo& Por
esta ra/nB se suele decir @ue el ti"o de dato de un o"jeto es la clase @ue de!ine las caractersticas del
mismoRYS&
Sinta*is de de"inicin de clases
#a sinta*is "$sica para de!inir una clase es la @ue a continuacin se muestraA
class <nombreClase>
{
<miembros>
}
)e este modo se de!inira una clase de nom"re cuyos miem"ros son los de!inidos en & #os miembros
de una clase son los datos y m,todos de los @ue van a disponer todos los o"jetos de la misma& 1n
ejemplo de cmo declarar una clase de nom"re - @ue no tenga ningCn miem"ro es la siguienteA
class A
{}
1na clase as declarada no dispondr$ de ningCn miem"ro a e*cepcin de los implcitamente
de!inidos de manera comCn para todos los o"jetos @ue creemos en C#& %stos miem"ros los veremos
dentro de poco en este mismo tema "ajo el epgra!e -a %lase !rime(i#a: Sstem..b/e%t&
-un@ue en C# (ay muc(os tipos de miem"ros distintosB por a(ora vamos a considerar @ue ,stos
Cnicamente pueden ser campos o m,todos y vamos a (a"lar un poco acerca de ellos y de cmo se
de!inenA
Cam"os: 1n cam"o es un dato comCn a todos los o"jetos de una determinada clase& Para
de!inir cu$les son los campos de los @ue una clase dispone se usa la siguiente sinta*is dentro de
la /ona se7alada como jmiem"ros6 en la de!inicin de la mismaA
<tipoCampo> <nombreCampo>$
%l nom"re @ue demos al campo puede ser cual@uier identi!icador @ue @ueramos siempre y cuando siga
las reglas descritas en el Tema *: 0s!e%tos -1i%os para la escritura de identi!icadores y no coincida
con el nom"re de ningCn otro miem"ro previamente de!inido en la de!inicin de clase&
#os campos de un o"jeto son a su ve/ o"jetosB y en jtipoCampo6 (emos de indicar cu$l es el tipo de
dato del o"jeto @ue vamos a crear& [ste tipo puede corresponderse con cual@uiera @ue los prede!inidos
en la 0C# o con cual@uier otro @ue nosotros (allamos de!inido siguiendo la sinta*is arri"a mostrada& -
continuacin se muestra un ejemplo de de!inicin de una clase de nom"re Persona @ue dispone de tres
camposA
class Persona
{
string Nombre;// Campo de cada objeto Persona que almacena su nombre
int Edad; // Campo de cada objeto Persona que almacena su edad
string NIF; // Campo de cada objeto Persona que almacena su NIF
}
SegCn esta de!inicinB todos los o"jetos de clase Persona incorporar$n campos @ue almacenar$n cu$l
es el nom"re de la persona @ue cada o"jeto representaB cu$l es su edad y cu$l es su 8I& %l tipo int
incluido en la de!inicin del campo %dad es un tipo prede!inido en la 0C# cuyos o"jetos son capaces
de almacenar nCmeros enteros con signo comprendidos entre 59&FXY&XGO&ZXG y 9&FXY&XGO&ZXY =O9 "its?B
mientras @ue string es un tipo prede!inido @ue permite almacenar cadenas de te*to @ue sigan el !ormato
de los literales de cadena visto en el Tema *: 0s!e%tos -1i%os
Para acceder a un campo de un determinado o"jeto se usa la sinta*isA
<objeto>#<campo>
Por ejemploB para acceder al campo %dad de un o"jeto Persona llamado p y cam"iar su valor por 9:
se (araA
p.edad = 20;
%n realidad lo marcado como jo"jeto6 no tiene por@u, ser necesariamente el nom"re de algCn
o"jetoB sino @ue puede ser cual@uier e*presin @ue produ/ca como resultado una re!erencia no nula a
un o"jeto =si produjese null se lan/ara una e*cepcin del tipo prede!inido
S(stem.Null1ointerE)ce"tion?
MetodosA1n mKtodo es un conjunto de instrucciones a las @ue se les asocia un nom"re de
modo @ue si se desea ejecutarlas "asta re!erenciarlas a trav,s de dic(o nom"re en ve/ de tener
@ue escri"irlas& )entro de estas instrucciones es posi"le acceder con total li"ertad a la
in!ormacin almacenada en los campos pertenecientes a la clase dentro de la @ue el m,todo se
(a de!inidoB por lo @ue como al principio del tema se indicB los m,todos permiten manipular
los datos almacenados en los o"jetos&
#a sinta*is @ue se usa en C# para de!inir los m,todos es la siguienteA
<tipoDevuelto> <nombreMtodo> (<parametros>)
{
<instrucciones>
}
.odo m,todo puede devolver un o"jeto como resultado de la ejecucin de las instrucciones @ue lo
!ormanB y el tipo de dato al @ue pertenece este o"jeto es lo @ue se indica en jtipo)evuelto6& Si no
devuelve nada se indica voidB y si devuelve algo es o"ligatorio !inali/ar la ejecucin de sus
instrucciones con alguna instruccin return jo"jeto6T @ue indi@ue @u, o"jeto (a de devolverse&
Opcionalmente todo m,todo puede reci"ir en cada llamada una lista de o"jetos a los @ue podr$
acceder durante la ejecucin de sus instrucciones& %n +!arametros, se indica es cu$les son los tipos de
dato de estos o"jetos y cu$l es el nom"re con el @ue (ar$n re!erencia las instrucciones del m,todo a
cada uno de ellos& -un@ue los o"jetos @ue puede reci"ir el m,todo pueden ser di!erentes cada ve/ @ue
se solicite su ejecucinB siempre (an de ser de los mismos tipos y (an de seguir el orden esta"lecido en
+!arametros,&
1n ejemplo de cmo declarar un m,todo de nom"re Cumplea7os es la siguiente modi!icacin de la
de!inicin de la clase Persona usada antes como ejemploA
class Persona
{
string Nombre;//Campo de cada objeto Persona que almacena su nombre
int Edad; //Campo de cada objeto Persona que almacena su edad
string NIF; //Campo de cada objeto Persona que almacena su NIF

void Cumpleaos()//Incrementa en uno de la edad del objeto Persona
{
Edad++;
}
}
#a sinta*is usada para llamar a los m,todos de un o"jeto es la misma @ue la usada para llamar a sus
camposB slo @ue a(ora tras el nom"re del m,todo al @ue se desea llamar (ay @ue indicar entre
par,ntesis cu$les son los valores @ue se desea dar a los par$metros del m,todo al (acer la llamada& O
seaB se escri"eA
<objeto>#<mtodo>(<parmetros>)
Como es lgicoB si el m,todo no tomase par$metros se dejaran vacos los par$metros en la llamada al
mismo& Por ejemploB para llamar al m,todo Cumplea7os=? de un o"jeto Persona llamado p se (araA
p.Cumpleaos(); // El mtodo no toma parmetros,
// luego no le pasamos ninguno
%s importante se7alar @ue en una misma clase pueden de!inirse varios m,todos con el mismo nom"re
siempre y cuando tomen di!erente nCmero o tipo de par$metros& - esto se le conoce como sobrecarga
de mKtodosB y es posi"le ya @ue el compilador sa"r$ a cual llamar a partir de los +!ar2metros,
especi!icados&
Sin em"argoB lo @ue no se permite es de!inir varios m,todos @ue Cnicamente se di!erencien en su valor
de retornoB ya @ue como ,ste no se tiene por@u, indicar al llamarlos no podra di!erenciarse a @ue
m,todo en concreto se (ace re!erencia en cada llamada& Por ejemploB a partir de la llamadaA
p.Cumpleaos();
Si adem$s de la versin de Cumplea7os=? @ue no retorna nada (u"iese otra @ue retornase un intB kcmo
sa"ra entonces el compilador a cu$l llamar>
-ntes de continuar es preciso se7alar @ue en C# todoB incluido los literalesB son o"jetos del tipo de cada
literal y por tanto pueden contar con miem"ros a los @ue se accedera tal y como se (a e*plicado& Para
entender esto no (ay nada mejor @ue un ejemploA
string s = 12.ToString();
%ste cdigo almacena el literal de cadena KF9L en la varia"le sB pues F9 es un o"jeto de tipo int =tipo
@ue representa enteros? y cuenta cuenta con el m,todo comCn a todos los ints llamado ToString;< @ue
lo @ue (ace es devolver una cadena cuyos caracteres son los dgitos @ue !orman el entero representado
por el int so"re el @ue se aplicaJ y como la varia"le s es de tipo string =tipo @ue representa cadenas? es
per!ectamente posi"le almacenar dic(a cadena en ellaB @ue es lo @ue se (ace en el cdigo anterior&
Creaci!n de objetos
Operador new
Ahora 2ue ya sa*emos cmo de#inir las clases de o*je!os 2ue podremos usar en nues!ras
aplicaciones ha llegado el momen!o de e5plicar cmo crear o*je!os de una de!erminada clase$
Algo de ello ya se in!rodujo en el 'ema 67 Aspec!os 85icos cuando se comen! la u!ilidad del
operador ne9+ 2ue precisamen!e es crear o*je!os y cuya sin!a5is es7
new <nombreTipo>(<parametros>)
%ste operador crea un nuevo o"jeto del tipo cuyo nom"re se le indica y llama durante su proceso de
creacin al constructor del mismo apropiado segCn los valores @ue se le pasen en jparametros6B
devolviendo una re!erencia al o"jeto reci,n creado& Hay @ue resaltar el (ec(o de @ue ne% no devuelve
el propio o"jeto creadoB sino una re!erencia a la direccin de memoria din$mica donde en realidad se (a
creado&
%l antes comentado constructor de un o"jeto no es m$s @ue un m,todo de!inido en la de!inicin de
su tipo @ue tiene el mismo nom"re @ue la clase a la @ue pertenece el o"jeto y no tiene valor de retorno&
Como ne% siempre devuelve una re!erencia a la direccin de memoria donde se cree el o"jeto y los
constructores slo pueden usarse como operandos de ne%B no tiene sentido @ue un constructor
devuelva o"jetosB por lo @ue no tiene sentido incluir en su de!inicin un campo jtipo)evuelto6 y el
compilador considera errneo (acerlo =aun@ue se indi@ue void?
%l constructor reci"e ese nom"re de"ido a @ue su cdigo suele usarse precisamente para construir el
o"jetoB para iniciali/ar sus miem"ros& Por ejemploB a nuestra clase de ejemplo Persona le podramos
a7adir un constructor dej$ndola asA
class Persona
{
string Nombre; // Campo de cada objeto Persona que almacena su nombre
int Edad; // Campo de cada objeto Persona que almacena su edad
string NIF; // Campo de cada objeto Persona que almacena su NIF

void Cumpleaos() // Incrementa en uno la edad del objeto Persona
{
Edad++;
}

Persona (string nombre, int edad, string nif) // Constructor
{
Nombre = nombre;
Edad = edad;
NIF = nif;
}
}

Como se ve en el cdigoB el constructor toma como par$metros los valores con los @ue deseemos
iniciali/ar el o"jeto a crear& ;racias a ,lB podemos crear un o"jeto Persona de nom"re Eos,B de 99 a7os
de edad y 8I F9OXXO9F5- asA
new Persona("Jos", 22, "12344321-A")
8tese @ue la !orma en @ue se pasan par$metros al constructor consiste en indicar los valores @ue se
(a de dar a cada uno de los par$metros indicados en la de!inicin del mismo separ$ndolos por comas&
O"viamenteB si un par$metro se de!ini como de tipo string (a"r$ @ue pasarle una cadenaB si se de!ini
de tipo int (a"r$ @ue pasarle un entero yB en generalB a todo par$metro (a"r$ @ue pasarle un valor de su
mismo tipo =o de alguno converti"le al mismo?B produci,ndose un error al compilar si no se (ace as&
%n realidad un o"jeto puede tener mCltiples constructoresB aun@ue para di!erenciar a unos de otros es
o"ligatorio @ue se di!erencien en el nCmero u orden de los par$metros @ue aceptanB ya @ue el nom"re
de todos ellos (a de coincidir con el nom"re de la clase de la @ue son miem"ros& )e ese modoB cuando
creemos el o"jeto el compilador podr$ inteligentemente determinar cu$l de los constructores (a de
ejecutarse en !uncin de los valores @ue le pasemos al ne%&
1na ve/ creado un o"jeto lo m$s normal es almacenar la direccin devuelta por ne% en una varia"le
del tipo apropiado para el o"jeto creado& %l siguiente ejemplo 5@ue como es lgico ir$ dentro de la
de!inicin de algCn m,todo5 muestra cmo crear una varia"le de tipo Persona llamada p y cmo
almacenar en ella la direccin del o"jeto @ue devolvera la anterior aplicacin del operador ne%A
Persona p; // Creamos variable p
p = new Persona("Jose", 22, "12344321-A");
// Almacenamos en p el objeto creado con new
- partir de este momento la varia"le p contendr$ una re!erencia a un o"jeto de clase Persona @ue
representar$ a una persona llamada Eos, de 99 a7os y 8I F9OXXO9F5-& O lo @ue pr$cticamente es lo
mismo y suele ser la !orma comCnmente usada para decirloA la varia"le p representa a una persona
llamada Eos, de 99 a7os y 8I F9OXXO9F5-&
Como lo m$s normal suele ser crear varia"les donde almacenar re!erencias a o"jetos @ue creemosB
las instrucciones anteriores pueden compactarse en una sola asA
Persona p = new Persona("Jos", 22, "12344321-A");
)e (ec(oB una sinta*is m$s general para la de!inicin de varia"les es la siguienteA
<tipoDato> <nombreVariable> = <valorInicial>$
#a parte M jvalorInicial6 de esta sinta*is es en realidad opcionalB y si no se incluye la varia"le
declarada pasar$ a almacenar una re!erencia nula =contendr$ el literal null?
Constructor por de"ecto
8o es o"ligatorio de!inir un constructor para cada claseB y en caso de @ue no de!inamos ninguno el
compilador crear$ uno por nosotros sin par$metros ni instrucciones& %s decirB como si se (u"iese
de!inido de esta !ormaA
<nombreTipo>(){}
;racias a este constructor introducido autom$ticamente por el compiladorB si Coc(e es una clase en
cuya de!inicin no se (a incluido ningCn constructorB siempre ser$ posi"le crear uno nuevo usando el
operador ne% asA
Coche c = new Coche(); //Crea coche c llamando al constructor por defecto
de Coche

Hay @ue tener en cuenta una cosaA el constructor por de!ecto es slo incluido por el compilador si no
(emos de!inido ningCn otro constructor& Por tantoB si tenemos una clase en la @ue (ayamos de!inido
algCn constructor con par$metros pero ninguno sin par$metros no ser$ v$lido crear o"jetos de la misma
llamando al constructor sin par$metrosB pues el compilador no lo (a"r$ de!inido autom$ticamente& Por
ejemploB con la Cltima versin de la clase de ejemplo Persona es inv$lido (acerA
Persona p = new Persona(); // ERROR:
// El nico constructor de Persona
// toma 3 parmetros
+e"erencia al ob,eto actual con t)is
)entro del cdigo de cual@uier m,todo de un o"jeto siempre es posi"le (acer re!erencia al propio
o"jeto usando la pala"ra reservada this& %sto puede venir "ien a la (ora de escri"ir constructores de
o"jetos de"ido a @ue permite @ue los nom"res @ue demos a los par$metros del constructor puedan
coincidir nom"res de los campos del o"jeto sin @ue (aya ningCn pro"lema& Por ejemploB el constructor
de la clase Persona escrito anteriormente se puede rescri"ir as usando thisA
Persona (string Nombre, int Edad, string NIF)
{
this.Nombre = Nombre;
this.Edad = Edad;
this.NIF = NIF;
}
%s decirB dentro de un m,todo con par$metros cuyos nom"res coincidan con camposB se da
pre!erencia a los par$metros y para (acer re!erencia a los campos (ay @ue pre!ijarlos con el this tal y
como se muestra en el ejemplo&
%l ejemplo anterior puede @ue no resulte muy interesante de"ido a @ue para evitar tener @ue usar this
podra (a"erse escrito el constructor tal y como se mostr en la primera versin del mismoA dando
nom"res @ue empiecen en minCscula a los par$metros y nom"res @ue empiecen con mayCsculas a los
campos& )e (ec(oB ese es el convenio @ue Microso!t recomienda usar& Sin em"argoB como m$s
adelante se ver$ s @ue puede ser Ctil this cuando los campos a iniciali/ar a sean privadosB ya @ue el
convenio de escritura de identi!icadores para campos privados recomendado por Microso!t coincide
con el usado para dar identi!icadores a par$metros =o"viamente otra solucin sera dar cual@uier otro
nom"re a los par$metros del constructor o los campos a!ectadosB aun@ue as el cdigo perdera algo
legi"ilidad?
1n uso m$s !recuente de this en C# es el de permitir reali/ar llamadas a un m,todo de un o"jeto
desde cdigo u"icado en m,todos del mismo o"jeto& %s decirB en C# siempre es necesario @ue cuando
llamemos a algCn m,todo de un o"jeto precedamos al operador . de alguna e*presin @ue indi@ue cu$l
es el o"jeto a cuyo m,todo se desea llamarB y si ,ste m,todo pertenece al mismo o"jeto @ue (ace la
llamada la Cnica !orma de conseguir indicarlo en C# es usando this&
inalmenteB una tercera utilidad de this es permitir escri"ir m,todos @ue puedan devolver como
o"jeto el propio o"jeto so"re el @ue el m,todo es aplicado& Para ello "astara usar una instruccin
return thisT al indicar el o"jeto a devolver&
Herencia y mtodos virtuales
Concepto de )erencia
%l mecanismo de herencia es uno de los pilares !undamentales en los @ue se "asa la programacin
orientada a o"jetos& %s un mecanismo @ue permite de!inir nuevas clases a partir de otras ya de!inidas de
modo @ue si en la de!inicin de una clase indicamos @ue ,sta deriva de otraB entonces la primera 5a la
@ue se le suele llamar clase hija5 ser$ tratada por el compilador autom$ticamente como si su de!inicin
incluyese la de!inicin de la segunda Ha la @ue se le suele llamar clase "adre o clase base& #as clases
@ue derivan de otras se de!inen usando la siguiente sinta*isA
class <nombreHija>:<nombrePadre>
{
<miembrosHija>
}
- los miem"ros de!inidos en jmiem"rosHijas6 se le a7adir$n los @ue (u"i,semos de!inido en la
clase padre& Por ejemploB a partir de la clase Persona puede crearse una clase .ra"ajador asA

class Trabajador:Persona
{
public int Sueldo;
public Trabajador (string nombre, int edad, string nif, int sueldo)
:base(nombre, edad, nif)
{
Sueldo = sueldo;
}
}
#os o"jetos de esta clase .ra"ajador contar$n con los mismos miem"ros @ue los o"jetos Persona y
adem$s incorporar$n un nuevo campo llamado Sueldo @ue almacenar$ el dinero @ue cada tra"ajador
gane& 8tese adem$s @ue a la (ora de escri"ir el constructor de esta clase (a sido necesario escri"irlo
con una sinta*is especial consistente en preceder la llave de apertura del cuerpo del m,todo de una
estructura de la !ormaA
" base(<parametrosBase>)
- esta estructura se le llama inicializador base y se utili/a para indicar cmo deseamos iniciali/ar
los campos (eredados de la clase padre& 8o es m$s @ue una llamada al constructor de la misma con los
par$metros adecuadosB y si no se incluye el compilador considerara por de!ecto @ue vale :base;<B lo
@ue sera incorrecto en este ejemplo de"ido a @ue Persona carece de constructor sin par$metros&
1n ejemplo @ue pone de mani!iesto cmo !unciona la (erencia es el siguienteA
using System;

class Persona
{
// Campo de cada objeto Persona que almacena su nombre
public string Nombre;
// Campo de cada objeto Persona que almacena su edad
public int Edad;
// Campo de cada objeto Persona que almacena su NIF
public string NIF;

void Cumpleaos() // Incrementa en uno de edad del objeto Persona
{
Edad++;
}

// Constructor de Persona
public Persona (string nombre, int edad, string nif)
{
Nombre = nombre;
Edad = edad;
NIF = nif;
}
}

class Trabajador: Persona
{

// Campo de cada objeto Trabajador que almacena cunto gana
public int Sueldo;

Trabajador(string nombre, int edad, string nif, int sueldo)
: base(nombre, edad, nif)
{ // Inicializamos cada Trabajador en base al constructor de Persona
Sueldo = sueldo;
}

public static void Main()
{
Trabajador p = new Trabajador("Josan", 22, "77588260-Z", 100000);
Console.WriteLine ("Nombre="+p.Nombre);
Console.WriteLine ("Edad="+p.Edad);
Console.WriteLine ("NIF="+p.NIF);
Console.WriteLine ("Sueldo="+p.Sueldo);
}
}
8tese @ue (a sido necesario pre!ijar la de!inicin de los miem"ros de Persona del pala"ra reservada
"ublic& %sto se de"e a @ue por de!ecto los miem"ros de una tipo slo son accesi"les desde cdigo
incluido dentro de la de!inicin de dic(o tipoB e incluyendo "ublic conseguimos @ue sean accesi"les
desde cual@uier cdigoB como el m,todo Main=? de!inido en .ra"ajador& "ublic es lo @ue se denomina
un modificador de accesoB concepto @ue se tratar$ m$s adelante en este mismo tema "ajo el epgra!e
titulado Modi3i%adores de a%%eso&
%lamadas por de"ecto al constructor base
Si en la de!inicin del constructor de alguna clase @ue derive de otra no incluimos iniciali/ador "ase
el compilador considerar$ @ue ,ste es :base;< Por ello (ay @ue estar seguros de @ue si no se incluye
base en la de!inicin de algCn constructorB el tipo padre del tipo al @ue pertene/ca disponga de
constructor sin par$metros&
%s especialmente signi!icativo rese7ar el caso de @ue no demos la de!inicin de ningCn constructor
en la clase (ijaB ya @ue en estos casos la de!inicin del constructor @ue por de!ecto introducir$ el
compilador ser$ en realidad de la !ormaA
<nombreClase>(): base()
{}
%s decirB este constructor siempre llama al constructor sin par$metros del padre del tipo @ue estemos
de!iniendoB y si ,se no dispone de alguno se producir$ un error al compilar&
M&todos #irtuales
Wa (emos visto @ue es posi"le de!inir tipos cuyos m,todos se (ereden de de!iniciones de otros tipos&
#o @ue a(ora vamos a ver es @ue adem$s es posi"le cam"iar dic(ar de!inicin en la clase (ijaB para lo
@ue (a"ra @ue (a"er precedido con la pala"ra reservada virtual la de!inicin de dic(o m,todo en la
clase padre& - este tipo de m,todos se les llama mKtodos virtualesB y la sinta*is @ue se usa para
de!inirlos es la siguienteA
virtual <tipoDevuelto> <nombreMtodo>(<parmetros>)
{
<cdigo>
}
Si en alguna clase (ija @uisi,semos dar una nueva de!inicin del del m,todoB simplemente lo
volveramos a de!inir en la misma pero sustituyendo en su de!inicin la pala"ra reservada virtual por
override& %s decirB usaramos esta sinta*isA
override <tipoDevuelto> <nombreMtodo>(<parmetros>)
{
<nuevoCdigo>
}
8tese @ue esta posi"ilidad de cam"iar el cdigo de un m,todo en su clase (ija slo se da si en la
clase padre el m,todo !ue de!inido como virtual& %n caso contrarioB el compilador considerar$ un error
intentar rede!inirlo&
%l lenguaje C# impone la restriccin de @ue toda rede!inicin de m,todo @ue @ueramos reali/ar
incorpore la partcula override para !or/ar a @ue el programador est, seguro de @ue verdaderamente lo
@ue @uiere (acer es cam"iar el signi!icado de un m,todo (eredado& -s se evita @ue por accidente
de!ina un m,todo del @ue ya e*ista una de!inicin en una clase padre& -dem$sB C# no permite de!inir
un m,todo como override y virtual a la ve/B ya @ue ello tendra un signi!icado a"surdoA estaramos
dando una rede!inicin de un m,todo @ue vamos a de!inir&
Por otro ladoB cuando de!inamos un m,todo como override (a de cumplirse @ue en alguna clase
antecesora =su clase padreB su clase a"uelaB etc&? de la clase en la @ue se (a reali/ado la de!inicin del
mismo e*ista un m,todo virtual con el mismo nom"re @ue el rede!inido& Si noB el compilador in!ormar$
de error por intento de rede!inicin de m,todo no e*istente o no virtual& -s se evita @ue por accidente
un programador crea @ue est$ rede!iniendo un m,todo del @ue no e*ista de!inicin previa o @ue
rede!ina un m,todo @ue el creador de la clase "ase no desee @ue se pueda rede!inir&
Para aclarar mejor el concepto de m,todo virtualB vamos a mostrar un ejemplo en el @ue
cam"iaremos la de!inicin del m,todo Cumplea7os=? en los o"jetos Persona por una nueva versin en
la @ue se muestre un mensaje cada ve/ @ue se ejecuteB y rede!iniremos dic(a nueva versin para los
o"jetos .ra"ajador de modo @ue el mensaje mostrado sea otro& %l cdigo de este ejemplo es el @ue se
muestra a continuacinA

using System;
class Persona
{
// Campo de cada objeto Persona que almacena su nombre
public string Nombre;
// Campo de cada objeto Persona que almacena su edad
public int Edad;
// Campo de cada objeto Persona que almacena su NIF
public string NIF;
// Incrementa en uno de la edad del objeto Persona

public virtual void Cumpleaos()
{
Edad++;
Console.WriteLine("Incrementada edad de persona");
}

// Constructor de Persona
public Persona (string nombre, int edad, string nif)
{
Nombre = nombre;
Edad = edad;
NIF = nif;
}
}

class Trabajador: Persona
{
// Campo de cada objeto Trabajador que almacena cunto gana
public int Sueldo;

Trabajador(string nombre, int edad, string nif, int sueldo)
: base(nombre, edad, nif)
{ // Inicializamos cada Trabajador en base al constructor de Persona
Sueldo = sueldo;
}

public override void Cumpleaos()
{
Edad++;
Console.WriteLine("Incrementada edad de trabajador");
}

public static void Main()
{
Persona p = new Persona("Carlos", 22, "77588261-Z");
Trabajador t = new Trabajador("Josan", 22, "77588260-Z", 100000);
t.Cumpleaos();
p.Cumpleaos();
}
}
8tese cmo se (a a7adido el modi!icador virtual en la de!inicin de Cumplea7os=? en la clase
Persona para (a"ilitar la posi"ilidad de @ue dic(o m,todo puede ser rede!inido en clase (ijas de
Persona y cmo se (a a7ado override en la rede!inicin del mismo dentro de la clase .ra"ajador para
indicar @ue la nueva de!inicin del m,todo es una rede!inicin del (eredado de la clase& #a salida de
este programa con!irma @ue la implementacin de Cum"leaVos;< es distinta en cada claseB pues es de
la !ormaA
ncrementada edad de tra"ajador
ncrementada edad de persona
.am"i,n es importante se7alar @ue para @ue la rede!inicin sea v$lida (a sido necesario a7adir la
partcula "ublic a la de!inicin del m,todo originalB pues si no se incluyese se considerara @ue el
m,todo slo es accesi"le desde dentro de la clase donde se (a de!inidoB lo @ue no tiene sentido en
m,todos virtuales ya @ue entonces nunca podra ser rede!inido& )e (ec(oB si se e*cluyese el
modi!icador "ublic el compilador in!ormara de un error ante este a"surdo& -dem$sB este modi!icador
tam"i,n se (a mantenido en la rede!inicin de Cumplea7os=? por@ue toda rede!inicin de un m,todo
virtual (a de mantener los mismos modi!icadores de acceso @ue el m,todo original para ser v$lida&
Clases abstractas
1na clase abstracta es a@uella @ue !or/osamente se (a de derivar si se desea @ue se puedan crear
o"jetos de la misma o acceder a sus miem"ros est$ticos =esto Cltimo se ver$ m$s adelante en este
mismo tema? Para de!inir una clase a"stracta se antepone abstract a su de!inicinB como se muestra en
el siguiente ejemploA
public abstract class A
{
public abstract void F();
}
abstract public class B: A
{
public void G() {}
}
class C: B
{
public override void F(){}
}
#as clases - y 0 del ejemplo son a"stractasB y como puede verse es posi"le com"inar en cual@uier
orden el modi!icador abstract con modi!icadores de acceso&
#a utilidad de las clases a"stractas es @ue pueden contener m,todos para los @ue no se d,
directamente una implementacin sino @ue se deje en manos de sus clases (ijas darla& 8o es o"ligatorio
@ue las clases a"stractas contengan m,todos de este tipoB pero s lo es marcar como a"stracta a toda la
@ue tenga alguno& %stos m,todos se de!inen precediendo su de!inicin del modi!icador abstract y
sustituyendo su cdigo por un punto y coma =T?B como se muestra en el m,todo =? de la clase - del
ejemplo =ntese @ue 0 tam"i,n (a de de!inirse como a"stracta por@ue tampoco implementa el m,todo
=? @ue (ereda de -?
O"viamenteB como un m,todo a"stracto no tiene cdigo no es posi"le llamarlo& Hay @ue tener
especial cuidado con esto a la (ora de utili/ar this para llamar a otros m,todos de un mismo o"jetoB ya
@ue llamar a los a"stractos provoca un error al compilar&
V,ase @ue todo m,todo de!inido como a"stracto es implcitamente virtualB pues si no sera imposi"le
rede!inirlo para darle una implementacin en las clases (ijas de la clase a"stracta donde est, de!inido&
Por ello es necesario incluir el modi!icador override a la (ora de darle implementacin y es redundante
marcar un m,todo como abstract y virtual a la ve/ =de (ec(oB (acerlo provoca un error al compilar?
%s posi"le marcar un m,todo como abstract y override a la ve/B lo @ue convertira al m,todo en
a"stracto para sus clases (ijas y !or/ara a @ue ,stas lo tuviesen @ue reimplementar si no se @uisiese @ue
!uesen clases a"stractas&
La clase prime!enia" #ystem$Object
-(ora @ue sa"emos lo @ue es la (erencia es el momento apropiado para e*plicar @ue en &8%. todos
los tipos @ue se de!inan (eredan implcitamente de la clase S(stem.bject prede!inida en la 0C#B por
lo @ue dispondr$n de todos los miem"ros de ,sta& Por esta ra/n se dice @ue S(stem.bject es la ra/
de la jerar@ua de o"jetos de &8%.&
- continuacin vamos a e*plicar cu$les son estos m,todos comunes a todos los o"jetosA
"ublic virtual bool ESuals;object o<A Se usa para comparar el o"jeto so"re el @ue se aplica con
cual@uier otro @ue se le pase como par$metro& )evuelve true si am"os o"jetos son iguales y
false en caso contrario&
#a implementacin @ue por de!ecto se (a dado a este m,todo consiste en usar igualdad por re!erencia
para los tipos por re!erencia e igualdad por valor para los tipos por valor& %s decirB si los o"jetos a
comparar son de tipos por re!erencia slo se devuelve true si am"os o"jetos apuntan a la misma
re!erencia en memoria din$micaB y si los tipos a comparar son tipos por valor slo se devuelve true si
todos los "its de am"os o"jetos son igualesB aun@ue se almacenen en posiciones di!erentes de memoria&
Como se veB el m,todo (a sido de!inido como virtualB lo @ue permite @ue los programadores puedan
rede!inirlo para indicar cu$ndo (a de considerarse @ue son iguales dos o"jetos de tipos de!inidos por
ellos& )e (ec(oB muc(os de los tipos incluidos en la 0C# cuentan con rede!iniciones de este tipoB como
es el caso de stringB @uien aCn siendo un tipo por re!erenciaB sus o"jetos se consideran iguales si
apuntan a cadenas @ue sean iguales car$cter a car$cter =aun@ue re!erencien a distintas direcciones de
memoria din$mica?
%l siguiente ejemplo muestra cmo (acer una rede!inicin de ESuals;< de manera @ue aun@ue los
o"jetos Persona sean de tipos por re!erenciaB se considere @ue dos Personas son iguales si tienen el
mismo 8IA
public override bool Equals(object o)
{
if (o==null)
return this==null;
else
return (o is Persona) && (this.NIF == ((Persona) o).NIF);
}
Hay @ue tener en cuenta @ue es conveniente @ue toda rede!inicin del m,todo ESuals;< @ue (agamos
cumpla con una serie de propiedades @ue muc(os de los m,todos incluidos en las distintas
clases de la 0C# esperan @ue se cumplan& %stas propiedades sonA
Cefle)ividad: .odo o"jeto (a de ser igual a s mismo& %s decirB *&%@uals=*? siempre (a de
devolver true&
Simetr0a: Ha de dar igual el orden en @ue se (aga la comparacin& %s decirB *&%@uals=y? (a de
devolver lo mismo @ue y&%@uals=*? &
Transitividad: Si dos o"jetos son iguales y uno de ellos es igual a otroB entonces el primero
tam"i,n (a de ser igual a ese otro o"jeto& %s decirB si *&%@uals=y? e y&%@uals=/? entonces
*&%@uals=/? &
Consistencia: Siempre @ue el m,todo se apli@ue so"re los mismos o"jetos (a de devolver el
mismo resultado&
Tratamiento de objetos nulos: Si uno de los o"jetos comparados es nulo =null?B slo se (a de
devolver true si el otro tam"i,n lo es&
Hay @ue recalcar @ue el (ec(o de @ue rede!inir %@uals=? no implica @ue el operador de igualdad =&&?
@uede tam"i,n rede!inido& %llo (a"ra @ue (acerlo de independientemente como se indica en el Tema
&&: 4ede3i#i%i'# de o!eradores&
"ublic virtual int #et?ashCode;<A )evuelve un cdigo de dispersin =(as(? @ue representa de
!orma num,rica al o"jeto so"re el @ue el m,todo es aplicado& #et?ashCode;< suele usarse para
tra"ajar con ta"las de dispersinB y se cumple @ue si dos o"jetos son iguales sus cdigos de
dispersin ser$n igualesB mientras @ue si son distintos la pro"a"ilidad de @ue sean iguales es
n!ima&
%n tanto @ue la "Cs@ueda de o"jetos en ta"las de dispersin no se reali/a Cnicamente usando la
igualdad de o"jetos =m,todo %@uals=?? sino usando tam"i,n la igualdad de cdigos de dispersinB suele
ser conveniente rede!inir ;etHas(Code=? siempre @ue se rede!ina %@uals=? )e (ec(oB si no se (ace el
compilador in!orma de la situacin con un mensaje de aviso&
"ublic virtual string ToString;<A )evuelve una representacin en !orma de cadena del o"jeto
so"re el @ue se el m,todo es aplicadoB lo @ue es muy Ctil para depurar aplicaciones ya @ue
permite mostrar con !acilidad el estado de los o"jetos&
#a implementacin por de!ecto de este m,todo simplemente devuelve una cadena de te*to con el
nom"re de la clase a la @ue pertenece el o"jeto so"re el @ue es aplicado& Sin em"argoB como lo
(a"itual suele ser implementar .oString=? en cada nueva clase @ue es de!inaB a continuacin
mostraremos un ejemplo de cmo rede!inirlo en la clase Persona para @ue muestre los valores de todos
los campos de los o"jetos PersonaA
public override string ToString()
{
string cadena = "";
cadena += "DNI = " + this.DNI + "\n";
cadena += "Nombre = " + this.Nombre + "\n";
cadena += "Edad = " + this.Edad + "\n";
return cadena;
}
%s de rese7ar el (ec(o de @ue en realidad los @ue (ace el operador de concatenacin de cadenas =*?
para concatenar una cadena con un o"jeto cual@uiera es convertirlo primero en cadena llamando a su
m,todo ToString;< y luego reali/ar la concatenacin de am"as cadenas&
)el mismo modoB cuando a Console.9rite:ine;< y Console.9rite;< se les pasa como par$metro un
o"jeto lo @ue (acen es mostrar por la salida est$ndar el resultado de convertirlo en cadena llamando a
su m,todo ToString;<J y si se les pasa como par$metros una cadena seguida de varios o"jetos lo
muestran por la salida est$ndar esa cadena pero sustituyendo en ella toda su"cadena de la !orma
TjnCmero6U por el resultado de convertir en cadena el par$metro @ue ocupe la posicin jnCmero6D9
en la lista de valores de llamada al m,todo&
"rotected object Member9iseClone;<: )evuelve una copia shallo% co"( del o"jeto so"re el
@ue se aplica& %sta copia es una copia "it a "it del mismoB por lo @ue el o"jeto resultante de la
copia mantendr$ las mismas re!erencias a otros @ue tuviese el o"jeto copiado y toda
modi!icacin @ue se (aga a estos o"jetos a trav,s de la copia a!ectar$ al o"jeto copiado y
viceversa&
Si lo @ue interesa es disponer de una copia m$s normalB en la @ue por cada o"jeto re!erenciado se crease
una copia del mismo a la @ue re!erenciase el o"jeto clonadoB entonces el programador (a de escri"ir su
propio m,todo clonador pero puede servirse de Mem"er'iseClone=? como "ase con la @ue copiar los
campos @ue no sean de tipos re!erencia&
"ublic S(stem.T("e #etT("e;<A )evuelve un o"jeto de clase S(stem.T("e @ue representa al
tipo de dato del o"jeto so"re el @ue el m,todo es aplicado& - trav,s de los m,todos o!recidos
por este o"jeto se puede acceder a metadatos so"re el mismo como su nom"reB su clase padreB
sus miem"rosB etc& #a e*plicacin de cmo usar los miem"ros de este o"jeto para o"tener dic(a
in!ormacin @ueda !uera del alcance de este documento ya @ue es muy larga y puede ser
!$cilmente consultada en la documentacin @ue acompa7a al &8%. S)]&
"rotected virtual void Dinalize;<A Contiene el cdigo @ue se ejecutar$ siempre @ue vaya (a ser
destruido algCn o"jeto del tipo del @ue sea miem"ro& #a implementacin dada por de!ecto a
Dinalize;< consiste en no (acer nada&
-un@ue es un m,todo virtualB en C# no se permite @ue el programador lo rede!ina e*plcitamente dado
@ue (acerlo es peligroso por ra/ones @ue se e*plicar$n en el Tema 8: Mtodos =otros lenguajes de &8%.
podran permitirlo?
-parte de los m,todos ya comentados @ue todos los o"jetos (eredanB la clase S(stem.bject tam"i,n
incluye en su de!inicin los siguientes m,todos de tipoA
"ublic static bool ESuals;object objeto2U object objeto3< l Versin est$tica del m,todo
ESuals;< ya visto& Indica si los o"jetos @ue se le pasan como par$metros son igualesB y para
compararlos lo @ue (ace es devolver el resultado de calcular objeto2.ESuals;objeto3<
compro"ando antes si alguno de los o"jetos vale null =slo se devolvera true slo si el otro
tam"i,n lo es?
O"viamente si se da una rede!inicin al ESuals;< no est$ticoB sus e!ectos tam"i,n se ver$n cuando se
llame al est$tico&
"ublic static bool CeferenceESuals;object objeto2U object objeto3< l Indica si los dos o"jetos
@ue se le pasan como par$metro se almacenan en la misma posicin de memoria din$mica& -
trav,s de este m,todoB aun@ue se (ayan rede!inido %@uals=? y el operador de igualdad =&&? para
un cierto tipo por re!erenciaB se podr$n seguir reali/ando comparaciones por re!erencia entre
o"jetos de ese tipo en tanto @ue rede!inir de %@uals=? no a!ecta a este m,todo& Por ejemploB
dada la anterior rede!inicin de %@uals=? para o"jetos PersonaA
Persona p = new Persona("Jos", 22, "83721654-W");
Persona q = new Persona("Antonio", 23, "83721654-W");
Console.WriteLine(p.Equals(q));
Console.WriteLine(Object.Equals(p, q));
Console.WriteLine(Object.ReferenceEquals(p, q));
Console.WriteLine(p == q);
#a salida @ue por pantalla mostrar$ el cdigo anterior esA
.rue
.rue
alse
alse
%n los primeros casos se devuelve true por@ue segCn la rede!inicin de %@uals=? dos personas son
iguales si tienen el mismo )8IB como pasa con los o"jetos p y @& Sin em"argoB en los Cltimos casos se
devuelve false por@ue aun@ue am"os o"jetos tienen el mismo )8I cada uno se almacena en la memoria
din$mica en una posicin distintaB @ue es lo @ue comparan +e!erence%@uals=? y el operador && =,ste
Cltimo slo por de!ecto?
Polimorfismo
Concepto de polimor"ismo
%l "olimorfismo es otro de los pilares !undamentales de la programacin orientada a o"jetos& %s la
capacidad de almacenar o"jetos de un determinado tipo en varia"les de tipos antecesores del primero a
costaB claro est$B de slo poderse acceder a trav,s de dic(a varia"le a los miem"ros comunes a am"os
tipos& Sin em"argoB las versiones de los m,todos virtuales a las @ue se llamara a trav,s de esas
varia"les no seran las de!inidas como miem"ros del tipo de dic(as varia"lesB sino las de!inidas en el
verdadero tipo de los o"jetos @ue almacenan&
- continuacin se muestra un ejemplo de cmo una varia"le de tipo Persona puede usarse para
almacenar o"jetos de tipo .ra"ajador& %n esos casos el campo Sueldo del o"jeto re!erenciado por la
varia"le no ser$ accesi"leB y la versin del m,todo Cumplea7os=? a la @ue se podra llamar a trav,s de
la varia"le de tipo Persona sera la de!inida en la clase .ra"ajadorB y no la de!inida en PersonaA
using System;
class Persona
{
// Campo de cada objeto Persona que almacena su nombre
public string Nombre;
// Campo de cada objeto Persona que almacena su edad
public int Edad;
// Campo de cada objeto Persona que almacena su NIF
public string NIF;

// Incrementa en uno la edad del objeto Persona
public virtual void Cumpleaos()
{
Console.WriteLine("Incrementada edad de persona");
}

// Constructor de Persona
public Persona (string nombre, int edad, string nif)
{
Nombre = nombre;
Edad = edad;
NIF = nif;
}
}
class Trabajador: Persona
{
// Campo de cada objeto Trabajador que almacena cunto gana
int Sueldo;

Trabajador(string nombre, int edad, string nif, int sueldo)
: base(nombre, edad, nif)
{// Inicializamos cada Trabajador en base al constructor de Persona
Sueldo = sueldo;
}

public override Cumpleaos()
{
Edad++;
Console.WriteLine("Incrementada edad de trabajador");
}

public static void Main()
{
Persona p = new Trabajador("Josan", 22, "77588260-Z", 100000);
p.Cumpleaos();
// p.Sueldo++; //ERROR: Sueldo no es miembro de Persona
}
}
%l mensaje mostrado por pantalla al ejecutar este m,todo con!irma lo antes dic(o respecto a @ue la
versin de Cumplea7os=? a la @ue se llamaB ya @ue esA

Incrementada edad de tra"ajador
M,todos gen,ricos
%l polimor!ismo es muy Ctil ya @ue permite escri"ir m,todos gen,ricos @ue puedan reci"ir par$metros
@ue sean de un determinado tipo o de cual@uiera de sus tipos (ijos& %s m$sB en tanto @ue cmo se ver$
en el epgra!e siguienteB en C# todos los tipos derivan implcitamente del tipo S(stem.bjectB podemos
escri"ir m,todos @ue admitan par$metros de cual@uier tipo sin m$s @ue de!inirlos como m,todos @ue
tomen par$metros de tipo S(stem.bject& Por ejemploA
public void MtodoGenrico(object o)
{
// Cdigo del mtodo
}
8tese @ue en ve/ de S(stem.bject se (a escrito objectB @ue es el nom"re a"reviado incluido en
C# para (acer re!erencia de manera compacta a un tipo tan !recuentemente usado como
S(stem.bject&
!eterminacin de tipo. -perador is
)entro de una rutina polimri!ica @ueB como la del ejemplo anteriorB admita par$metros @ue puedan ser
de cual@uier tipoB muc(as veces es conveniente poder consultar en el cdigo de la misma cu$l es el tipo
en concreto del par$metro @ue se (aya pasado al m,todo en cada llamada al mismo& Para ello C# o!rece
el operador isB cuya !orma sinta*is de uso esA
<expresin> is <nombreTipo>
%ste operador devuelve true en caso de @ue el resultado de evaluar je*presin6 sea del tipo cuyo
nom"re es jnom"re.ipo6 y false en caso contrarioRGS& ;racias a ellas podemos escri"ir m,todos
gen,ricos @ue puedan determinar cu$l es el tipo @ue tienen los par$metros @ue en cada llamada en
concreto se les pasen& O seaB m,todos comoA
public void MtodoGenrico(object o)
{
if (o is int)// Si o es de tipo int (entero)...
//...Cdigo a ejecutar si el objeto o es de tipo int
else if (o is string) // Si no, si o es de tipo string (cadena)...
//...Cdigo a ejecutar si o es de tipo string
//... Idem para otros tipos
}
%l "lo@ue if&&&else es una instruccin condicional @ue permite ejecutar un cdigo u otro en !uncin de
si la condicin indicada entre par,ntesis tras el if es cierta =true? o no =false? %sta instruccin se
e*plicar$ m$s detalladamente en el Tema &5: "#str$%%io#es
Acceso a la clase base
Hay determinadas circunstancias en las @ue cuando rede!inamos un determinado m,todo nos interese
poder acceder al cdigo de la versin original& Por ejemploB por@ue el cdigo rede!inido @ue vayamos a
escri"ir (aga lo mismo @ue el original y adem$s algunas cosas e*tras& %n estos casos se podra pensar
@ue una !orma de conseguir esto sera convirtiendo el o"jeto actual al tipo del m,todo a rede!inir y
entonces llamar as a ese m,todoB como por ejemplo en el siguiente cdigoA
using System;
class A
{
public virtual void F()
{
Console.WriteLine("A");
}
}
class B:A
{
public override void F()
{
Console.WriteLine("Antes");
((A) this).F(); // (2)
Console.WriteLine("Despus");
}
public static void Main()
{
B b = new B();
b.F();
}
}
Pues "ienB si ejecutamos el cdigo anterior veremos @ue la aplicacin nunca termina de ejecutarse y
est$ constantemente mostrando el mensaje -ntes por pantalla& %sto se de"e a @ue de"ido al
polimor!ismo se (a entrado en un "ucle in!initoA aun@ue usemos el operador de conversin para tratar
el o"jeto como si !uese de tipo -B su verdadero tipo sigue siendo 0B por lo @ue la versin de =? a la @ue
se llamar$ en =9? es a la de 0 de nuevoB @ue volver$ a llamarse as misma una y otra ve/ de manera
inde!inida&
Para solucionar estoB los dise7adores de C# (an incluido una pala"ra reservada llamada base @ue
devuelve una re!erencia al o"jeto actual semejante a this pero con la peculiaridad de @ue los accesos a
ella son tratados como si el verdadero tipo !uese el de su clase "ase& 1sando baseB podramos
reempla/ar el cdigo de la rede!inicin de =? de ejemplo anterior porA
public override void F()
{
Console.WriteLine("Antes");
base.F();
Console.WriteLine("Despus");
}
Si a(ora ejecutamos el programa veremos @ue a(ora s @ue la versin de =? en 0 llama a la versin de
=? en -B resultando la siguiente salida por pantallaA
-ntes
-
)espu,s

- la (ora de rede!inir m,todos a"stractos (ay @ue tener cuidado con una cosaA desde el m,todo
rede!inidor no es posi"le usar base para (acer re!erencia a m,todos a"stractos de la clase padreB aun@ue
s para (acer re!erencia a los no a"stractos& Por ejemploA
abstract class A
{
public abstract void F();
public void G(){}
}
class B: A
{
public override void F()
{
base.G();// Correcto
base.F();// Error, base.F() es abstracto
}
}
)o'ncasting
)ado @ue una varia"le de un determinado tipo puede estar en realidad almacenando un o"jeto @ue sea
de algCn tipo (ijo del tipo de la varia"le y en ese caso a trav,s de la varia"le slo puede accederse a
a@uellos miem"ros del verdadero tipo del o"jeto @ue sean comunes con miem"ros del tipo de la
varia"le @ue re!erencia al o"jetoB muc(as veces nos va a interesar @ue una ve/ @ue dentro de un m,todo
gen,rico (ayamos determinado cu$l es el verdadero tipo de un o"jeto =por ejemploB con el operador is?
podamos tratarlo como tal& %n estos casos lo @ue (ay es @ue (acer una conversin del tipo padre al
verdadero tipo del o"jetoB y a esto se le llama do%ncasting
Para reali/ar un do'ncasting una primera posi"ilidad es indicar preceder la e*presin a convertir del
tipo en el @ue se la desea convertir indicado entre par,ntesis& %s decirB siguiendo la siguiente sinta*isA
(<tipoDestino>) <expresinAConvertir>
%l resultado de este tipo de e*presin es el o"jeto resultante de convertir el resultado de
je*presin-Convertir6 a jtipo)estino6& %n caso de @ue la conversin no se pudiese reali/ar se
lan/ara una e*cepcin del tipo prede!inido S(stem.InvalidCastE)ce"tion
Otra !orma de reali/ar el do'ncasting es usando el operador asB @ue se usa asA
<expresinAConvertir> as <tipoDestino>
#a principal di!erencia de este operador con el anterior es @ue si a(ora la conversin no se pudiese
reali/ar se devolvera null en lugar de lan/arse una e*cepcin& #a otra di!erencia es @ue as slo es
aplica"le a tipos re!erencia y slo a conversiones entre tipos de una misma jerar@ua =de padres a (ijos
o viceversa?
#os errores al reali/ar conversiones de este tipo en m,todos gen,ricos se producen cuando el valor
pasado a la varia"le gen,rica no es ni del tipo indicado en jtipo)estino6 ni e*iste ninguna de!inicin
de cmo reali/ar la conversin a ese tipo =cmo de!inirla se ver$ en el Tema &&: 4ede3i#i%i'# de
o!eradores?
Clases . m&todos sellados
1na clase sellada es una clase @ue no puede tener clases (ijasB y para de!inirla "asta anteponer el
modi!icador sealed a la de!inicin de una clase normal& Por ejemploA
sealed class ClaseSellada
{}
1na utilidad de de!inir una clase como sellada es @ue permite @ue las llamadas a sus m,todos
virtuales (eredados se realicen tan e!icientemente como si !uesen no virtualesB pues al no poder e*istir
clases (ijas @ue los rede!inan no puede (a"er polimor!ismo y no (ay @ue determinar cu$l es la versin
correcta del m,todo a la @ue se (a de llamar& 8tese @ue se (a dic(o m,todos virtuales (eredadosB pues
lo @ue no se permite es de!inir miem"ros virtuales dentro de este tipo de clasesB ya @ue al no poderse
(eredarse de ellas es algo sin sentido en tanto @ue nunca podran rede!inirse&
-(ora "ienB (ay @ue tener en cuenta @ue sellar reduce enormemente su capacidad de reutili/acinB y
eso es algo @ue el aumento de e!iciencia o"tenido en las llamadas a sus m,todos virtuales no suele
compensar& %n realidad la principal causa de la inclusin de estas clases en C# es @ue permiten
asegurar @ue ciertas clases crticas nunca podr$n tener clases (ijas y sus varia"les siempre almacenar$n
o"jetos del mismo tipo& Por ejemploB para simpli!icar el !uncionamiento del C#+ y los compiladores se
(a optado por (acer @ue todos los tipos de datos "$sicos e*cepto S(stem.bject est,n sellados&
.,ngase en cuenta @ue es a"surdo de!inir simult$neamente una clase como abstract y sealedB pues
nunca podra accederse a la misma al no poderse crear clases (ijas suyas @ue de!inan sus m,todos
a"stractos& Por esta ra/nB el compilador considera errneo de!inir una clase con am"os modi!icadores
a la ve/&
-parte de para sellar clasesB tam"i,n se puede usar sealed como modi!icador en la rede!inicin de
un m,todo para conseguir @ue la nueva versin del mismo @ue se de!ina deje de ser virtual y se le
puedan aplicar las optimi/aciones arri"a comentadas& 1n ejemplo de esto es el siguienteA
class A
{
public abstract F();
}
class B:A
{
public sealed override F() // F() deja de ser redefinible
{}
}
Ocultaci%n de miembros
Hay ocasiones en las @ue puede resultar interesante usar la (erencia Cnicamente como mecanismo
de reutili/acin de cdigo pero no necesariamente para reutili/ar miem"ros& %s decirB puede @ue
interese (eredar de una clase sin @ue ello impli@ue @ue su clase (ija (erede sus miem"ros tal cuales
sino con ligeras modi!icaciones&
%sto puede muy Ctil al usar la (erencia para de!inir versiones especiali/adas de clases de uso
gen,rico& Por ejemploB los o"jetos de la clase S(stem.Collections.Frra(:ist incluida en la 0C#
pueden almacenar cual@uier nCmero de o"jetos S(stem.bjectB @ue al ser la clase primigenia ello
signi!ica @ue pueden almacenar o"jetos de cual@uier tipo& Sin em"argoB al recuperarlos de este almac,n
gen,rico se tiene el pro"lema de @ue los m,todos @ue para ello se o!recen devuelven o"jetos
S(stem.bjectB lo @ue implicar$ @ue muc(as veces (aya luego @ue reconvertirlos a su tipo original
mediante do'ncasting para poder as usar sus m,todos espec!icos& %n su lugarB si slo se va a usar un
Frra(:ist para almacenar o"jetos de un cierto tipo puede resultar m$s cmodo usar un o"jeto de
alguna clase derivada de Frra(:ist cuyo m,todo e*tractor de o"jetos oculte al (eredado de Frra(:ist
y devuelva directamente o"jetos de ese tipo&
Para ver m$s claramente cmo (acer la ocultacinB vamos a tomar el siguiente ejemplo donde se
deriva de una clase con un m,todo void =? pero se desea @ue en la clase (ija el m,todo @ue se tenga
sea de la !orma int =?A
class Padre
{
public void F()
{}
}
class Hija:Padre
{
public int F()
{return 1;}
}
Como en C# no se admite @ue en una misma clase (ayan dos m,todos @ue slo se di!erencien en sus
valores de retornoB puede pensarse @ue el cdigo anterior producir$ un error de compilacin& Sin
em"argoB esto no es as sino @ue el compilador lo @ue (ar$ ser$ @uedarse Cnicamente con la versin
de!inida en la clase (ija y desec(ar la (eredada de la clase padre& - esto se le conoce como ocultaci!n
de miembro ya @ue (ace desparacer en la clase (ija el miem"ro (eredadoB y cuando al compilar se
detecte se generar$ el siguiente de aviso =se supone @ue clases&cs almacena el cdigo anterior?A
clases&cs=dBFV?A 'arning CS:F:GA .(e 2ey'ord ne' is re@uired on fHija&=?f "ecause it (ides
in(erited mem"er fPadre&=?f
Como generalmente cuando se (ereda interesa @ue la clase (ija comparta los mismos miem"ros @ue
la clase padre =y si acaso @ue a7ada miem"ros e*tra?B el compilador emite el aviso anterior para indicar
@ue no se est$ (aciendo lo (a"itual& Si @ueremos evitarlo (emos de preceder la de!inicin del m,todo
ocultador de la pala"ra reservada ne% para as indicar e*plcitamente @ue @ueremos ocultar el =?
(eredadoA
class Padre
{
public void F()
{}
}
class Hija:Padre
{
new public int F()
{return 1;}
}
%n realidad la ocultacin de miem"ros no implica los miem"ros ocultados tengan @ue ser m,todosB
sino @ue tam"i,n pueden ser campos o cual@uiera de los dem$s tipos de miem"ro @ue en temas
posteriores se ver$n& Por ejemploB puede @ue se desee @ue un campo P de tipo int est, disponi"le en la
clase (ija como si !uese de tipo string&
.ampoco implica @ue los miem"ros m,todos ocultados tengan @ue di!erenciarse de los m,todos
ocultadores en su tipo de retornoB sino @ue pueden tener e*actamente su mismo tipo de retornoB
par$metros y nom"re& Hacer esto puede dar lugar a errores muy sutiles como el incluido en la siguiente
variante de la clase .ra"ajador donde en ve/ de rede!inirse Cumplea7os=? lo @ue se (ace es ocultarlo al
olvidar incluir el overrideA
using System;
class )ersona
{
// Campo de cada objeto Persona que almacena su nombre
public string Nombre;
// Campo de cada objeto Persona que almacena su edad
public int Edad;
// Campo de cada objeto Persona que almacena su NIF
public string NIF;

// Incrementa en uno la edad del objeto Persona
public virtual void Cumpleaos()
{
Console.WriteLine("Incrementada edad de persona");
}

// Constructor de Persona
public )ersona (string nombre, int edad, string nif)
{
Nombre = nombre;
Edad = edad;
NIF = nif;
}
}

class Trabajador: Persona

{ // Campo de cada objeto Trabajador que almacena cunto gana
int Sueldo;

Trabajador(string nombre, int edad, string nif, int sueldo)
: base(nombre, edad, nif)
{ // Inicializamos cada Trabajador en base al constructor de Persona
Sueldo = sueldo;
}

public Cumpleaos()
{
Edad++;
Console.WriteLine("Incrementada edad de trabajador");
}

public static void Main()
{
Persona p = new Trabajador("Josan", 22, "77588260-Z", 100000);
p.Cumpleaos();
// p.Sueldo++; //ERROR: Sueldo no es miembro de Persona
}
}
-l no incluirse override se (a perdido la capacidad de polimor!ismoB y ello puede verse en @ue la
salida @ue a(ora mostrara por pantalla el cdigoA
Incrementada edad de persona
%rrores de este tipo son muy sutiles y podran ser di!ciles de detectar& Sin em"argoB en C# es !$cil
(acerlo gracias a @ue el compilador emitir$ el mensaje de aviso ya visto por (a"er (ec(o la ocultacin
sin ne%& Cuando el programador lo vea podr$ a7adir ne% para suprimirlo si realmente lo @ue @uera
(acer era ocultarB pero si esa no era su intencin as sa"r$ @ue tiene @ue corregir el cdigo =por ejemploB
a7adiendo el override olvidado?
Como su propio nom"re indicaB cuando se rede!ine un m,todo se cam"ia su de!inicin original y por
ello las llamadas al mismo ejecutaran dic(a versin aun@ue se (agan a trav,s de varia"les de la clase
padre @ue almacenen o"jetos de la clase (ija donde se rede!ini& Sin em"argoB cuando se oculta un
m,todo no se cam"ia su de!inicin en la clase padre sino slo en la clase (ijaB por lo @ue las llamadas
al mismo reali/adas a trav,s de varia"les de la clase padre ejecutar$n la versin de dic(a clase padre y
las reali/adas mediante varia"les de la clase (ija ejecutar$n la versin de la clase (ija&
%n realidad el polimor!ismo y la ocultacin no son conceptos totalmente antagnicosB y aun@ue no
es v$lido de!inir m,todos @ue simult$neamente tengan los modi!icadores override y ne% ya @ue un
m,todo ocultador es como si !uese la primera versin @ue se (ace del mismo =luego no puede
rede!inirse algo no de!inido?B s @ue es posi"le com"inar ne% y virtual para de!inir m,todos
ocultadores rede!ini"les& Por ejemploA
using System;
class A
{
public virtual void F() { Console.WriteLine("A.F"); }
}
class B: A
{
public override void F() { Console.WriteLine("B.F"); }
}
class C: B
{
new public virtual void F() { Console.WriteLine("C.F"); }
}
class D: C
{
public override void F() { Console.WriteLine("D.F"); }
}
class Ocultacin
{
public static void Main()
{
A a = new D();
B b = new D();
C c = new D();
D d = new D();
a.F();
b.F();
c.F();
d.F();
}
}
#a salida por pantalla de este programa esA
0&
0&
)&
)&
-un@ue el verdadero tipo de los o"jetos a cuyo m,todo se llama en Main=? es )B en las dos primeras
llamadas se llama al =? de 0& %sto se de"e a @ue la rede!inicin dada en 0 cam"ia la versin de =? en
- por la suya propiaB pero la ocultacin dada en C (ace @ue para la rede!inicin @ue posteriormente se
da en ) se considere @ue la versin original de =? es la dada en C y ello provoca @ue no modi!i@ue la
versiones de dic(o m,todo dadas en - y 0 =@ueB por la rede!inicin dada en 0B en am"os casos son la
versin de 0?
1n truco mnemot,cnico @ue puede ser Ctil para determinar a @u, versin del m,todo se llamar$ en
casos complejos como el anterior consiste en considerar @ue el mecanismo de polimor!ismo !unciona
como si "uscase el verdadero tipo del o"jeto a cuyo m,todo se llama descendiendo en la jerar@ua de
tipos desde el tipo de la varia"le so"re la @ue se aplica el m,todo y de manera @ue si durante dic(o
recorrido se llega a alguna versin del m,todo con ne% se para la "Cs@ueda y se @ueda con la versin
del mismo incluida en el tipo recorrido justo antes del @ue tena el m,todo ocultador&
Hay @ue tener en cuenta @ue el grado de ocultacin @ue proporcione ne% depende del nivel de
accesi"ilidad del m,todo ocultadorB de modo @ue si es privado slo ocultar$ dentro de la clase donde
est, de!inido& Por ejemploB dadoA
using System;
class A
{
// F() es un mtodo redefinible
public virtual void F()
{
Console.WriteLine("F() de A");
}
}
class B: A
{
// Oculta la versin de F() de A slo dentro de B
new private void F() {}
}

class C: B
{
// Vlido, pues aqu slo se ve el F() de A
public override void F()
{
base.F();
Console.WriteLine("F() de B");
}
public static void Main()
{
C obj = new C();
obj.F();
}
}
#a salida de este programa por pantalla ser$A
=? de -
=? de 0
Pese a todo lo comentadoB (ay @ue resaltar @ue la principal utilidad de poder indicar e*plcitamente
si se desea rede!inir u ocultar cada miem"ro es @ue !acilita enormemente la resolucin de pro"lemas de
versionado de ti"os @ue puedan surgir si al derivar una nueva clase de otra y a7adirle miem"ros
adicionalesB posteriormente se la desea actuali/ar con una nueva versin de su clase padre pero ,sta
contiene miem"ros @ue entran en con!lictos con los a7adidos previamente a la clase (ija cuando aCn no
e*istan en la clase padre& %n lenguajes donde implcitamente todos los miem"ros son virtualesB como
EavaB esto da lugar a pro"lemas muy graves de"idos so"re todo aA
mue por sus nom"res los nuevos miem"ros de la clase padre entre en con!lictos con los
a7adidos a la clase (ija cuando no e*istan& Por ejemploB si la versin inicial de de la clase
padre no contiene ningCn m,todo de nom"re =?B a la clase (ija se le a7ade void =? y luego en
la nueva versin de la clase padre se incorporado int =?B se producir$ un error por tenerse en la
clase (ija dos m,todos =?
%n Eava para resolver este pro"lema una posi"ilidad sera pedir al creador de la clase padre @ue
cam"iase el nom"re o par$metros de su m,todoB lo cual no es siempre posi"le ni conveniente en tanto
@ue ello podra trasladar el pro"lema a @ue (u"iesen derivado de dic(a clase antes de volverla a
modi!icar& Otra posi"ilidad sera modi!icar el nom"re o par$metros del m,todo en la clase (ijaB lo @ue
nuevamente puede llevar a incompati"ilidades si tam"i,n se (u"iese derivado de dic(a clase (ija&
mue los nuevos miem"ros tengan los mismos nom"res y tipos de par$metros @ue los incluidos
en las clases (ijas y sea o"ligatorio @ue toda rede!inicin @ue se (aga de ellos siga un cierto
es@uema&
%sto es muy pro"lem$tico en lenguajes como Eava donde toda de!inicin de m,todo con igual nom"re y
par$metros @ue alguno de su clase padre es considerado implcitamente rede!inicin de ,steB ya @ue
di!cilmente en una clase (ija escrita con anterioridad a la nueva versin de la clase padre se (a"r$
seguido el es@uema necesario& Por elloB para resolverlo (a"r$ @ue actuali/ar la clase (ija para @ue lo
siga y de tal manera @ue los cam"ios @ue se le (agan no a!ecten a sus su"clasesB lo @ue ello puede ser
m$s o menos di!cil segCn las caractersticas del es@uema a seguir&
Otra posi"ilidad sera sellar el m,todo en la clase (ijaB pero ello recorta la capacidad de reutili/acin de
dic(a clase y slo tiene sentido si no !ue rede!inido en ninguna su"clase suya&
%n C# todos estos pro"lemas son de !$cil solucin ya @ue pueden resolverse con slo ocultar los
nuevos miem"ros en la clase (ija y seguir tra"ajando como si no e*istiesen&
&iembros de tipo
%n realidadB dentro la de!inicin de un tipo de dato no tienen por@u, incluirse slo de!iniciones de
miem"ros comunes a todos sus o"jetosB sino tam"i,n pueden de!inirse miem"ros ligados al tipo como
tal y no a los o"jetos del mismo& Para ello "asta preceder la de!inicin de ese miem"ro de la pala"ra
reservada staticB como muestra este ejemploA

class A
{
int x;
static int y;
}
#os o"jetos de clase - slo van a disponer del campo *B mientras @ue el campo y va a pertenecer a la
clase -& Por esta ra/n se dice @ue los miem"ros con modi!icador static son miembros de ti"o y @ue
los no lo tienen son miembros de objeto&
Para acceder a un miem"ro de clase ya no es v$lida la sinta*is (asta a(ora vista de
jo"jeto6.jmiem"ro6B pues al no estar estos miem"ros ligados a ningCn o"jeto no podra ponerse nada
en el campo jo"jeto6& #a sinta*is a usar para acceder a estos miem"ros ser$
jnom"reClase6.jmiem"ro6B como muestra ejemplo donde se asigna el valor 9 al miem"ro y de la
clase - de!inida m$s arri"aA
A.y = 2;
8tese @ue la inclusin de miem"ros de clase rompe con la a!irmacin indicada al principio del tema
en la @ue se deca @ue C# es un lenguaje orientado a o"jetos puro en el @ue todo con lo @ue se tra"aja
son o"jetosB ya @ue a los miem"ros de tipo no se les accede a trav,s de o"jetos sino nom"res de tipos&
%s importante mati/ar @ue si de!inimos una !uncin como staticB entonces el cdigo de la misma
slo podr$ acceder implcitamente =sin sinta*is jo"jeto6&jmiem"ro6? a otros miem"ros static del tipo
de dato al @ue pertene/ca& O seaB no se podr$ acceder a ni a los miem"ros de o"jeto del tipo en @ue est,
de!inido ni se podr$ usar this ya @ue el m,todo no est$ asociado a ningCn o"jeto& O seaB este cdigo
sera inv$lidoA
int x;
static void Incrementa()
{
x++; //ERROR: x es miembro de objeto e Incrementa() lo es de clase.
}
.am"i,n (ay @ue se7alar @ue los m,todos est$ticos no entran dentro del mecanismo de
rede!iniciones descrito en este mismo tema& )ic(o mecanismo slo es aplica"le a m,todos de o"jetosB
@ue son de @uienes puede declararse varia"les y por tanto puede actuar el polimor!ismo& Por elloB
incluir los modi!icadores virtualB override o abstract al de!inir un m,todo static es considerado
errneo por el compilador& %so no signi!ica @ue los miem"ros static no se (eredenB sino tan slo @ue no
tiene sentido rede!inirlos&
Encapsulaci%n
Wa (emos visto @ue la (erencia y el polimor!ismo eran dos de los pilares !undamentales en los @ue es
apoya la programacin orientada a o"jetos& Pues "ienB el tercero y Cltimo es la enca"sulaci!nB @ue es
un mecanismo @ue permite a los dise7adores de tipos de datos determinar @u, miem"ros de los tipos
creen pueden ser utili/ados por otros programadores y cu$les no& #as principales ventajas @ue ello
aporta sonA
Se !acilita a los programadores @ue vaya a usar el tipo de dato =programadores clientes? el
aprendi/aje de cmo tra"ajar con ,lB pues se le pueden ocultar todos los detalles relativos a su
implementacin interna y slo dejarle visi"les a@uellos @ue puedan usar con seguridad&
-dem$sB as se les evita @ue cometan errores por manipular inadecuadamente miem"ros @ue no
de"eran tocar&
Se !acilita al creador del tipo la posterior modi!icacin del mismoB pues si los programadores
clientes no pueden acceder a los miem"ros no visi"lesB sus aplicaciones no se ver$n a!ectadas si
,stos cam"ian o se eliminan& ;racias a esto es posi"le crear inicialmente tipos de datos con un
dise7o sencillo aun@ue poco e!icienteB y si posteriormente es necesario modi!icarlos para
aumentar su e!icienciaB ello puede (acerse sin a!ectar al cdigo escrito en "ase a la no mejorada
de tipo&
#a encapsulacin se consigue a7adiendo modificadores de acceso en las de!iniciones de miem"ros
y tipos de datos& %stos modi!icadores son partculas @ue se les colocan delante para indicar desde @u,
cdigos puede accederse a ellosB entendi,ndose por acceder el (ec(o de usar su nom"re para cual@uier
cosa @ue no sea de!inirloB como llamarlo si es una !uncinB leer o escri"ir su valor si es un campoB crear
o"jetos o (eredar de ,l si es una claseB etc&
Por de!ecto se considera @ue los miem"ros de un tipo de dato slo son accesi"les desde cdigo
situado dentro de la de!inicin del mismoB aun@ue esto puede cam"iarse precedi,ndolos de uno los
siguientes modi!icadores =aun@ue algunos de ellos ya se (an e*plicado a lo largo del temaB a@u se
recogen todos de manera detallada? al de!inirlosA
"ublic: Puede ser accedido desde cual@uier cdigo&
"rotected: )esde una clase slo puede accederse a miem"ros "rotected de o"jetos de esa
misma clase o de su"clases suyas& -sB en el siguiente cdigo las instrucciones comentadas
con II %rror no son v$lidas por lo escrito junto a ellasA
public class A
{
protected int x;
static void F(A a, B b, C c)
{
a.x = 1; // Ok
b.x = 1; // Ok
c.x = 1; // OK
}
}

public class B: A
{
static void F(A a, B b, C c)
{
//a.x = 1; // Error, ha de accederse a traves de objetos tipo B o C
b.x = 1; // Ok
c.x = 1; // Ok
}
}

public class C: B
{
static void F(A a, B b, C c)
{
//a.x = 1; // Error, ha de accederse a traves de objetos tipo C
//b.x = 1; // Error, ha de accederse a traves de objetos tipo C
c.x = 1; // Ok
}
}
O"viamente siempre @ue se (erede de una clase se tendr$ total acceso en la clase (ija He implcitamente
sin necesidad de usar la sinta*is jo"jeto6.jmiem"ro65 a los miem"ros @ue ,sta (erede de su clase
padreB como muestra el siguiente ejemploA
using System;
class A
{
protected int x=5;
}
class B:A
{
B()
{
Console.WriteLine("Heredado x={0} de clase A", x);
}

public static void Main()
{
new B();
}
}
Como es de esperarB la salida por pantalla del programa de ejemplo ser$A
Heredado *MV de clase -

- lo @ue no se podr$ acceder desde una clase (ija es a los miem"ros protegidos de otros o"jetos de su
clase padreB sino slo a los (eredados& %s decirA
using System;
class A
{
protected int x=5;
}
class B:A
{
B(A objeto)
{
Console.WriteLine("Heredado x={0} de clase A", x);
Console.WriteLine(objeto.x); // Error, no es el x heredado
}

public static void Main()
{
new B(new A());
}
}
"rivate: Slo puede ser accedido desde el cdigo de la clase a la @ue pertenece& %s lo
considerado por de!ecto&
internal: Slo puede ser accedido desde cdigo perteneciente al ensam"lado en @ue se (a
de!inido&
"rotected internal: Slo puede ser accedido desde cdigo perteneciente al ensam"lado en @ue
se (a de!inido o desde clases @ue deriven de la clase donde se (a de!inido&
Si se duda so"re el modi!icador de visi"ilidad a poner a un miem"roB es mejor ponerle inicialmente
el @ue proporcione menos permisos de accesosB ya @ue si luego detecta @ue necesita darle m$s permisos
siempre podr$ cam"i$rselo por otro menos restringido& Sin em"argoB si se le da uno m$s permisivo de
lo necesario y luego se necesita cam"iar por otro menos permisivoB los cdigos @ue escrito en "ase a la
versin m$s permisiva @ue dependiesen de dic(o miem"ro podran dejar de !uncionar por @uedarse sin
acceso a ,l&
%s importante recordar @ue toda rede!inicin de un m,todo virtual o a"stracto (a de reali/arse
manteniendo los mismos modi!icadores @ue tuviese el m,todo original& %s decirB no podemos rede!inir
un m,todo protegido cam"iando su accesi"ilidad por pC"licaB pues si el creador de la clase "ase lo
de!ini as por algo sera&
+especto a los tipos de datosB por de!ecto se considera @ue son accesi"les slo desde el mismo
ensam"lado en @ue (a sido de!inidosB aun@ue tam"i,n es posi"le modi!icar esta consideracin
anteponiendo uno de los siguientes modi!icadores a su de!inicinA
"ublic: %s posi"le acceder a la clase desde cual@uier ensam"lado&
internal: Slo es posi"le acceder a la clase desde el ensam"lado donde se declar& %s lo
considerado por de!ecto&
.am"i,n pueden de!inirse tipos dentro de otros =ti"os internos? %n ese caso ser$n considerados
miem"ros del tipo contenedor dentro de la @ue se (ayan de!inidoB por lo @ue les ser$n aplica"les todos
los modi!icadores v$lidos para miem"ros y por de!ecto se considerar$ @ueB como con cual@uier
miem"roB son privados& Para acceder a estos tipos desde cdigo e*terno a su tipo contenedor =ya sea
para (eredar de ellosB crear o"jetos suyos o acceder a sus miem"ros est$ticos?B adem$s de necesitarse
los permisos de acceso necesarios segCn el modi!icador de accesi"ilidad al de!inirlosB (ay @ue usar la
notacin jnom"re.ipoContendor6.jnom"re.ipoInterno6B como muestra en este ejemploA
// No lleva modificador, luego se considera que es internal
class A
{
// Si ahora no se pusiese public se considerara private
public class AInterna {}
}
// B deriva de la clase interna AInterna definida dentro de A.
// Es vlido porque A.AInterna es pblica
class B:A.AInterna
{}
8tese @ue dado @ue los tipos e*ternos est$n de!inidos dentro de su tipo e*ternoB desde ellos es
posi"le acceder a los miem"ros est$ticos privados de ,ste& Sin em"argoB (ay @ue se7alar @ue no
"ueden acceder a los miembros no est$ticos de su ti"o contenedor&
Es"acios de nombres
Conce"to de es"acio de nombres
)el mismo modo @ue los !ic(eros se organi/an en directoriosB los tipos de datos se organi/an en
es"acio de nombres&
Por un ladoB esto permite tenerlos m$s organi/ados y !acilita su locali/acin& )e (ec(oB as es como
se (alla organi/ada la 0C#B de modo @ue todas las clases m$s comCnmente usadas en cual@uier
aplicacin se (allan en el espacio de nom"res llamado S(stemB las de acceso a "ases de datos en
S(stem.EataB las de reali/acin de operaciones de entradaIsalida en S(stem.IB etc&
Por otro ladoB los espacios de nom"res tam"i,n permiten poder usar en un mismo programa varias
clases con igual nom"re si pertenecen a espacios di!erentes& #a idea es @ue cada !a"ricante de!ina sus
tipos dentro de un espacio de nom"res propio para @ue as no (aya con!lictos si varios !a"ricantes
de!inen clases con el mismo nom"re y se @uieren usar a la ve/ en un mismo programa& O"viamente
para @ue esto !uncione no (an de coincidir los nom"res los espacios de cada !a"ricanteB y una !orma de
conseguirlo es d$ndoles el nom"re de la empresa !a"ricanteB o su nom"re de dominio en InternetB etc&
'efinici%n de espacios de nombres
Para de!inir un espacio de nom"res se utili/a la siguiente sinta*isA
namespace <nombreEspacio>
{
<tipos>
}
#os as de!inidos pasar$n a considerase miem"ros del espacio de nom"res llamado & Como veremos
m$s adelanteB aparte de clases estos tipos pueden ser tam"i,n inter!acesB estructurasB tipos enumerados
y delegados& - continuacin se muestra un ejemplo en el @ue de!inimos una clase de nom"re
Clase%jemplo perteneciente a un espacio de nom"res llamado %spacio%jemploA
namespace (spacio(jemplo
{
class ClaseEjemplo
{}
}
%l verdadero nom"re de una claseB al @ue se denomina nom"re completamente cali!icadoB es el
nom"re @ue le demos al declararla pre!ijado por la concatenacin de todos los espacios de nom"res a
los @ue pertenece ordenados del m$s e*terno al m$s interno y seguido cada uno de ellos por un punto
=car$cter &? Por ejemploB el verdadero nom"re de la clase Clase%jemplo antes de!inida es
%spacio%jemplo&Clase%jemplo& Si no de!inimos una clase dentro de una de!inicin de espacio de
nom"res 5como se (a (ec(o en los ejemplos de temas previos5 se considera @ue ,sta pertenece al
llamado espacio de nom"res glo"al y su nom"re completamente cali!icado coincidir$ con el
identi!icador @ue tras la pala"ra reservada class le demos en su de!inicin =nom"re simple?
-parte de de!iniciones de tipoB tam"i,n es posi"le incluir como miem"ros de un espacio de nom"res
a otros espacios de nom"res& %s decirB como se muestra el siguiente ejemplo es posi"le anidar espacios
de nom"resA
namespace (spacio(jemplo
{
namespace (spacio(jemplo*
{
class ClaseEjemplo
{}
}
}
-(ora Clase%jemplo tendr$ %spacio%jemplo&%spacio%jemplo9&Clase%jemplo como nom"re
completamente cali!icado& %n realidad es posi"le compactar las de!iniciones de espacios de nom"res
anidados usando esta sinta*is de cali!icacin completa para dar el nom"re del espacio de nom"res a
de!inir& %s decirB el Cltimo ejemplo es e@uivalente aA
namespace (spacio(jemplo#(spacio(jemplo*
{
class ClaseEjemplo
{}
}
%n am"os casos lo @ue se (a de!inido es una clase Clase%jemplo perteneciente al espacio de nom"res
%spacio%jemplo9 @ueB a su ve/B pertenece al espacio %spacio%jemplo&
Importaci%n de espacios de nombres
Sentencia usin$
En "rinci"ioU si desde c!digo "erteneciente a una clase definida en un cierto es"acio de
nombres se desea hacer referencia a ti"os definidos en otros es"acios de nombresU se ha de
referir a los mismos usando su nombre com"letamente calificado. 1or ejem"lo:
namespace (spacio(jemplo#(spacio(jemplo*
{
class ClaseEjemplo
{}
}
class Principal // Pertenece al espacio de nombres global
{
public static void Main()
{
EspacioEjemplo.EspacioEjemplo2.ClaseEjemplo c =
new EspacioEjemplo.EspacioEjemplo2.ClaseEjemplo();
}
}

Como puede resultar muy pesado tener @ue escri"ir nom"res tan largos cada ve/ @ue se re!erencie a
tipos as de!inidosB C# incluye un mecanismo de importacin de espacios de nom"res @ue simpli!ica la
tarea y se "asa en una sentencia @ue usa la siguiente sinta*isA
using <espacioNombres>$

%stas sentencias siempre (an de aparecer en la de!inicin de espacio de nom"res antes @ue cual@uier
de!inicin de miem"ros de la misma& Permiten indicar cu$les ser$n los espacios de nom"res @ue se
usar$n implcitamente dentro de ese espacio de nom"res& - los miem"ros de los espacios de nom"res
as importados se les podr$ re!erenciar sin usar cali!icacin completa& -sB aplicando esto al ejemplo
anterior @uedaraA
using (spacio(jemplo#(spacio(jemplo*;
namespace (spacio(jemplo#(spacio(jemplo*
{
class ClaseEjemplo
{}
}
// (1)
class Principal // Pertenece al espacio de nombres global
{
public static void Main()
{
// EspacioEjemplo.EspacioEjemplo2. est implcito
ClaseEjemplo c = new ClaseEjemplo();
}
}

8tese @ue la sentencia using no podra (a"erse incluido en la /ona marcada en el cdigo como =F?
por@ue entonces se violara la regla de @ue todo using (a aparecer en un espacio de nom"res antes @ue
cual@uier de!inicin de miem"ro =la de!inicin del espacio de nom"res
%spacio%jemplo&%spacio%jemplo9 es un miem"ro del espacio de nom"res glo"al? Sin em"argoB el
siguiente cdigo s @ue sera v$lidoA
namespace (spacio(jemplo#(spacio(jemplo*
{
class ClaseEjemplo
{}
}
namespace )rincipal
{
using EspacioEjemplo.EspacioEjemplo2;
class Principal // Pertenece al espacio de nombres global
{
public static void Main()
{
ClaseEjemplo c = new ClaseEjemplo();
}
}
}
%n este caso el using aparece antes @ue cual@uier otra de!inicin de tipos dentro del espacio de
nom"res en @ue se incluye =Principal? Sin em"argoB a(ora la importacin (ec(a con el using slo ser$
v$lida dentro de cdigo incluido en ese mismo espacio de nom"resB mientras @ue en el caso anterior era
v$lida en todo el !ic(ero al estar incluida en el espacio de nom"res glo"al&
)e"e tenerse en cuenta @ue si una sentencia using importa miem"ros de igual nom"re @ue miem"ros
de!inidos en el espacio de nom"res en @ue se incluyeB no se produce error alguno pero se dar$
pre!erencia a los miem"ros no importados& 1n ejemploA
namespace +,#+*
{
class A {}
class B {}
}
namespace +-
{
using N1.N2;
class A {}
class C: A {}
}
-@u C deriva de 8O&- en ve/ de 8F&89&-& Si @ueremos lo contrario tendremos @ue re!erenciar a
8F&89&- por su nom"re completo al de!inir C oB como se e*plica a continuacinB usar un alias&
Especi"icacin de alias
-Cn en el caso de @ue usemos espacios de nom"res distintos para di!erenciar clases con igual
nom"re pero procedentes de distintos !a"ricantesB podran darse con!lictos si usamos sentencias using
para importar los espacios de nom"res de dic(os !a"ricantes ya @ue entonces al (acerse re!erencia a una
de las clases comunes con tan solo su nom"re simple el compilador no podr$ determinar a cual de ellas
en concreto nos re!erimos&
Por ejemploB si tenemos una clase de nom"re completamente cali!icado -&ClaseB otra de nom"re
0&ClaseB y (acemosA
using A;
using B;
class EjemploConflicto: Clase {}
kCmo sa"r$ el compilador si lo @ue @ueremos es derivar de -&Clase o de 0&Clase> Pues en realidad
no podr$ determinarlo y producir$ un error in!ormando de @ue e*iste una re!erencia am"igua a Clase en
el cdigo&
Para resolver am"ig<edades de este tipo podra (acerse re!erencia a los tipos en con!licto usando
siempre sus nom"res completamente cali!icadosB pero ello puede llegar a ser muy !atigoso so"re todo si
sus nom"res son muy largos& Para solucionarlo sin escri"ir tantoB C# permite de!inir alias para
cual@uier tipo de datoB @ue son sinnimos @ue se les de!inen utili/ando la siguiente sinta*isA
using <alias> % <nombreCompletoTipo>$
Como cual@uier otro usingB las de!iniciones de alias slo pueden incluirse al principio de las
de!iniciones de espacios de nom"res y slo tienen valide/ dentro de las mismas&
)e!iniendo alias distintos para los tipos en con!lictos se resuelven los pro"lemas de am"ig<edades&
Por ejemploB el pro"lema del ejemplo anterior podra resolverse asA
using A;
using B;
using ClaseA = A.Clase;
class EjemploConflicto: ClaseA
{} // Heredamos de A.Clase
#os alias no tienen por@u, ser slo re!erentes a tiposB sino @ue tam"i,n es posi"le escri"ir alias de
espacios de nom"res& Por ejemploA
namespace +,#+*
{
class A {}
}
namespace +-
{
using R1 = N1;
using R2 = N1.N2;
class B
{
N1.N2.A a; // Campo de nombre completamente calificado N1.N2.A
R1.N2.A b; // Campo de nombre completamente calificado N1.N2.A
R2.A c; // Campo de nombre completamente calificado N1.N2.A
}
}
-l de!inir alias (ay @ue tener cuidado con no de!inir en un mismo espacio de nom"res varios con
igual nom"re o cuyos nom"res coincidan con los de miem"ros de dic(o espacio de nom"res& .am"i,n
(ay @ue tener en cuenta @ue no se pueden de!inir unos alias en !uncin de otroB por lo @ue cdigos
como el siguiente son incorrectosA
namespace +,#+* {}
namespace +-
{
using R1 = N1;
using R2 = N1.N2;
using R3 = R1.N2; // ERROR: No se puede definir R3 en funcin de R1
}

Espacio de nombres distribuidos
Si (acemos varias de!iniciones de un espacio de nom"res en un mismo o di!erentes !ic(eros y se
compilan todas juntasB el compilador las !usionar$ en una sola de!inicin cuyos miem"ros ser$n la
concatenacin de los de de!inicin reali/ada& Por ejemploA
namespace . // (1)
{
class B1 {}
}
namespace . // (2)
{
class B2 {}
}
1na de!inicin como la anterior es tratada por el compilador e*actamente igual @ueA
namespace .
{
class B1 {}
class B2 {}
}
W lo mismo ocurrira si las de!iniciones marcadas como =F? y =9? se (u"iesen (ec(o en !ic(eros
separados @ue se compilasen conjuntamente&
Hay @ue tener en cuenta @ue las sentencias usingB ya sean de importacin de espacios de nom"res o
de de!inicin de aliasB no son consideradas miem"ros de los espacios de nom"res y por tanto no
participan en sus !usiones& -sB el siguiente cdigo es inv$lidoA
namespace .
{
class ClaseA {}
}
namespace /
{
using A;
}
namespace /
{
// using A;
class Principal: ClaseA {}
}

%ste cdigo no es correcto por@ue aun@ue se importa el espacio de nom"res - al principio de una
de!inicin del espacio de nom"res donde se (a de!inido PrincipalB no se importa en la misma de!inicin
donde se deriva Principal de -&Clase-& Para @ue el cdigo compilase (a"ra @ue descomentar la lnea
comentada&
Eefinici!n de variables
Jna variable "uede verse sim"lemente como un hueco en el Sue se "uede almacenar un
objeto de un determinado ti"o al Sue se le da un cierto nombre. 1ara "oderla utilizar s!lo
ha( Sue definirla indicando cual er$ su nombre ( cual ser$ el ti"o de datos Sue "odr$
almacenarU lo Sue se hace siguiendo la siguiente inta)is:
<tipoVariable> <nombreVariable>$

1na varia"le puede ser de!inida dentro de una de!inicin de claseB en cuyo caso se correspondera
con el tipo de miem"ro @ue (asta a(ora (emos denominado campo& .am"i,n puede de!inirse como un
varia"le local a un m,todoB @ue es una varia"le de!inida dentro del cdigo del m,todo a la @ue slo
puede accederse desde dentro de dic(o cdigo& Otra posi"ilidad es de!inirla como par$metro de un
m,todoB @ue son varia"les @ue almacenan los valores de llamada al m,todo y @ueB al igual @ue las
varia"les localesB slo puede ser accedidas desde cdigo u"icado dentro del m,todo& %l siguiente
ejemplo muestra como de!inir varia"les de todos estos casosA
class A
{
int x, z;
int y;
void F(string a, string b)
{
Persona p;
}
}
%n este ejemplo las varia"les *B / e y son campos de tipo intB mientras @ue p es una varia"le local de
tipo Persona y a y " son par$metros de tipo string& Como se muestra en el ejemploB si un m,todo toma
varios par$metros las de!iniciones de ,stos se separan mediante comas =car$cter B?B y si @ueremos
de!inir varios campos o varia"les locales =no v$lido para par$metros? de un mismo tipo podemos
incluirlos en una misma de!inicin incluyendo en sus nom"res separados por comas&
Con la sinta*is de de!inicin de varia"les anteriormente dada simplemente de!inimos varia"les pero
no almacenamos ningCn o"jeto inicial en ellas& %l compilador dar$ un valor por de!ecto a los campos
para los @ue no se indi@ue e*plcitamente ningCn valor segCn se e*plica en el siguiente apartado& Sin
em"argoB a la varia"les locales no les da ningCn valor inicialB pero detecta cual@uier intento de leerlas
antes de darles valor y produce errores de compilacin en esos casos&
Wa (emos visto @ue para crear o"jetos se utili/a el operador ne'& Por tantoB una !orma de asignar un
valor a la varia"le p del ejemplo anterior sera asA
Persona p;
p = new Persona("Jos", 22, "76543876-A");
Sin em"argoB C# tam"i,n proporciona una sinta*is m$s sencilla con la @ue podremos asignar un
o"jeto a una varia"le en el mismo momento se de!ine& Para ello se la (a de de!inir usando esta otra
notacinA
<tipoVariable> <nombreVariable> % <valorInicial>$

-s por ejemploB la anterior asignacin de valor a la varia"le p podra rescri"irse de esta otra !orma
m$s compactaA
Persona p = new Persona("Jos", 22, "76543876-A");
#a especi!icacin de un valor inicial tam"i,n com"inarse con la de!inicin de mCltiples varia"les
separadas por comas en una misma lnea& Por ejemploB las siguientes de!iniciones son v$lidasA
Persona p1 = new Persona("Jos", 22, "76543876-A"),
p2 = new Persona("Juan", 21, "87654212-S");
W son tratadas por el compilador de !orma completamente e@uivalentes a (a"erlas declarado comoA
Persona p1 = new Persona("Jos", 22, "76543876-A");
Persona p2 = new Persona("Juan", 21, "87654212-S");

(ipos de datos bsicos
#os tipos de datos "$sicos son ciertos tipos de datos tan comCnmente utili/ados en la escritura de
aplicaciones @ue en C# se (a incluido una sinta*is especial para tratarlos& Por ejemploB para representar
nCmeros enteros de O9 "its con signo se utili/a el tipo de dato System&IntO9 de!inido en la 0C#B aun@ue
a la (ora de crear un o"jeto a de este tipo @ue represente el valor 9 se usa la siguiente sinta*isA
System.Int32 a = 2;
Como se veB no se utili/a el operador ne' para crear o"jeto System&IntO9B sino @ue directamente se
indica el literal @ue representa el valor a crearB con lo @ue la sinta*is necesaria para crear entero de este
tipo se reduce considera"lemente& %s m$sB dado lo !recuente @ue es el uso de este tipo tam"i,n se (a
prede!inido en C# el alias int para el mismoB por lo @ue la de!inicin de varia"le anterior @ueda as de
compactaA
int a = 2;
S(stem.Int53 no es el Cnico tipo de dato "$sico incluido en C#& %n el espacio de nom"res System se
(an incluido todos estosA
.ipo )escripcin 0its +ango de valores -lias
S=(te 6tes con signo G R5F9GB F9YS s"yte
=(te 6tes sin signo G R:B 9VVS "yte
Int27 %nteros cortos con signo FZ R5O9&YZGB O9&YZYS s(ort
JInt27 %nteros cortos sin signo FZ R:B ZV&VOVS us(ort
Int53 %nteros normales O9
R59&FXY&XGO&ZXGB
9&FXY&XGO&ZXYS
int
JInt53 %nteros normales sin signo O9 R:B X&9dX&dZY&9dVS uint
Int76 %nteros largos ZX
R5
d&99O&OY9&:OZ&GVX&YYV&G:GB

d&99O&OY9&:OZ&GVX&YYV&G:YS
long
JInt76 %nteros largos sin signo ZX
R:5
FG&XXZ&YXX&:YO&Y:d&VVF&ZFVS
ulong
Single
+eales con Y dgitos de
precisin
O9 RFBVnF:
5XV
5 OBXnF:
OG
S !loat
Eouble
+eales de FV5FZ dgitos de
precisin
ZX RVB:nF:
5O9X
5 FBYnF:
O:G
S dou"le
Eecimal
+eales de 9G59d dgitos de
precisin
F9G RFB:nF:
59G
5 YBdnF:
9G
S decimal
=oolean Valores lgicos O9 trueB false "ool
Char Caracteres 1nicode FZ Rh\u::::iB h\uiS c(ar
String Cadenas de caracteres Varia"le %l permitido por la memoria string
bject Cual@uier o"jeto Varia"le Cual@uier o"jeto o"ject
.a"la V A .ipos de datos "$sicos
Pese a su sinta*is especialB en C# los tipos "$sicos son tipos del mismo nivel @ue cual@uier otro tipo
del lenguaje& %s decirB (eredan de System&O"ject y pueden ser tratados como o"jetos de dic(a clase por
cual@uier m,todo @ue espere un System&O"jectB lo @ue es muy Ctil para el dise7o de rutinas gen,ricas
@ue admitan par$metros de cual@uier tipo y es una ventaja importante de C# !rente a lenguajes
similares como Eava donde los tipos "$sicos no son considerados o"jetos&
%l valor @ue por de!ecto se da a los campos de tipos "$sicos consiste en poner a cero todo el $rea de
memoria @ue ocupen& %sto se traduce en @ue los campos de tipos "$sicos num,ricos se iniciali/an por
de!ecto con el valor :B los de tipo "ool lo (acen con !alseB los de tipo c(ar con h\u::::iB y los de tipo
string y o"ject con null&
-(ora @ue sa"emos cu$les son los tipos "$sicosB es el momento de comentar cu$les son los su!ijos
@ue admiten los literales num,ricos para indicar al compilador cu$l es el tipo @ue se (a de considerar
@ue tiene& Por ejemploB si tenemos en una clase los m,todosA
public static void F(int x)
{...}
public static void F(long x)
{...}
-nte una llamada como =F::?B ka cu$l de los m,todos se llamara> Pues "ienB en principio se
considera @ue el tipo de un literal entero es el correspondiente al primero de estos tipos "$sicos @ue
permitan almacenarloA intB uintB longB ulongB por lo @ue en el caso anterior se llamara al primer =? Para
llamar al otro podra a7adirse el su!ijo # al literal y (acer la llamada con =F::#? %n la .a"la Z se
resumen los posi"les su!ijos v$lidosA
Su!ijo .ipo del literal entero
ninguno Primero deA intU uintU longB ulong
: lRdS Primero deA longU ulong
J u Primero deA intU uint
J:U JlU u:U ulU :JU :uU lJ lu ulong
.a"la ZA Su!ijos de literales enteros
Por su parteB en la .a"la Y se indican los su!ijos @ue admiten los literales realesA
Su!ijo .ipo del literal real
D f float
ningunoB E d double
M m decimal
.a"la YA Su!ijos de literales reales
Tablas unidimensionales

1na ta"la unidimensional o vector es un tipo especial de varia"le @ue es capa/ de almacenar en su
interior y de manera ordenada uno o varios datos de un determinado tipo& Para declarar ta"las se usa la
siguiente sinta*isA
<tipoDatos>[] <nombreTabla>$
Por ejemploB una ta"la @ue pueda almacenar o"jetos de tipo int se declara asA
int[] tabla;
Con esto la ta"la creada no almacenara ningCn o"jetoB sino @ue valdra null& Si se desea @ue
verdaderamente almacene o"jetos (ay @ue indicar cu$l es el nCmero de o"jetos @ue podr$ almacenarB lo
@ue puede (acerse usando la siguiente sinta*is al declararlaA
<tipoDatos>[] <nombreTabla> = new <tipoDatos>[<nmeroDatos>];
Por ejemploB una ta"la @ue pueda almacenar F:: o"jetos de tipo int se declara asA
int[] tabla = new int[100];
-un@ue tam"i,n sera posi"le de!inir el tama7o de la ta"la de !orma separada a su declaracin de
este modoA
int[] tabla;
tabla = new int[100];
Con esta Cltima sinta*is es posi"le cam"iar din$micamente el nCmero de elementos de una varia"le
ta"la sin m$s @ue irle asignando nuevas ta"las& %llo no signi!ica @ue una ta"la se pueda redimensionar
conservando los elementos @ue tuviese antes del cam"io de tama7oB sino @ue ocurre todo lo contrarioA
cuando a una varia"le ta"la se le asigna una ta"la de otro tama7oB sus elementos antiguos son
so"reescritos por los nuevos&
Si se crea una ta"la con la sinta*is (asta a(ora e*plicada todos sus elementos tendran el valor por
de!ecto de su tipo de dato& Si @ueremos darles otros valores al declarar la ta"laB (emos de indicarlos
entre llaves usando esta sinta*isA
<tipoDatos>[] <nombreTabla> = new <tipoDatos>[] 0<valores>1$
Han de especi!icarse tantos jvalores6 como nCmero de elementos se desee @ue tenga la ta"laB y si
son m$s de uno se (an de separar entre s mediante comas =U? 8tese @ue a(ora no es necesario indicar
el nCmero de elementos de la ta"la =aun@ue puede (acerse si se desea?B pues el compilador puede
deducirlo del nCmero de valores especi!icados& Por ejemploB para declarar una ta"la de cuatro
elementos de tipo int con valores VBFBXB: se podra (acer lo siguienteA
int[] tabla = new int[] {5,1,4,0};
Incluso se puede compactar aCn m$s la sinta*is declarando la ta"la asA
int[] tabla = {5,1,4,0};
.am"i,n podemos crear ta"las cuyo tama7o se pueda esta"lecer din$micamente a partir del valor de
cual@uier e*presin @ue produ/ca un valor de tipo entero& Por ejemploB para crear una ta"la cuyo
tama7o sea el valor indicado por una varia"le de tipo int =luego su valor ser$ de tipo entero? se (araA
int i = 5;
...
int[] tablaDinmica = new int[i];
- la (ora de acceder a los elementos almacenados en una ta"la "asta indicar entre corc(etesB y a
continuacin de la re!erencia a la mismaB la posicin @ue ocupe en la ta"la el elemento al @ue acceder&
Cuando se (aga (ay @ue tener en cuenta @ue en C# las ta"las se inde*an desde :B lo @ue signi!ica @ue el
primer elemento de la ta"la ocupar$ su posicin :B el segundo ocupar$ la posicin FB y as
sucesivamente para el resto de elementos& Por ejemploB aun@ue es m$s ine!icienteB la ta"la declarada en
el Cltimo !ragmento de cdigo de ejemplo tam"i,n podra (a"erse de!inido asA
int[] tabla = new int[4];
tabla[0] = 5;
// Por defecto se inicializ a 0,
// luego ahora el valor de tabla[1] pasa a ser 1
tabla[1]++;
tabla[2] = tabla[0] - tabla[1];
// tabla[2] pasa a valer 4, pues 5-4 = 1
// El contenido de la tabla ser {5,1,4,0},
// pues tabla[3] se inicializ por defecto a 0.
Hay @ue tener cuidado a la (ora de acceder a los elementos de una ta"la ya @ue si se especi!ica una
posicin superior al nCmero de elementos @ue pueda almacenar la ta"la se producir$ una e*cepcin de
tipo S(stem.utf=oundsE)ce"tion& %n el Tema &5: "#str$%%io#es se e*plica @u, son las
e*cepcionesB pero por a(ora "asta considerar @ue son o"jetos @ue in!orman de situaciones
e*cepcionales =generalmente errores? producidas durante la ejecucin de una aplicacin& Para evitar
este tipo de e*cepciones puede consultar el valor del campoRF:S de slo lectura :ength @ue est$
asociado a toda ta"la y contiene el nCmero de elementos de la misma& Por ejemploB para asignar un Y al
Cltimo elemento de la ta"la anterior se (araA
tabla[tabla.Length - 1] = 7;
// Se resta 1 porque tabla.Length devuelve 4 pero el ltimo
// elemento de la tabla es tabla[3]
ablas dentadas
1na tabla dentada no es m$s @ue una ta"la cuyos elementos son a su ve/ ta"lasB pudi,ndose as
anidar cual@uier nCmero de ta"las& Para declarar ta"las de este tipo se usa una sinta*is muy similar a la
e*plicada para las ta"las unidimensionalesB slo @ue a(ora se indican tantos corc(etes como nivel de
anidacin se desee& Por ejemploB para crear una ta"la de ta"las de elementos de tipo int !ormada por
dos elementosB uno de los cuales !uese una ta"la de elementos de tipo int !ormada por los elementos de
valores FB9 y el otro !uese una ta"la de elementos de tipo int y valores OBXBVB se puede (acerA

int[][] tablaDentada = new int[2][] {new int[] {1,2}, new int[] {3,4,5}};
Como se indica e*plcitamente cu$les son los elementos de la ta"la declarada no (ace !alta indicar el
tama7o de la ta"laB por lo @ue la declaracin anterior es e@uivalente aA
int[][] tablaDentada = new int[][] {new int[] {1,2}, new int[] {3,4,5}};
%s m$sB igual @ue como se vi con las ta"las unidimensionales tam"i,n es v$lido (acerA
int[][] tablaDentada = {new int[] {1,2}, new int[] {3,4,5}};
Si no @uisi,semos indicar cu$les son los elementos de las ta"las componentesB entonces tendramos
@ue indicar al menos cu$l es el nCmero de elementos @ue podr$n almacenar =se iniciali/ar$n con
valores por de!ecto? @uedandoA
int[][] tablaDentada = {new int[2], new int[3]};
Si no @ueremos crear las ta"las componentes en el momento de crear la ta"la dentadaB entonces
tendremos @ue indicar por lo menos cu$l es el nCmero de ta"las componentes posi"les =cada una
valdra null?B con lo @ue @uedaraA
int[][] tablaDentada = new int[2][];
%s importante se7alar @ue no es posi"le especi!icar todas las dimensiones de una ta"la dentada en su
de!inicin si no se indica e*plcitamente el valor inicial de ,stas entre llaves& %s decirB esta declaracin
es incorrectaA
int[][] tablaDentada = new int[2][5];
%sto se de"e a @ue el tama7o de cada ta"la componente puede ser distinto y con la sinta*is anterior
no se puede decir cu$l es el tama7o de cada una& 1na opcin (u"iese sido considerar @ue es V para
todas como se (ace en EavaB pero ello no se (a implementado en C# y (a"ra @ue declarar la ta"la deB
por ejemploB esta maneraA
int[][] tablaDentada = {new int[5], new int[5]);
inalmenteB si slo @ueremos declarar una varia"le ta"la dentada pero no @ueremos indicar su
nCmero de elementosB =luego la varia"le valdra null?B entonces "asta ponerA
int[][] tablaDentada;
Hay @ue precisar @ue aun@ue en los ejemplos (asta a(ora presentes se (an escrito ejemplos "asados
en ta"las dentadas de slo dos niveles de anidacinB tam"i,n es posi"le crear ta"las dentadas de
cual@uier nCmero de niveles de anidacin& Por ejemploB para una ta"la de ta"las de ta"las de enteros de
9 elementos en la @ue el primero !uese una ta"la dentada !ormada por dos ta"las de V enteros y el
segundo elemento !uese una ta"la dentada !ormada por una ta"la de X enteros y otra de O se podra
de!inir asA
int[][][] tablaDentada = new int[][][]
{ new int[][] {new int[5], new int[5]},
new int[][] {new int[4], new int[3]}};
- la (ora de acceder a los elementos de una ta"la dentada lo Cnico @ue (ay @ue (acer es indicar entre
corc(etes cu$l es el elemento e*acto de las ta"las componentes al @ue se desea accederB indic$ndose un
elemento de cada nivel de anidacin entre unos corc(etes di!erentes pero coloc$ndose todas las parejas
de corc(etes juntas y ordenadas de la ta"la m$s e*terna a la m$s interna& Por ejemploB para asignar el
valor F: al elemento cuarto de la ta"la @ue es elemento primero de la ta"la @ue es elemento segundo de
la ta"la dentada declarada en Cltimo lugar se (araA
tablaDentada[1][0][3] = 10;

Tablas multidimensionales
Jna tabla multidimensional o matriz es aSuella cu(os elementos se encuentran organizados en
una estructura de varias dimensiones. 1ara definirlas se utiliza una sinta)is similar a la
usada "ara declarar tablas unidimensionales "ero se"arando las diferentes dimensiones
mediante comas ;U< 1or ejem"loU una tabla multidimensional de elementos de ti"o int Sue
conste de 23 elementos "uede tener sus elementos distribuidos en dos dimensiones
formando una estructura 5)6 similar a una matriz de la forma:
F 9 O
X V Z
Y G d
%sta ta"la se podra declarar asA

int[,] tablaMultidimensional = new int[3,4] {{1,2,3,4},
{5,6,7,8},
{9,10,11,12}};

%n realidad no es necesario indicar el nCmero de elementos de cada dimensin de la ta"la ya @ue
pueden deducirse de los valores e*plcitamente indicados entre llavesB por lo @ue la de!inicin anterior
es similar a estaA
int[,] tablaMultidimensional = new int[,] {{1,2,3,4},
{5,6,7,8},
{9,10,11,12}};
Incluso puede reducirse aCn m$s la sinta*is necesaria @uedando tan sloA
int[,] tablaMultidimensional = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};
Si no @ueremos indicar e*plcitamente los elementos de la ta"la al declararlaB podemos o"viarlos
pero aCn as indicar el tama7o de cada dimensin de la ta"la =a los elementos se les dara el valor por
de!ecto de su tipo de dato? asA
int[,] tablaMultidimensional = new int[3,4];
.am"i,n podemos no especi!icar ni si@uiera el nCmero de elementos de la ta"la de esta !orma
=ta"laMultidimensional contendra a(ora null?A
int[,] tablaMultidimensional;
-un@ue los ejemplos de ta"las multidimensionales (asta a(ora mostrados son de ta"las de dos
dimensionesB en general tam"i,n es posi"le crear ta"las de cual@uier nCmero de dimensiones& Por
ejemploB una ta"la @ue almacene 9X elementos de tipo int y valor : en una estructura tridimensional
O*X*9 se declarara asA
int[,,] tablaMultidimensional = new int[3,4,2];
%l acceso a los elementos de una ta"la multidimensional es muy sencilloA slo (ay @ue indicar los
ndices de la posicin @ue ocupe en la estructura multidimensional el elemento al @ue se desee acceder&
Por ejemploB para incrementar en una unidad el elemento @ue ocupe la posicin =FBOB9? de la ta"la
anterior se (ara =se indi/a desde :?A
tablaMultidimensional[0,2,1]++;
8tese @ue tanto las ta"las dentadas como las ta"las multidimensionales pueden ser utili/adas tanto
para representar estructuras matriciales como paraB en generalB representar cual@uier estructura de
varias dimensiones& #a di!erencia entre am"as sonA
Como las ta"las dentadas son ta"las de ta"lasB cada uno de sus elementos puede ser una ta"la de
un tama7o di!erente& -sB con las ta"las dentadas podemos representar matrices en las @ue cada
columna tenga un tama7o distinto =por el aspecto KaserradoL de este tipo de matrices es por lo
@ue se les llama ta"las dentadas?B mientras @ue usando ta"las multidimensionales slo es posi"le
crear matrices rectangulares o cuadradas& #as estructuras aserradas pueden simularse usando
matrices multidimensionales con todas sus columnas del tama7o de la columna m$s grande
necesariaB aun@ue ello implica desperdiciar muc(a memoria so"re todo si los tama7os de cada
columna son muy di!erentes y la ta"la es grande& )e todos modosB las estructuras m$s comunes
@ue se usan en la mayora de aplicaciones suelen ser rectangulares o cuadradas&
#os tiempos @ue se tardan en crear y destruir ta"las dentadas son superiores a los @ue se tardan
en crear y destruir ta"las multidimensionales& %sto se de"e a @ue las primeras son ta"las de
ta"las mientras @ue las segundas son una Cnica ta"laB Por ejemploB para crear una ta"la dentada
RF::SRF::S (ay @ue crear F:F ta"las =la ta"la dentada m$s las F:: ta"las @ue contiene?B mientras
@ue para crear una crear una ta"la "idimensional RF::BF::S (ay @ue crear una Cnica ta"la&
#as ta"las dentadas no !orman parte del C#SB por lo @ue no todos los lenguajes gestionados los
tienen por@u, admitir& Por ejemplo Visual 0asic&8%. no las admiteB por lo @ue al usarlas en
miem"ros pC"licos e@uivale a perder interopera"ilidad con estos lenguajes&
ablas mi*tas
1na tabla mi)ta es simplemente una ta"la !ormada por ta"las multidimensionales y dentadas
com"inadas entre s de cual@uier manera& Para declarar una ta"la de este tipo "asta con tan solo
com"inar las notaciones ya vistas para las multidimensionales y dentadas& Por ejemploB para declarar
una ta"la de ta"las multidimensionales cuyos elementos sean ta"las unidimensionales de enteros se
(ara lo siguienteA
int[][,][] tablaMixta;
Covarian/a de ta"las
#a covarian/a de ta"las es el resultado de llevar el polimor!ismo al mundo de las ta"las& %s decirB es
la capacidad de toda ta"la de poder almacenar elementos de clases (ijas de la clase de elementos @ue
pueda almacenar& Por ejemploB en tanto @ue todas clases son (ijas de System&O"jectB la siguiente
asignacin es v$lidaA
string[] tablaCadenas = {"Manolo", "Paco", "Pepe"};
object[] tablaObjetos = tablaCadenas;
Hay @ue tener en cuenta @ue la covarian/a de ta"las slo se aplica a o"jetos de tipos re!erencia y no a
o"jetos de tipos valor Por ejemploB la siguiente asignacin no sera v$lida en tanto @ue int es un tipo
por valorA
int[] tablaEnteros = {1, 2, 3};
object[] tablaObjetos = tablaEnteros;

%a clase S.stem.Arra.
%n realidadB todas las ta"las @ue de!inamosB sea cual sea el tipo de elementos @ue contenganB son
o"jetos @ue derivan de S(stem.Frra(& %s decirB van a disponer de todos los miem"ros @ue se (an
de!inido para esta claseB entre los @ue son destaca"lesA
:engthA CampoRFFS de slo lectura @ue in!orma del nCmero total de elementos @ue contiene la
ta"la& Si la ta"la tiene m$s de una dimensin o nivel de anidacin indica el nCmero de
elementos de todas sus dimensiones y niveles& Por ejemploA
int[] tabla = {1,2,3,4};
int[][] tabla2 = {new int[] {1,2}, new int[] {3
int[,] tabla3 = {{1,2},{3,4,5,6}};

Console.WriteLine(tabla.Length); //Imprime 4
Console.WriteLine(tabla2.Length); //Imprime 5
Console.WriteLine(tabla3.Length); //Imprime 6
Can'A Campo de slo lectura @ue almacena el nCmero de dimensiones de la ta"la& O"viamente
si la ta"la no es multidimensional valdr$ F& Por ejemploA
int[] tabla = {1,2,3,4};
int[][] tabla2 = {new int[] {1,2}, new int[] {3,4,5}};
int[,] tabla3 = {{1,2},{3,4,5,6}};

Console.WriteLine(tabla.Rank); //Imprime 1
Console.WriteLine(tabla2.Rank); //Imprime 1
Console.WriteLine(tabla3.Rank); //Imprime 2
int #et:ength;int dimensi!n<A M,todo @ue devuelve el nCmero de elementos de la dimensin
especi!icada& #as dimensiones se indican empe/ando a contar desde ceroB por lo @ue si @uiere
o"tenerse el nCmero de elementos de la primera dimensin (a"r$ @ue usar ;et#engt(=:?B si se
@uiere o"tener los de la segunda (a"r$ @ue usar ;et#engt(=F?B etc& Por ejemploA
int[,] tabla = {{1,2}, {3,4,5,6}};
Console.WriteLine(tabla.GetLength(0)); // Imprime 2
Console.WriteLine(tabla.GetLength(1)); // Imprime 4
void Co"(To;Frra( destinoU int "osici!n<A Copia todos los elementos de la ta"la so"re la @ue
se aplica en la ta"la destino a partir de la "osici!n de ,sta indicada& Por ejemploA
int[] tabla1 = {1,2,3,4};
int[] tabla2 = {5,6,7,8, 9};
tabla1.CopyTo(tabla2,0);
// A partir de ahora, tabla2 contendr {5,1,2,3,4}
-m"as ta"las de"en ser unidimensionalesB la ta"la de destino (ade ser de un tipo @ue pueda
almacenar los o"jetos de la ta"la origenB el ndice especi!icado (a de ser v$lido =mayor o igual @ue cero
y menor @ue el tama7o de la ta"la de destino? y no (a de valer null ninguna de las ta"las& Si no !uese
asB saltaran e*cepciones de diversos tipos in!ormando del error cometido =en la documentacin del
S)] puede ver cu$les son en concreto?
-parte de los miem"ros a@u se7aladosB S(stem.Frra( tam"i,n cuenta con muc(os otros @ue
!acilitan reali/ar tareas tan !recuentes como "Cs@uedas de elementosB ordenacionesB etc& Para m$s
in!ormacin so"re ellos puede consultarse la documentacin del S)]&
Cadenas de te)to
1na cadena de te)to no es m$s @ue una secuencia de caracteres& &8%. las representa internamente
en !ormato 1nicodeB y C# las representan e*ternamente como o"jetos de un tipo de dato stringB @ue no
es m$s @ue un alias del tipo S(stem.String de la 0C#&
#as cadenas de te*to suelen crearse a partir literales de cadena o de otras cadenas previamente
creadas& %jemplos de am"os casos se muestran a continuacinA
string cadena1 = "Jos Antonio";
string cadena2 = cadena1;
%n el primer caso se (a creado un o"jeto string @ue representa a la cadena !ormada por la secuencia
de caracteres Eos, -ntonio indicada literalmente =ntese @ue las comillas do"les entre las @ue se
encierran los literales de cadena no !orman parte del contenido de la cadena @ue representan sino @ue
slo se usan como delimitadores de la misma? %n el segundo caso la varia"le cadena9 creada se genera
a partir de la varia"le cadenaF ya e*istenteB por lo @ue am"as varia"les apuntar$n al mismo o"jeto en
memoria&
Hay @ue tener en cuenta @ue el tipo string es un tipo re!erenciaB por lo @ue en principio la
comparacin entre o"jetos de este tipo de"era comparar sus direcciones de memoria como pasa con
cual@uier tipo re!erencia& Sin em"argoB si ejecutamos el siguiente cdigo veremos @ue esto no ocurre en
el caso de las cadenasA
using System;
public class IgualdadCadenas
{
public static void Main()
{
string cadena1 = "Jos Antonio";
string cadena2 = String.Copy(cadena1);
Console.WriteLine(cadena1==cadena2);
}
}
%l m,todo Co"(;< de la clase String usado devuelve una copia del o"jeto @ue se le pasa como
par$metro& Por tantoB al ser o"jetos di!erentes se almacenar$n en posiciones distintas de memoria y al
compararlos de"era devolverse false como pasa con cual@uier tipo re!erencia& Sin em"argoB si ejecuta
el programa ver$ @ue lo @ue se o"tiene es precisamente lo contrarioA true& %sto se de"e a @ue para (acer
para (acer m$s intuitivo el tra"ajo con cadenasB en C# se (a modi!icado el operador de igualdad para
@ue cuando se apli@ue entre cadenas se considere @ue sus operandos son iguales slo si son
le*icogr$!icamente e@uivalentes y no si re!erencian al mismo o"jeto en memoria& -dem$sB esta
comparacin se (ace teniendo en cuenta la capitali/acin usadaB por lo @ue KHolaLMMLHO#-L
KHolaLMML(olaL devolver$n false ya @ue contienen las mismas letras pero con distinta capitali/acin&
Si se @uisiese comparar cadenas por re!erencia (a"ra @ue optar por una de estas dos opcionesA
compararlas con bject.CeferenceESuals;< o convertirlas en objects y luego compararlas con && Por
ejemploA
Console.WriteLine(Object.ReferecenceEquals(cadena1, cadena2));
Console.WriteLine( (object) cadena1 == (object) cadena2);
-(ora s @ue lo @ue se comparan son las direcciones de los o"jetos @ue representan a las cadenas en
memoriaB por lo @ue la salida @ue se mostrar$ por pantalla esA
alse
alse
Hay @ue se7alar una cosaB y es @ue aun@ue en principio el siguiente cdigo de"era mostrar la misma
salida por pantalla @ue el anterior ya @ue las cadenas comparadas se de"eran corresponder a o"jetos
@ue aun@ue sean le*icogr$!icamente e@uivalentes se almacenan en posiciones di!erentes en memoriaA
using System;
public class IgualdadCadenas2
{
public static void Main()
{
string cadena1 = "Jos Antonio";
string cadena2 = "Jos Antonio";
Console.WriteLine(Object.ReferenceEquals(cadena1, cadena2));
Console.WriteLine( ((object) cadena1) == ((object) cadena2));
}
}
Si lo ejecutamos veremos @ue la salida o"tenida es justamente la contrariaA
.rue
.rue
%sto se de"e a @ue el compilador (a detectado @ue am"os literales de cadena son le*icogr$!icamente
e@uivalentes y (a decidido @ue para a(orra memoria lo mejor es almacenar en memoria una Cnica copia
de la cadena @ue representan y (acer @ue am"as varia"les apunten a esa copia comCn& %sto va a a!ectar
a la !orma en @ue es posi"le manipular las cadenas como se e*plicar$ m$s adelante&
-l igual @ue el signi!icado del operador && (a sido especialmente modi!icado para tra"ajar con
cadenasB lo mismo ocurre con el operador "inario *& %n este casoB cuando se aplica entre dos cadenas o
una cadena y un car$cter lo @ue (ace es devolver una nueva cadena con el resultado de concatenar sus
operandos& -s por ejemploB en el siguiente cdigo las dos varia"les creadas almacenar$n la cadena
Hola MundoA
public class Concatenacin
{
public static void Main()
{
string cadena = "Hola" + " Mundo";
string cadena2 = "Hola Mund" + 'o';
}
}
Por otro ladoB el acceso a las cadenas se (ace de manera similar a como si de ta"las de caracteres se
trataseA su KcampoL :ength almacenar$ el nCmero de caracteres @ue la !orman y para acceder a sus
elementos se utili/a el operador -.& Por ejemploB el siguiente cdigo muestra por pantalla cada car$cter
de la cadena Hola en una lnea di!erenteA
using System;
public class AccesoCadenas
{
public static void Main()
{
string cadena = "Hola";
Console.WriteLine(cadena[0]);
Console.WriteLine(cadena[1]);
Console.WriteLine(cadena[2]);
Console.WriteLine(cadena[3]);
}
}
Sin em"argoB (ay @ue se7alar una di!erencia importante respecto a la !orma en @ue se accede a las
ta"lasA las cadenas son inmuta"lesB lo @ue signi!ica @ue no es posi"le modi!icar los caracteres @ue las
!orman& %sto se de"e a @ue el compilador comparte en memoria las re!erencias a literales de cadena
le*icogr$!icamente e@uivalentes para as a(orrar memoriaB y si se permitiese modi!icarlos los cam"ios
@ue se (iciesen a trav,s de una varia"le a una cadena compartida a!ectaran al resto de varia"les @ue la
compartanB lo @ue podra causar errores di!ciles de detectar& Por tantoB (acer esto es incorrectoA
string cadena = "Hola";
cadena[0]="A"; //Error: No se pueden modificar las cadenas
Sin em"argoB el (ec(o de @ue no se puedan modi!icar las cadenas no signi!ica @ue no se puedan
cam"iar los o"jetos almacenados en las varia"les de tipo string&Por ejemploB el siguiente cdigo es
v$lidoA

&tring cad = "Hola";
cad = "Adios";
// Correcto, pues no se modifica la cadena almacenada en cad
// sino que se hace que cad pase a almacenar otra cadena distinta..
Si se desea tra"ajar con cadenas modi!ica"les puede usarse S(tem.Te)t.String=uilderB @ue !unciona
de manera similar a string pero permite la modi!icacin de sus cadenas en tanto @ue estas no se
comparten en memoria& Para crear o"jetos de este tipo "asta pasar como par$metro de su constructor el
o"jeto string @ue contiene la cadena a representar mediante un String=uilderB y para convertir un
String=uilder en String siempre puede usarse su m,todo ToString;< (eredado de S(stem.bject& Por
ejemploA
using System.Text;
using System;
public class ModificacinCadenas
{
public static void Main()
{
StringBuilder cadena = new StringBuilder("Pelas");
String cadenaInmutable;
cadena[0] = 'V';
Console.WriteLine(cadena); // Muestra Velas
cadenaInmutable = cadena.ToString();
Console.WriteLine(cadenaInmutable); // Muestra Velas
}
}
-parte de los m,todos ya vistosB en la clase S(stem.String se de!inen muc(os otros m,todos
aplica"les a cual@uier cadena y @ue permiten manipularla& #os principales sonA
int Inde)f;string subcadena<A Indica cu$l es el ndice de la primera aparicin de la
su"cadena indicada dentro de la cadena so"re la @ue se aplica& #a "Cs@ueda de dic(a su"cadena
se reali/a desde el principio de la cadenaB pero es posi"le indicar en un segundo par$metro
opcional de tipo int cu$l es el ndice de la misma a partir del @ue se desea empe/ar a "uscar&
)el mismo modoB la "Cs@ueda aca"a al llegar al !inal de la cadena so"re la @ue se "uscaB pero
pasando un tercer par$metro opcional de tipo int es posi"le indicar algCn ndice anterior donde
terminarla&
8tese @ue es un m,todo muy Ctil para sa"er si una cadena contiene o no alguna su"cadena
determinadaB pues slo si no la encuentra devuelve un M2&
int :astInde)f;string subcadena<A unciona de !orma similar a Inde)f;< slo @ue
devuelve la posicin de la Cltima aparicin de la su"cadena "uscada en lugar de devolver la de
la primera&
string Insert;int "osici!nU string subcadena<A )evuelve la cadena resultante de insertar la
su"cadena indicada en la posicin especi!icada de la cadena so"re la @ue se aplica&
string Cemove;int "osici!nU int nWmero<A )evuelve la cadena resultante de eliminar el
nCmero de caracteres indicado @ue (u"iese en la cadena so"re al @ue se aplica a partir de la
posicin especi!icada&
string Ce"lace;string aSustituirU string sustituta<A )evuelve la cadena resultante de sustituir
en la cadena so"re la @ue se aplica toda aparicin de la cadena aSustituir indicada por la cadena
sustituta especi!icada como segundo par$metro&
string Substring;int "osici!nU int nWmero<A )evuelve la su"cadena de la cadena so"re la @ue
se aplica @ue comien/a en la posicin indicada y tiene el nCmero de caracteres especi!icados& Si
no se indica dic(o nCmero se devuelve la su"cadena @ue va desde la posicin indicada (asta el
!inal de la cadena&
string ToJ""er;< y string To:o%er;<A )evuelvenB respectivamenteB la cadena @ue resulte de
convertir a mayCsculas o minCsculas la cadena so"re la @ue se aplican&
%s preciso incidir en @ue aun@ue (ayan m,todos de insercinB reempla/o o eliminacin de caracteres
@ue puedan dar la sensacin de @ue es posi"le modi!icar el contenido de una cadenaB en realidad las
cadenas son inmuta"les y dic(o m,todos lo @ue (acen es devolver una nueva cadena con el contenido
correspondiente a (a"er e!ectuado las operaciones de modi!icacin solicitadas so"re la cadena a la @ue
se aplican& Por elloB las cadenas so"re las @ue se aplican @uedan intactas como muestra el siguiente
ejemploA
using System;
public class EjemploInmutabilidad
{
public static void Main()
{
string cadena1="Hola";
string cadena2=cadena1.Remove(0,1);
Console.WriteLine(cadena1);
Console.WriteLine(cadena2);
}
}
#a salida por pantalla de este ejemplo demuestra lo antes dic(oB pues esA
Hola
ola
Como se veB tras el Cemove;< la cadenaF permanece intacta y el contenido de cadena9 es el @ue
de"era tener cadenaF si se le (u"iese eliminado su primer car$cter&
Constantes
1na constante es una varia"le cuyo valor puede determinar el compilador durante la compilacin y
puede aplicar optimi/aciones derivadas de ello& Para @ue esto sea posi"le se (a de cumplir @ue el valor
de una constante no pueda cam"iar durante la ejecucinB por lo @ue el compilador in!ormar$ con un
error de todo intento de modi!icar el valor inicial de una constante& #as constantes se de!inen como
varia"les normales pero precediendo el nom"re de su tipo del modi!icador const y d$ndoles siempre un
valor inicial al declararlas& O seaB con esta sinta*isA
const <tipoConstante> <nombreConstante> = <valor>;
-sB ejemplos de de!inicin de constantes es el siguienteA
const int a = 123;
const int b = a + 125;
)adas estas de!iniciones de constantesB lo @ue (ar$ el compilador ser$ sustituir en el cdigo
generado todas las re!erencias a las constantes a y " por los valores F9O y 9XG respectivamenteB por lo
@ue el cdigo generado ser$ m$s e!iciente ya @ue no incluir$ el acceso y c$lculo de los valores de a y "&
8tese @ue puede (acer esto por@ue en el cdigo se indica e*plcitamente cual es el valor @ue siempre
tendr$ a yB al ser este un valor !ijoB puede deducir cu$l ser$ el valor @ue siempre tendr$ "& Para @ue el
compilador pueda (acer estos c$lculos se (a de cumplir @ue el valor @ue se asigne a las constantes en
su declaracin sea una e*presin constante& Por ejemploB el siguiente cdigo no es v$lido en tanto @ue
el valor de * no es constanteA
// x es una variable normal, no una constante
int x = 123;
// Error: x no tiene porqu tener valor constante (aunque aqu lo tenga)
const int y = x +123;
)e"ido a la necesidad de @ue el valor dado a una constante sea precisamente constanteB no tiene
muc(o sentido crear constantes de tipos de datos no "$sicosB pues a no ser @ue valgan null sus valores
no se pueden determinar durante la compilacin sino Cnicamente tras la ejecucin de su constructor& #a
Cnica e*cepcin a esta regla son los tipos enumeradosB cuyos valores se pueden determinar al compilar
como se e*plicar$ cuando los veamos en el Tema &*: E#$mera%io#es
.odas las constantes son implcitamente est$ticasB por lo se considera errneo incluir el modi!icador
static en su de!inicin al no tener sentido (acerlo& )e (ec(oB para leer su valor desde cdigos e*ternos
a la de!inicin de la clase donde est, de!inida la constanteB (a"r$ @ue usar la sinta*is
jnom"reClase6&jnom"reConstante6 tpica de los campos static&
Por CltimoB (ay @ue tener en cuenta @ue una varia"le slo puede ser de!inida como constante si es
una varia"le local o un campoB pero no si es un par$metro&
)ariables de s%lo lectura
)ado @ue (ay ciertos casos en los @ue resulta interesante disponer de la capacidad de slo lectura
@ue tienen las constantes pero no es posi"le usarlas de"ido a las restricciones @ue (ay impuestas so"re
su usoB en C# tam"i,n se da la posi"ilidad de de!inir varia"les @ue slo puedan ser ledas& Para ello se
usa la siguiente sinta*isA
readonly <tipoConstante> <nombreConstante> = <valor>;
%stas varia"les superan la mayora de las limitaciones de las constantes& Por ejemploA
8o es o"ligatorio darles un valor al de!inirlasB sino @ue puede d$rseles en el constructor& -(ora
"ienB una ve/ dado un valor a una varia"le readonl( ya no es posi"le volverlo a modi!icar& Si
no se le da ningCn valor ni en su constructor ni en su de!inicin tomar$ el valor por de!ecto
correspondiente a su tipo de dato&
8o tienen por@u, almacenar valores constantesB sino @ue el valor @ue almacenen puede
calcularse durante la ejecucin de la aplicacin&
8o tienen por@u, de!inirse como est$ticasB aun@ue si se desea puede (acerse&
Su valor se determina durante la ejecucin de la aplicacinB lo @ue permite la actuali/acin de
cdigos cliente sin necesidad de recompilar& Por ejemploB dadoA
namespace Programa1
{
public class Utilidad
{
public static readonly int X = 1;
}
}
namespace Programa2
{
class Test
{
public static void Main()
{
System.Console.WriteLine(Programa1.Utilidad.X);
}
}
}
%n principioB la ejecucin de este programa producir$ el valor F& Sin em"argoB si cada espacio de
nom"res se compilan en mdulos de cdigo separados @ue luego se enla/an din$micamente y
cam"iamos el valor de PB slo tendremos @ue recompilar el mdulo donde est, de!inido
ProgramaF&1tilidad y Programa9&.est podr$ ejecutarse usando el nuevo valor de P sin necesidad de
recompilarlo&
Sin em"argoB pese a las ventajas @ue las varia"les de slo lectura o!recen respecto a las constantesB
tienen dos inconvenientes respecto a ,stasA slo pueden de!inirse como campos =no como varia"les
locales? y con ellas no es posi"le reali/ar las optimi/aciones de cdigo comentadas para las constantes&
Orden de iniciali*aci%n de variables
Para deducir el orden en @ue se iniciali/ar$n las varia"les de un tipo de dato "asta sa"er cu$l es el
momento en @ue se iniciali/a cada una y cuando se llama a los constructoresA
#os cam"os est$ticos slo se iniciali/an la primera ve/ @ue se accede al tipo al @ue pertenecenB
pero no en sucesivos accesos& %stos accesos pueden ser tanto para crear o"jetos de dic(o tipo
como para acceder a sus miem"ros est$ticos& #a iniciali/acin se (ace de modo @ue en primer
lugar se d, a cada varia"le el valor por de!ecto correspondiente a su tipoB luego se d, a cada una
el valor inicial especi!icado al de!inirlasB y por Cltimo se llame al constructor del tipo& 1n
constructor de tipo es similar a un constructor normal slo @ue en su cdigo Cnicamente puede
accederse a miem"ros static =se ver$ en el Tema 8: Mtodos?
#os cam"os no est$ticos se iniciali/an cada ve/ @ue se crea un o"jeto del tipo de dato al @ue
pertenecen& #a iniciali/acin se (ace del mismo modo @ue en el caso de los campos est$ticosB y
una ve/ terminada se pasa a ejecutar el cdigo del constructor especi!icado al crear el o"jeto& %n
caso de @ue la creacin del o"jeto sea el primer acceso @ue se (aga al tipo de dato del mismoB
entonces primero se iniciali/ar$n los campos est$ticos y luego los no est$ticos&
#os "ar$metros se iniciali/an en cada llamada al m,todo al @ue pertenecen con los valores
especi!icados al llamarlo&
#as variables locales se iniciali/an en cada llamada al m,todo al cual pertenecen pero tras
(a"erse iniciali/ado los par$metros de!inidos para el mismo& Si no se les da valor inicial no
toman ninguno por de!ectoB consider$ndose errneo todo acceso de lectura @ue se (aga a las
mismas mientras no se les escri"a algCn valor&
Hay @ue tener en cuenta @ue al de!inirse campos est$ticos pueden (acerse de!iniciones cclicas en las
@ue el valor de unos campos dependa del de otros y el valor de los segundos dependa del de los
primeros& Por ejemploA
class ReferenciasCruzadas
{
static int a = b + 1;
static int b = a + 1;

public static void Main()
{
System.Console.WriteLine("a = {0}, b = {1}", a, b);
}
}
%sto slo es posi"le (acerlo al de!inir campos est$ticos y no entre campos no est$ticas o varia"les
localesB ya @ue no se puede iniciali/ar campos no est$ticos en !uncin del valor de otros miem"ros no
est$ticos del mismo o"jeto por@ue el o"jeto aCn no estara iniciali/adoB y no se pueden iniciali/ar
varia"les locales en !uncin del valor de otras varia"les locales de!inidas m$s adelante por@ue no se
pueden leer varia"les no iniciali/adas& -dem$sB aun@ue las constantes sean implcitamente est$ticas
tampoco puede (acerse de!iniciones cclicas entre constantes&
%n primer lugarB (ay @ue se7alar @ue escri"ir un cdigo como el del ejemplo anterior no es un "uen
($"ito de programacin ya @ue di!iculta innecesariamente la legi"ilidad del programa& -Cn asB C#
admite este tipo de cdigos y para determinar el valor con @ue se iniciali/ar$n "asta tener en cuenta @ue
siempre se iniciali/an primero todos los campos con sus valores por de!ecto y luego se iniciali/an
a@uellos @ue tengan valores iniciales con dic(os valores iniciales y en el mismo orden en @ue apare/can
en el cdigo !uente& )e este modoB la salida del programa de ejemplo anterior ser$A
a 7 &8 b 7 9
8tese @ue lo @ue se (a (ec(o es iniciali/ar primero a y " con sus valores por de!ecto =: en este
caso?B luego calcular el valor !inal de a y luego calcular el valor !inal de "& Como " vale : cuando se
calcula el valor !inal de aB entonces el valor !inal de a es FJ y como a vale F cuando se calcula el valor
!inal de "B entonces el valor !inal de " es 9&
Concepto de mtodo
1n mKtodo es un conjunto de instrucciones a las @ue se les da un determinado nom"re de tal manera
@ue sea posi"le ejecutarlas en cual@uier momento sin tenerlas @ue rescri"ir sino usando slo su nom"re&
- estas instrucciones se les denomina cuer"o del m,todoB y a su ejecucin a trav,s de su nom"re se le
denomina llamada al m,todo&
#a ejecucin de las instrucciones de un m,todo puede producir como resultado un o"jeto de
cual@uier tipo& - este o"jeto se le llama valor de retorno del m,todo y es completamente opcionalB
pudi,ndose escri"ir m,todos @ue no devuelvan ninguno&
#a ejecucin de las instrucciones de un m,todo puede depender del valor de unas varia"les
especiales denominadas "ar$metros del m,todoB de manera @ue en !uncin del valor @ue se d, a estas
varia"les en cada llamada la ejecucin del m,todo se pueda reali/ar de una u otra !orma y podr$
producir uno u otro valor de retorno&
-l conjunto !ormado por el nom"re de un m,todo y el nCmero y tipo de sus par$metros se le conoce
como signatura del m,todo& #a signatura de un m,todo es lo @ue verdaderamente lo identi!icaB de
modo @ue es posi"le de!inir en un mismo tipo varios m,todos con id,ntico nom"re siempre y cuando
tengan distintos par$metros& Cuando esto ocurre se dice @ue el m,todo @ue tiene ese nom"re est$
sobrecargado&
'efinici%n de mtodos
Para de!inir un m,todo (ay @ue indicar tanto cu$les son las instrucciones @ue !orman su cuerpo como
cu$l es el nom"re @ue se le dar$B cu$l es el tipo de o"jeto @ue puede devolver y cu$les son los
par$metros @ue puede tomar& %sto se indica de!ini,ndolo asA
<tipoRetorno> <nombreMtodo>(<parmetros>)
{
<cuerpo>
}
%n jtipo+etorno6 se indica cu$l es el tipo de dato del o"jeto @ue el m,todo devuelveB y si no
devuelve ninguno se (a de escri"ir void en su lugar&
Como nom"re del m,todo se puede poner en jnom"reM,todo6 cual@uier identi!icador v$lido& Como
se ver$ m$s adelante en el Tema &5: "#ter3a%esB tam"i,n es posi"le incluir en jnom"reM,todo6
in!ormacin de e*plicitacin de implementacin de inter!a/B pero por a(ora podemos considerar @ue
siempre ser$ un identi!icador&
-un@ue es posi"le escri"ir m,todos @ue no tomen par$metrosB si un m,todo los toma se (a de indicar
en +!ar2metros, cu$l es el nom"re y tipo de cada unoB separ$ndolos con comas si son m$s de uno y
siguiendo la sinta*is @ue m$s adelante se e*plica&
%l +%$er!o, del m,todo tam"i,n es opcionalB pero si el m,todo retorna algCn tipo de o"jeto
entonces (a de incluir al menos una instruccin return @ue indi@ue cu$l o"jeto&
#a sinta*is anteriormente vista no es la @ue se usa para de!inir mKtodos abstractos& Como ya se vio
en el Tema 5: ClasesB en esos casos lo @ue se (ace es sustituir el cuerpo del m,todo y las llaves @ue lo
encierran por un simple punto y coma =T? M$s adelante en este tema veremos @ue eso es tam"i,n lo @ue
se (ace para de!inir mKtodos e)ternos&
- continuacin se muestra un ejemplo de cmo de!inir un m,todo de nom"re Saluda cuyo cuerpo
consista en escri"ir en la consola el mensaje KHola MundoL y @ue devuelva un o"jeto int de valor FA
int Saluda()
{
Console.WriteLine("Hola Mundo");
return 1;
}
Llamada a mtodos
#a !orma en @ue se puede llamar a un m,todo depende del tipo de m,todo del @ue se trate& Si es un
mKtodo de objeto =m,todo no est$tico? se (a de usar la notacinA
<objeto>.<nombreMtodo>(<valoresParmetros>)
%l jo"jeto6 indicado puede ser directamente una varia"le del tipo de datos al @ue pertene/ca el
m,todo o puede ser una e*presin @ue produ/ca como resultado una varia"le de ese tipo =recordemos
@ueB de"ido a la (erenciaB el tipo del jo"jeto6 puede ser un su"tipo del tipo donde realmente se (aya
de!inido el m,todo?J pero si desde cdigo de algCn m,todo de un o"jeto se desea llamar a otro m,todo
de ese mismo o"jetoB entonces se (a de dar el valor this a jo"jeto6&
%n caso de @ue sea un mKtodo de ti"o =m,todo est$tico?B entones se (a de usarA
<tipo>.<nombreMtodo>(<valoresParmetros>)
-(ora en jtipo6 (a de indicarse el tipo donde se (aya de!inido el m,todo o algCn su"tipo suyo& Sin
em"argoB si el m,todo pertenece al mismo tipo @ue el cdigo @ue lo llama entonces se puede usar la
notacin a"reviadaA
<nombreMtodo>(<valoresParmetros>)
%l !ormato en @ue se pasen los valores a cada par$metro en jvaloresPar$metros6 a a@uellos m,todos
@ue tomen par$metros depende del tipo de par$metro @ue sea& %sto se e*plica en el siguiente apartado&
(ipos de parmetros$ #inta+is de definici%n
#a !orma en @ue se de!ine cada par$metro de un m,todo depende del tipo de par$metro del @ue se
trate& %n C# se admiten cuatro tipos de par$metrosA par$metros de entradaB par$metros de salidaB
par$metros por re!erencia y par$metros de nCmero inde!inido&
Parmetros de entrada
1n "ar$metro de entrada reci"e una copia del valor @ue almacenara una varia"le del tipo del
o"jeto @ue se le pase& Por tantoB si el o"jeto es de un tipo valor se le pasar$ una copia del o"jeto y
cual@uier modi!icacin @ue se (aga al par$metro dentro del cuerpo del m,todo no a!ectar$ al o"jeto
original sino a su copiaJ mientras @ue si el o"jeto es de un tipo re!erencia entonces se le pasar$ una
copia de la re!erencia al mismo y cual@uier modi!icacin @ue se (aga al par$metro dentro del m,todo
tam"i,n a!ectar$ al o"jeto original ya @ue en realidad el par$metro re!erencia a ese mismo o"jeto
original&
Para de!inir un par$metro de entrada "asta indicar cu$l el nom"re @ue se le desea dar y el cu$l es tipo
de dato @ue podr$ almacenar& Para ello se sigue la siguiente sinta*isA
<tipoParmetro> <nombreParmetro>
Por ejemploB el siguiente cdigo de!ine un m,todo llamado Suma @ue toma dos par$metros de
entrada de tipo int llamados parF y par9 y devuelve un int con su sumaA
int Suma(int par1, int par2)
{
return par1+par2;
}
Como se veB se usa la instruccin return para indicar cu$l es el valor @ue (a de devolver el m,todo&
%ste valor es el resultado de ejecutar la e*presin parFDpar9J es decirB es la suma de los valores pasados
a sus par$metros parF y par9 al llamarlo&
%n las llamadas a m,todos se e*presan los valores @ue se deseen dar a este tipo de par$metros
indicando simplemente el valor deseado& Por ejemploB para llamar al m,todo anterior con los valores 9
y V se (ara jo"jeto6&Suma=9BV?B lo @ue devolvera el valor Y&
.odo esto se resume con el siguiente ejemploA
using System;
class ParmetrosEntrada
{
public int a = 1;
public static void F(ParametrosEntrada p)
{
p.a++;
}
public static void G(int p)
{
p++;
}
public static void Main()
{
int obj1 = 0;
ParmetrosEntrada obj2 = new ParmetrosEntrada();
G(obj1);
F(obj2);
Console.WriteLine("{0}, {1}", obj1, obj2.a);
}
}
%ste programa muestra la siguiente salida por pantallaA
:B 9
Como se veB la llamada al m,todo ;=? no modi!ica el valor @ue tena o"jF antes de llamarlo ya @ue
o"jF es de un tipo valor =int? Sin em"argoB como o"j9 es de un tipo re!erencia =Par$metros#lamadas?
los cam"ios @ue se le (acen dentro de =? al pas$rselo como par$metro s @ue le a!ectan&
Par$metros de salida
1n "ar$metro de salida se di!erencia de uno de entrada en @ue todo cam"io @ue se le realice en el
cdigo del m,todo al @ue pertenece a!ectar$ al o"jeto @ue se le pase al llamar dic(o m,todo tanto si
,ste es de un tipo por valor como si es de un tipo re!erencia& %sto se de"e a @ue lo @ue a estos
par$metros se les pasa es siempre una re!erencia al valor @ue almacenara una varia"le del tipo del
o"jeto @ue se les pase&
Cual@uier par$metro de salida de un m,todo siempre (a de modi!icarse dentro del cuerpo del m,todo
y adem$s dic(a modi!icacin (a de (acerse antes @ue cual@uier lectura de su valor& Si esto no se (iciese
as el compilador lo detectara e in!ormara de ello con un error& Por esta ra/n es posi"le pasar
par$metros de salida @ue sean varia"les no iniciali/adasB pues se garanti/a @ue en el m,todo se
iniciali/ar$n antes de leerlas& -dem$sB tras la llamada a un m,todo se considera @ue las varia"les @ue se
le pasaron como par$metros de salida ya estar$n iniciali/adasB pues dentro del m,todo seguro @ue se las
iniciali/a&
8tese @ue este tipo de par$metros permiten dise7ar m,todos @ue devuelvan mCltiples o"jetosA un
o"jeto se devolvera como valor de retorno y los dem$s se devolveran escri"i,ndolos en los par$metros
de salida&
#os par$metros de salida se de!inen de !orma parecida a los par$metros de entrada pero se les (a de
a7adir la pala"ra reservada out& O seaB se de!inen asA
out <tipoParmetro> <nombreParmetro>
-l llamar a un m,todo @ue tome par$metros de este tipo tam"i,n se (a preceder el valor especi!icado
para estos par$metros del modi!icador out& 1na utilidad de esto es !acilitar la legi"ilidad de las
llamadas a m,todos& Por ejemploB dada una llamada de la !ormaA
a.f(x, out z)
%s !$cil determinar @ue lo @ue se (ace es llamar al m,todo !=? del o"jeto a pas$ndole * como
par$metro de entrada y / como par$metro de salida& -dem$sB tam"i,n se puede deducir @ue el valor de
/ cam"iar$ tras la llamada&
Sin em"argoB la verdadera utilidad de !or/ar a e*plicitar en las llamadas el tipo de paso de cada
par$metro es @ue permite evitar errores derivados de @ue un programador pase una varia"le a un
m,todo y no sepa @ue el m,todo la puede modi!icar& .eni,ndola @ue e*plicitar se asegura @ue el
programador sea consciente de lo @ue (ace&
Parmetros por re"erencia
1n "ar$metro "or referencia es similar a un par$metro de salida slo @ue no es o"ligatorio
modi!icarlo dentro del m,todo al @ue perteneceB por lo @ue ser$ o"ligatorio pasarle una varia"le
iniciali/ada ya @ue no se garanti/a su iniciali/acin en el m,todo&
#os par$metros por re!erencia se de!inen igual @ue los par$metros de salida pero sustituyendo el
modi!icador out por el modi!icador ref& )el mismo modoB al pasar valores a par$metros por re!erencia
tam"i,n (ay @ue precederlos del ref&
Parmetros de n/mero inde"inido
C# permite dise7ar m,todos @ue puedan tomar cual@uier nCmero de par$metros& Para ello (ay @ue
indicar como Cltimo par$metro del m,todo un par$metro de algCn tipo de ta"la unidimensional o
dentada precedido de la pala"ra reservada "arams& Por ejemploA
static void F(int x, params object[] extras)
{}

.odos los par$metros de nCmero inde!inido @ue se pasan al m,todo al llamarlo (an de ser del mismo
tipo @ue la ta"la& 8tese @ue en el ejemplo ese tipo es la clase primigenia objectB con lo @ue se
consigue @ue gracias al polimor!ismo el m,todo pueda tomar cual@uier nCmero de par$metros de
cual@uier tipo& %jemplos de llamadas v$lidas seranA
F(4);// Pueden pasarse 0 parmetros indefinidos
F(3,2);
F(1, 2, "Hola", 3.0, new Persona());
F(1, new object[] {2,"Hola", 3.0, new Persona});
%l primer ejemplo demuestra @ue el nCmero de par$metros inde!inidos @ue se pasen tam"i,n puede
ser :& Por su parteB los dos Cltimos ejemplos son totalmente e@uivalentesB pues precisamente la utilidad
de pala"ra reservada "arams es indicar @ue se desea @ue la creacin de la ta"la object-. se (aga
implcitamente&
%s importante se7alar @ue la prioridad de un m,todo @ue incluya el "arams es in!erior a la de
cual@uier otra so"recarga del mismo& %s decirB si se (u"iese de!inido una so"recarga del m,todo
anterior como la siguienteA
static void F(int x, int y)
{}
Cuando se (iciese una llamada como =OB9? se llamara a esta Cltima versin del m,todoB ya @ue
aun@ue la del "arams es tam"i,n aplica"leB se considera @ue es menos prioritaria&
Sobrecar$a de tipos de parmetros
%n realidad los modi!icadores ref y out de los par$metros de un m,todo tam"i,n !orman parte de lo
@ue se conoce como signatura del m,todoB por lo @ue esta clase es v$lidaA
class Sobrecarga
{
public void f(int x)
{}
public void f(out int x)
{}
}
8tese @ue esta clase es correcta por@ue cada uno de sus m,todos tiene una signatura distintaA el
par$metro es de entrada en el primero y de salida en el segundo&
Sin em"argoB (ay una restriccinA no puede ocurrir @ue la Cnica di!erencia entre la signatura de dos
m,todos sea @ue en uno un determinado par$metro lleve el modi!icador ref y en el otro lleve el
modi!icador out& Por ejemploB no es v$lidoA
class SobrecargaInvlida
{
public void f(ref int x)
{}
public void f(out int x)
{}
}

&todos e+ternos
1n mKtodo e)terno es a@u,l cuya implementacin no se da en el !ic(ero !uente en @ue es declarado&
%stos m,todos se declaran precediendo su declaracin del modi!icador e)tern& Como su cdigo se da
e*ternamenteB en el !uente se sustituyen las llaves donde de"era escri"irse su cuerpo por un punto y
coma =T?B @uedando una sinta*is de la !ormaA
extern <nombreMtodo>(<parmetros>);

#a !orma en @ue se asocie el cdigo e*terno al m,todo no est$ de!inida en la especi!icacin de C#
sino @ue depende de la implementacin @ue se (aga del lenguaje& %l Cnico re@uisito es @ue no pueda
de!inirse un m,todo como a"stracto y e*terno a la ve/B pero por todo lo dem$s puede com"inarse con
los dem$s modi!icadoresB incluso pudi,ndose de!inir m,todos virtuales e*ternos&
#a !orma m$s (a"itual de asociar cdigo e*terno consiste en preceder la declaracin del m,todo de
un atributo de tipo S(stem.Cuntime.Intero"Services.EllIm"ort @ue indi@ue en cu$l li"rera de
enlace din$mico =)##? se (a implementado& %ste atri"uto re@uiere @ue el m,todo e*terno @ue le siga
sea est$ticoB y un ejemplo de su uso esA
using System.Runtime.InteropServices; // Aqu est definido DllImport

public class Externo
{
[2ll'mport(3kernel-*3)]
public static extern void CopyFile(string fuente, string destino);

public static void Main()
{
CopyFile("fuente.dat", "destino.dat");
}
}
%l concepto de atri"uto se e*plica detalladamente en el Tema &*:0trib$tos& Por a(ora "asta sa"er @ue
los atri"utos se usan de !orman similar a los m,todos slo @ue no est$n asociados a ningCn o"jeto ni
tipo y se indican entre corc(etes =-.? antes de declaraciones de elementos del lenguaje& %n el caso
concreto de EllIm"ort lo @ue indica el par$metro @ue se le pasa es cu$l es el !ic(ero =por de!ecto se
considera @ue su e*tensin es .dll? donde se encuentra la implementacin del m,todo e*terno a
continuacin de!inido&
#o @ue el cdigo del ejemplo anterior (ace es simplemente de!inir un m,todo de nom"re Copyile=?
cuyo cdigo se corresponda con el de la !uncin Co"(Dile;< del !ic(ero 2ernelO9&dll del F1I 9in53&
%ste m,todo es llamado en Main=? para copiar el !ic(ero de nom"re !uente&dat en otro de nom"re
destino&dat& 8tese @ue dado @ue Copyile=? se (a declarado como static y se le llama desde la misma
clase donde se (a declaradoB no es necesario precederlo de la notacin jnom"reClase6. para llamarlo&
Como se veB la utilidad principal de los m,todos e*ternos es permitir (acer llamadas a c!digo
nativo desde cdigo gestionadoB lo @ue puede ser Ctil por ra/ones de e!iciencia o para reutili/ar cdigo
antiguamente escrito pero reduce la porta"ilidad de la aplicacin&
Constructores
Concepto de constructores
#os constructores de un tipo de datos son m,todos especiales @ue se de!inen como miem"ros de
,ste y @ue contienen cdigo a ejecutar cada ve/ @ue se cree un o"jeto de ese tipo& [ste cdigo suele
usarse para la"ores de iniciali/acin de los campos del o"jeto a crearB so"re todo cuando el valor de
,stos no es constante o incluye acciones m$s all$ de una asignacin de valor =aperturas de !ic(erosB
accesos a redesB etc&?
Hay @ue tener en cuenta @ue la ejecucin del constructor siempre se reali/a despu,s de (a"erse
iniciali/ado todos los campos del o"jetoB ya sea con los valores iniciales @ue se (u"iesen especi!icado
en su de!inicin o dej$ndolos con el valor por de!ecto de su tipo&
-parte de su especial sinta*is de de!inicinB los constructores y los m,todos normales tienen una
di!erencia muy importanteA los constructores no se heredan&
!e"inicin de constructores
#a sinta*is "$sica de de!inicin de constructores consiste en de!inirlos como cual@uier otro m,todo
pero d$ndoles el mismo nom"re @ue el tipo de dato al @ue pertenecen y no indicando el tipo de valor de
retorno de"ido a @ue nunca pueden devolver nada& %s decirB se usa la sinta*isA
<modificadores> <nombreTipo>(<parmetros>)
{
<cdigo>
}
1n constructor nunca puede devolver ningCn tipo de o"jeto por@ueB como ya se (a vistoB slo se usa
junto al operador ne%B @ue devuelve una re!erencia al o"jeto reci,n creado& Por elloB es a"surdo @ue
devuelva algCn valor ya @ue nunca podra ser capturado en tanto @ue ne% nunca lo devolvera& Por esta
ra/n el compilador considera errneo indicar algCn tipo de retorno en su de!inicinB incluso aun@ue se
indi@ue void&
%lamada al constructor
-l constructor de una clase se le llama en el momento en @ue se crea algCn o"jeto de la misma
usando el operador ne%& )e (ec(oB la !orma de uso de este operador esA
new <llamadaConstructor>
Por ejemploB el siguiente programa demuestra cmo al crearse un o"jeto se ejecutan las instrucciones
de su constructorA
class Prueba
{
Prueba(int x)
{
System.Console.Write("Creado objeto Prueba con x={0}",x);
}
public static void Main()
{
Prueba p = new Prueba(5);
}
}
#a salida por pantalla de este programa demuestra @ue se (a llamado al constructor del o"jeto de
clase Prue"a creado en Main=?B pues esA
Creado o"jeto Prue"a con *MVJ

#lamadas entre constructores
-l igual @ue ocurre con cual@uier otro m,todoB tam"i,n es posi"le so"recargar los constructores& %s
decirB se pueden de!inir varios constructores siempre y cuando ,stos tomen di!erentes nCmeros o tipos
de par$metros& -dem$sB desde el cdigo de un constructor puede llamarse a otros constructores del
mismo tipo de dato antes de ejecutar las instrucciones del cuerpo del primero& Para ello se a7ade un
inicializador this al constructorB @ue es estructura @ue precede a la llave de apertura de su cuerpo tal y
como se muestra en el siguiente ejemploA
class A
{
int total;

A(int valor): this(valor, 2); // (1)
{
}

A(int valor, int peso) // (2)
{
total = valor*peso;
}
}
%l this incluido (ace @ue la llamada al constructor =F? de la clase - provo@ue una llamada al
constructor =9? de esa misma clase en la @ue se le pase como primer par$metro el valor originalmente
pasado al constructor =F? y como segundo par$metro el valor 9& %s importante se7alar @ue la llamada al
constructor =9? en =F? se (ace antes de ejecutar cual@uier instruccin de =F?
8tese @ue la so"recarga de constructores 5y de cual@uier m,todo en general5 es un "uen modo de
de!inir versiones m$s compactas de m,todos de uso !recuente en las @ue se tomen valores por de!ecto
para par$metros de otras versiones menos compactas del mismo m,todo& #a implementacin de estas
versiones compactas consistira en (acer una llamada a la versin menos compacta del m,todo en la
@ue se le pasen esos valores por de!ecto =a trav,s del this en el caso de los constructores? y si acaso
luego =yIo antesB si no es un constructor? se (agan la"ores espec!icas en el cuerpo del m,todo
compacto&
)el mismo modo @ue en la de!inicin de un constructor de un tipo de datos es posi"le llamar a otros
constructores del mismo tipo de datosB tam"i,n es posi"le (acer llamadas a constructores de su tipo
padre sustituyendo en su iniciali/ador la pala"ra reservada this por base& Por ejemploA
class A
{
int total;

A(int valor, int peso)
{
total = valor*peso;
}
}
class B:A
{
B(int valor):base(valor,2)
{}
}
%n am"os casosB los valores pasados como par$metros en el iniciali/ador no pueden contener
re!erencias a campos del o"jeto @ue se est, creandoB ya @ue se considera @ue un o"jeto no est$ creado
(asta @ue no se ejecute su constructor yB por tantoB al llamar al iniciali/ador aCn no est$ creado& Sin
em"argoB lo @ue s pueden incluir son re!erencias a los par$metros con los @ue se llam al constructor&
Por ejemploB sera v$lido (acerA
A(int x, int y): this(x+y)
{}
Constructor por de!ecto
.odo tipo de datos (a de disponer de al menos un constructor& Cuando se de!ine un tipo sin
especi!icar ninguno el compilador considera @ue implcitamente se (a de!inido uno sin cuerpo ni
par$metros de la siguiente !ormaA
public <nombreClase>(): base()
{}
%n el caso de @ue el tipo sea una clase a"stractaB entonces el constructor por de!ecto introducido es el
@ue se muestra a continuacinB ya @ue el anterior no sera v$lido por@ue permitira crear o"jetos de la
clase a la @ue perteneceA
protected <nombreClase>(): base()
{}
%n el momento en se de!ina e*plcitamente algCn constructor el compilador dejar$ de introducir
implcitamente el anterior& Hay @ue tener especial cuidado con la llamada @ue este constructor por
de!ecto reali/a en su iniciali/adorB pues pueden producirse errores como el del siguiente ejemploA
class A
{
public A(int x)
{}
}
class B:A
{
public static void Main()
{
B b = new B(); // Error: No hay constructor base
}
}
%n este casoB la creacin del o"jeto de clase 0 en Main=? no es posi"le de"ido a @ue el constructor
@ue por de!ecto el compilador crea para la clase 0 llama al constructor sin par$metros de su clase "ase
-B pero - carece de dic(o constructor por@ue no se le (a de!inido e*plcitamente ninguno con esas
caractersticas pero se le (a de!inido otro @ue (a (ec(o @ue el compilador no le de!ina implcitamente
el primero&
Otro error @ue podra darse consistira en @ue aun@ue el tipo padre tuviese un constructor sin
par$metrosB ,ste !uese privado y por tanto inaccesi"le para el tipo (ijo&
.am"i,n es importante se7alar @ue aCn en el caso de @ue de!inamos nuestras propios constructoresB
si no especi!icamos un iniciali/ador el compilador introducir$ por nosotros uno de la !orma A"ase=? Por
tantoB en estos casos tam"i,n (ay @ue asegurarse de @ue el tipo donde se (aya de!inido el constructor
(erede de otro @ue tenga un constructor sin par$metros no privado&
%lamadas polimr"icas en constructores
%s conveniente evitar en la medida de lo posi"le la reali/acin de llamadas a m,todos virtuales
dentro de los constructoresB ya @ue ello puede provocar errores muy di!ciles de detectar de"ido a @ue
se ejecuten m,todos cuando la parte del o"jeto @ue manipulan aCn no se (a sido iniciali/ado& 1n
ejemplo de esto es el siguienteA
using System;
public class Base
{
public Base()
{
Console.WriteLine("Constructor de Base");
this.F();
}

public virtual void F()
{
Console.WriteLine("Base.F");
}
}
public class Derivada:Base
{
Derivada()
{
Console.WriteLine("Constructor de Derivada");
}

public override void F()
{
Console.WriteLine("Derivada.F()");
}

public static void Main()
{
Base b = new Derivada();
}
}
#a salida por pantalla mostrada por este programa al ejecutarse es la siguienteA
Constructor de 0ase
)erivada&=?
Constructor de )erivada
#o @ue (a ocurrido es lo siguienteA -l crearse el o"jeto )erivada se (a llamado a su constructor sin
par$metrosB @ue como no tiene iniciali/ador implcitamente llama al constructor sin par$metros de su
clase "ase& %l constructor de 0ase reali/a una llamada al m,todo virtual =?B y como el verdadero tipo
del o"jeto @ue se est$ construyendo es )erivadaB entonces la versin del m,todo virtual ejecutada es la
rede!inicin del mismo incluida en dic(a clase& Por CltimoB se termina llamando al constructor de
)erivada y !inali/a la construccin del o"jeto&

8tese @ue se (a ejecutado el m,todo =? de )erivada antes @ue el cdigo del constructor de dic(a
claseB por lo @ue si ese m,todo manipulase campos de!inidos en )erivada @ue se iniciali/asen a trav,s
de constructorB se (a"ra accedido a ellos antes de iniciali/arlos y ello seguramente provocara errores
de causas di!ciles de averiguar&
Constructor de tipo

.odo tipo puede tener opcionalmente un constructor de ti"oB @ue es un m,todo especial @ue !unciona
de !orma similar a los constructores ordinarios slo @ue para lo @ue se usa es para iniciali/ar los
campos static del tipo donde se (a de!inido&

Cada tipo de dato slo puede tener un constructor de tipo& [ste constructor es llamado autom$ticamente
por el compilador la primera ve/ @ue se accede al tipoB ya sea para crear o"jetos del mismo o para
acceder a sus campos est$ticos& %sta llamada se (ace justo despu,s de iniciali/ar los campos est$ticos
del tipo con los valores iniciales especi!icados al de!inirlos =oB en su ausenciaB con los valores por
de!ecto de sus tipos de dato?B por lo @ue el programador no tiene !orma de controlar la !orma en @ue se
le llama yB por tantoB no puede pasarle par$metros @ue condicionen su ejecucin&

Como cada tipo slo puede tener un constructor de tipo no tiene sentido poder usar this en su
iniciali/ador para llamar a otro& W adem$sB tampoco tiene sentido usar base de"ido a @ue ,ste siempre
(ar$ re!erencia al constructor de tipo sin par$metros de su clase "ase& O seaB un constructor de ti"o
no "uede tener inicializador&

-dem$sB no tiene sentido darle modi!icadores de acceso ya @ue el programador nunca lo podr$ llamar
sino @ue slo ser$ llamado autom$ticamente y slo al accederse al tipo por primera ve/& Como es
a"surdoB el compilador considera un error d$rselos&

#a !orma en @ue se de!ine el constructor de tipo es similar a la de los constructores normalesB slo @ue
a(ora la de!inicin (a de ir pre!ijada del modi!icador static y no puede contar con par$metros ni
iniciali/ador& O seaB se de!ine de la siguiente maneraA
static <nombreTipo>()
{
<cdigo>
}
%n la especi!icacin de C# no se (a recogido cu$l (a de ser el orden e*acto de las llamadas a los
constructores de tipos cuando se com"inan con (erenciaB aun@ue lo @ue s se indica es @ue se (a de
asegurar de @ue no se accede a un campo est$tico sin (a"erse ejecutado antes su constructor de tipo&
.odo esto puede verse m$s claro con un ejemploA
using System;
class A
{
public static X;
static A()
{
Console.WriteLine("Constructor de A");
X=1;
}
}
class B:A
{
static B()
{
Console.WriteLine("Constructor de B");
X=2;
}

public static void Main()
{
B b = new B();
Console.WriteLine(B.X);
}
}
#a salida @ue muestra por pantalla la ejecucin de este programa es la siguienteA
Iniciali/ada clase 0
Iniciali/ada clase -
9
%n principio la salida de este programa puede resultar con!usa de"ido a @ue los primeros dos
mensajes parecen dar la sensacin de @ue la creacin del o"jeto " provoc @ue se ejecutase el
constructor de la clase (ija antes @ue al de la clase padreB pero el Cltimo mensaje se corresponde con
una ejecucin en el orden opuesto& Pues "ienB lo @ue (a ocurrido es lo siguienteA como el orden de
llamada a constructores de tipo no est$ esta"lecidoB el compilador de Microso!t (a llamado antes al de
la clase (ija y por ello el primer mensaje mostrado es Iniciali/ada clase 0& Sin em"argoB cuando en este
constructor se va a acceder al campo P se detecta @ue la clase donde se de!ini aCn no est$ iniciali/ada
y entonces se llama a su constructor de tipoB lo @ue (ace @ue se muestre el mensaje Inciali/ada clase -&
.ras esta llamada se mac(aca el valor @ue el constructor de - di a P =valor F? por el valor @ue el
constructor de 0 le da =valor 9? inalmenteB el Cltimo Nrite#ine=? muestra un 9B @ue es el Cltimo valor
escrito en P&
'estructores
-l igual @ue es posi"le de!inir m,todos constructores @ue incluyan cdigo @ue gestione la creacin
de o"jetos de un tipo de datoB tam"i,n es posi"le de!inir un destructor @ue gestione cmo se destruyen
los o"jetos de ese tipo de dato& %ste m,todo suele ser Ctil para li"erar recursos tales como los !ic(eros o
las cone*iones de redes a"iertas @ue el o"jeto a destruir estuviese acaparando en el momento en @ue se
!uese a destruir&
#a destruccin de un o"jeto es reali/ada por el recolector de "asura cuando reali/a una recoleccin
de "asura y detecta @ue no e*isten re!erencias a ese o"jeto ni en pilaB ni en registros ni desde otros
o"jetos s re!erenciados& #as recolecciones se inician autom$ticamente cuando el recolector detecta @ue
@ueda poca memoria li"re o @ue se va a !inali/ar la ejecucin de la aplicacinB aun@ue tam"i,n puede
!or/arse llamando al m,todo Collect;< de la clase S(stem.#C
#a sinta*is @ue se usa para de!inir un destructor es la siguienteA
~<nombreTipo>()
{
<cdigo>
}
.ras la ejecucin del destructor de un o"jeto de un determinado tipo siempre se llama al destructor
de su tipo padreB !orm$ndose as una cadena de llamadas a destructores @ue aca"a al llegarse al
destructor de object& [ste Cltimo destructor no contiene cdigo algunoB y dado @ue object no tiene
padreB tampoco llama a ningCn otro destructor&
#os destructores no se (eredan& Sin em"argoB para asegurar @ue la cadena de llamadas a destructores
!uncione correctamente si no incluimos ninguna de!inicin de destructor en un tipoB el compilador
introducir$ en esos casos una por nosotros de la siguiente !ormaA
~<nombreTipo>()
{}
%l siguiente ejemplo muestra como se de!inen destructores y cmo !unciona la cadena de llamada a
destructoresA
using System;
class A
{
~A()
{
Console.WriteLine("Destruido objeto de clase A");
}
}
class B:A
{
~B()
{
Console.WriteLine("Destruido objeto de clase B");
}
public static void Main()
{
new B();
}
}
%l cdigo del m,todo Main=? de este programa crea un o"jeto de clase 0 pero no almacena ninguna
re!erencia al mismo& #uego !inali/a la ejecucin del programaB lo @ue provoca la actuacin del
recolector de "asura y la destruccin del o"jeto creado llamando antes a su destructor& #a salida @ue
o!rece por pantalla el programa demuestra @ue tras llamar al destructor de 0 se llama al de su clase
padreB ya @ue esA
)estruido o"jeto de clase 0
)estruido o"jeto de clase -

8tese @ue aun@ue no se (aya guardado ninguna re!erencia al o"jeto de tipo 0 creado y por tanto sea
inaccesi"le para el programadorB al recolector de "asura no le pasa lo mismo y siempre tiene acceso a
los o"jetosB aun@ue sean inCtiles para el programador&
%s importante recalcar @ue no es v$lido incluir ningCn modi!icador en la de!inicin de un destructorB
ni si@uiera modi!icadores de accesoB ya @ue como nunca se le puede llamar e*plcitamente no tiene
ningCn nivel de acceso para el programador& Sin em"argoB ello no implica @ue cuando se les llame no
se tenga en cuenta el verdadero tipo de los o"jetos a destruirB como demuestra el siguiente ejemploA
using System;
public class Base
{
public virtual void F()
{
Console.WriteLine("Base.F");
}

~Base()
{
Console.WriteLine("Destructor de Base");
this.F();
}
}
public class Derivada:Base
{
~Derivada()
{
Console.WriteLine("Destructor de Derivada");
}

public override void F()
{
Console.WriteLine("Derivada.F()");
}

public static void Main()
{
Base b = new Derivada();
}
}
#a salida mostrada @ue muestra por pantalla este programa al ejecutarlo esA
)estructor de )erivada
)estructor de 0ase
)erivada&=?
Como se veB aun@ue el o"jeto creado se almacene en una varia"le de tipo 0aseB su verdadero tipo es
)erivada y por ello se llama al destructor de esta clase al destruirlo& .ras ejecutarse dic(o destructor se
llama al destructor de su clase padre sigui,ndose la cadena de llamadas a destructores& %n este
constructor padre (ay una llamada al m,todo virtual =?B @ue como nuevamente el o"jeto @ue se est$
destruyendo es de tipo )erivadaB la versin de =? a la @ue se llamar$ es a la de la dic(a clase&
8tese @ue una llamada a un m,todo virtual dentro de un destructor como la @ue se (ace en el
ejemplo anterior puede dar lugar a errores di!ciles de detectarB pues cuando se llama al m,todo virtual
ya se (a destruido la parte del o"jeto correspondiente al tipo donde se de!ini el m,todo ejecutado& -sB
en el ejemplo anterior se (a ejecutado )erivada&=? tras )erivada&o=?B por lo @ue si en )erivada&=? se
usase algCn campo destruido en )erivada&o=? podran producirse errores di!ciles de detectar&
Concepto de propiedad
1na "ro"iedad es una me/cla entre el concepto de campo y el concepto de m,todo& %*ternamente es
accedida como si de un campo normal se trataseB pero internamente es posi"le asociar cdigo a ejecutar
en cada asignacin o lectura de su valor& [ste cdigo puede usarse para compro"ar @ue no se asignen
valores inv$lidosB para calcular su valor slo al solicitar su lecturaB etc&
1na propiedad no almacena datosB sino slo se utili/a como si los almacenase& %n la pr$ctica lo @ue
se suele (acer escri"ir como cdigo a ejecutar cuando se le asigne un valorB cdigo @ue controle @ue
ese valor sea correcto y @ue lo almacene en un campo privado si lo esJ y como cdigo a ejecutar cuando
se lea su valorB cdigo @ue devuelva el valor almacenado en ese campo pC"lico& -s se simula @ue se
tiene un campo pC"lico sin los inconvenientes @ue estos presentan por no poderse controlar el acceso a
ellos&
'efinici%n de propiedades
Para de!inir una propiedad se usa la siguiente sinta*isA
<tipoPropiedad> <nombrePropiedad>
{
set
{
<cdigoEscritura>
}
get
{
<cdigoLectura>
}
}
1na propiedad as de!inida sera accedida como si de un campo de tipo jtipoPropiedad6 se trataseB
pero en cada lectura de su valor se ejecutara el jcdigo#ectura6 y en cada escritura de un valor en ella
se ejecutara jcdigo%scritura6
-l escri"ir los "lo@ues de cdigo get y set (ay @ue tener en cuenta @ue dentro del cdigo set se
puede (acer re!erencia al valor @ue se solicita asignar a trav,s de un par$metro especial del mismo tipo
de dato @ue la propiedad llamado value =luego nosotros no podemos de!inir uno con ese nom"re en
jcdigo%scritura6?J y @ue dentro del cdigo get se (a de devolver siempre un o"jeto del tipo de dato
de la propiedad&
%n realidad el orden en @ue apare/can los "lo@ues de cdigo set y get es irrelevante& -dem$sB es
posi"le de!inir propiedades @ue slo tengan el "lo@ue get ="ro"iedades de s!lo lectura? o @ue slo
tengan el "lo@ue set ="ro"iedades de s!lo escritura? #o @ue no es v$lido es de!inir propiedades @ue
no incluyan ninguno de los dos "lo@ues&
#as propiedades participan del mecanismo de polimor!ismo igual @ue los m,todosB siendo incluso
posi"le de!inir propiedades cuyos "lo@ues de cdigo get o set sean a"stractos& %sto se (ara pre!ijando
el "lo@ue apropiado con un modi!icador abstract y sustituyendo la de!inicin de su cdigo por un
punto y coma& Por ejemploA
using System;
abstract class A
{
public abstract int PropiedadEjemplo
{
set;
get;
}
}
class B:A
{
private int valor;

public override int PropiedadEjemplo
{
get
{
Console.WriteLine("Ledo {0} de PropiedadEjemplo", valor);
return valor;
}

set
{
valor = value;
Console.WriteLine("Escrito {0} en PropiedadEjemplo", valor);
}
}
}
%n este ejemplo se ve cmo se de!inen y rede!inen propiedades a"stractas& -l igual @ue a"stract y
overrideB tam"i,n es posi"le usar cual@uiera de los modi!icadores relativos a (erencia y polimor!ismo
ya vistosA virtualB ne% y sealed&

8tese @ue aun@ue en el ejemplo se (a optado por asociar un campo privado valor a la propiedad
Propiedad%jemploB en realidad nada o"liga a @ue ello se (aga y es posi"le de!inir propiedades @ue no
tengan campos asociados& %s decirB una propiedad no se tiene por@u, corresponder con un almac,n de
datos&
,cceso a propiedades

#a !orma de acceder a una propiedadB ya sea para lectura o escrituraB es e*actamente la misma @ue la
@ue se usara para acceder a un campo de su mismo tipo& Por ejemploB se podra acceder a la propiedad
de un o"jeto de la clase 0 del ejemplo anterior conA
B obj = new B();
obj.PropiedadEjemplo++;
%l resultado @ue por pantalla se mostrara al (acer una asignacin como la anterior seraA
#edo : de Propiedad%jemploJ
%scrito F en Propiedad%jemploJ
8tese @ue en el primer mensaje se muestra @ue el valor ledo es : por@ue lo @ue devuelve el "lo@ue
get de la propiedad es el valor por de!ecto del campo privado valorB @ue como es de tipo int tiene como
valor por de!ecto :&
Implementaci%n interna de propiedades
%n realidad la de!inicin de una propiedad con la sinta*is antes vista es convertida por el compilador
en la de!inicin de un par de m,todos de la siguiente !ormaA
<tipoPropiedad> get_<nombrePropiedad>()
{// Mtodo en que se convierte en bloque get
<cdigoLectura>
}
void set_<nombrePropiedad> (<tipoPropiedad> value)
{// Mtodo en que se convierte en bloque set
<cdigoEscritura>
}
%sto se (ace para @ue desde lenguajes @ue no soporten las propiedades se pueda acceder tam"i,n a
ellas& Si una propiedad es de slo lectura slo se generar$ el m,todo getXY;<B y si es de slo escritura
slo se generar$ el setXY;< -(ora "ienB en cual@uier caso (ay @ue tener cuidado con no de!inir en un
mismo tipo de dato m,todos con signaturas como estas si se van a generar internamente de"ido a la
de!inicin de una propiedadB ya @ue ello provocara un error de de!inicin mCltiple de m,todo&
.eniendo en cuenta la implementacin interna de las propiedadesB es !$cil ver @ue el Cltimo ejemplo
de acceso a propiedad es e@uivalente aA
B b = new B();
obj.set_PropiedadEjemplo(obj.get_Propiedad_Ejemplo()++);
Como se veB gracias a las propiedades se tiene una sinta*is muc(o m$s compacta y clara para
acceder a campos de manera controlada& Se podra pensar @ue la contrapartida de esto es @ue el tiempo
de acceso al campo aumenta considera"lemente por perderse tiempo en (acer las llamada a m,todos
setAget& Pues "ienB esto no tiene por@u, ser as ya @ue el compilador de C# elimina llamadas (aciendo
inlining =sustitucin de la llamada por su cuerpo? en los accesos a "lo@ues getAset no virtuales y de
cdigos pe@ue7osB @ue son los m$s (a"ituales&

8tese @ue de la !orma en @ue se de!inen los m,todos generados por el compilador se puede deducir el
por@u, del (ec(o de @ue en el "lo@ue set se pueda acceder a trav,s de value al valor asignado y de @ue
el o"jeto devuelto por el cdigo de un "lo@ue get tenga @ue ser del mismo tipo de dato @ue la propiedad
a la @ue pertenece&
Indi*adores
Concepto de indi*ador
1n indizador es una de!inicin de cmo se puede aplicar el operador de acceso a ta"las =- .? a los
o"jetos de un tipo de dato& %sto es especialmente Ctil para (acer m$s clara la sinta*is de acceso a
elementos de o"jetos @ue puedan contener colecciones de elementosB pues permite tratarlos como si
!uesen ta"las normales&
#os indi/adores permiten de!inir cdigo a ejecutar cada ve/ @ue se acceda a un o"jeto del tipo del
@ue son miem"ros usando la sinta*is propia de las ta"lasB ya sea para leer o escri"ir& - di!erencia de las
ta"lasB los ndices @ue se les pase entre corc(etes no tiene por@u, ser enterosB pudi,ndose de!inir varios
indi/adores en un mismo tipo siempre y cuando cada uno tome un nCmero o tipo de ndices di!erente&
'efinici%n de indi*ador
- la (ora de de!inir un indi/ador se usa una sinta*is parecida a la de las propiedadesA
<tipoIndizador> this[<ndices>]
{
set
{
<cdigoEscritura>
}

get
{
<cdigoLectura>
}
}
#as Cnicas di!erencias entre esta sinta*is y la de las propiedades sonA
%l nom"re dado a un indi/ador siempre (a de ser thisB pues carece de sentido poder darle
cual@uiera en tanto @ue a un indi/ador no se accede por su nom"re sino aplicando el operador
- . a un o"jeto& Por elloB lo @ue di!erenciar$ a unos indi/adores de otros ser$ el nCmero y tipo de
sus jndices6&
%n jndices6 se indica cu$les son los ndices @ue se pueden usar al acceder al indi/ador& Para
ello la sinta*is usada es casi la misma @ue la @ue se usa para especi!icar los par$metros de un
m,todoB slo @ue no se admite la inclusin de modi!icadores refB out o "arams y @ue siempre
(a de de!inirse al menos un par$metro& O"viamenteB el nom"re @ue se d, a cada ndice ser$ el
nom"re con el @ue luego se podr$ acceder al mismo en los "lo@ues setIget&
8o se pueden de!inir indi/adores est$ticosB sino slo indi/adores de o"jetos&
Por todo lo dem$sB la sinta*is de de!inicin de los indi/adores es la misma @ue la de las propiedadesA
pueden ser de slo lectura o de slo escrituraB da igual el orden en @ue se de!inan sus "lo@ues setIgetB
dentro del "lo@ue set se puede acceder al valor a escri"ir a trav,s del par$metro especial value del tipo
del indi/adorB el cdigo del "lo@ue get (a de devolver un o"jeto de dic(o tipoB
etc&
- continuacin se muestra un ejemplo de de!inicin de una clase @ue consta de dos indi/adoresA
am"os permiten almacenar elementos de tipo enteroB pero uno toma como ndice un entero y el otro
toma dos cadenasA

using System;

public class A
{
public int this[int ndice]
{
set
{
Console.WriteLine("Escrito {0} en posicin {1}", value, ndice);
}
get
{
Console.WriteLine("Ledo 1 de posicin {0}", ndice);
return 1;
}
}

public int this[string cad1, string cad2]
{
set
{
Console.WriteLine("Escrito {0} en posicin ({1},{2})"
, value, cad1, cad2);
}
get
{
Console.WriteLine("Ledo 2 de posicin ({0},{1})", cad1, cad2);
return 2;
}
}
,cceso a indi*adores
Para acceder a un indi/ador se utili/a e*actamente la misma sinta*is @ue para acceder a una ta"laB
slo @ue los ndices no tienen por@u, ser enteros sino @ue pueden ser de cual@uier tipo de dato @ue se
(aya especi!icado en su de!inicin& Por ejemploB accesos v$lidos a los indi/adores de un o"jeto de la
clase - de!inida en el epgra!e anterior sonA
A obj = new A();
obj[100] = obj["barco", "coche"];
#a ejecucin de la asignacin de este ejemplo producir$ esta salida por pantallaA
#edo 9 de posicin ="arcoB coc(e?
%scrito 9 en posicin F::
Implementacin interna de indi/adores
-l igual @ue las propiedadesB para !acilitar la interopera"ilidad entre lenguajes los indi/adores son
tam"i,n convertidos por el compilador en llamadas a m,todos cuya de!inicin se deduce de la
de!inicin del indi/ador& -(ora los m,todos son de la !ormaA
<tipoIndizador> get_Item(<ndices>)
{
<cdigoLectura>
}
void set_Item(<ndices>, <tipoIndizador> value)
{
<cdigoEscritura>
}
8uevamenteB (ay @ue tener cuidado con la signatura de los m,todos @ue se de!inan en una clase ya
@ue como la de alguno coincida con la generada autom$ticamente por el compilador para los
indi/adores se producir$ un error de am"ig<edad&
-edefinici%n de operadores
Concepto de redefinici%n de operador
1n o"erador en C# no es m$s @ue un sm"olo !ormado por uno o m$s caracteres @ue permite
reali/ar una determinada operacin entre uno o m$s datos y produce un resultado& %n el Tema *:
0s!e%tos -1i%os ya (emos visto @ue C# cuenta con un "uen nCmero de operadores @ue permiten
reali/ar con una sinta*is clara e intuitiva las operaciones comunes a la mayora de lenguajes
=aritm,ticaB lgicaB etc&? as como otras operaciones m$s particulares de C# =operador isB operador
stac'allocB etc&?
%n C# viene prede!inido el comportamiento de sus operadores cuando se aplican a ciertos tipos de
datos& Por ejemploB si se aplica el operador * entre dos o"jetos int devuelve su sumaB y si se aplica
entre dos o"jetos string devuelve su concatenacin& Sin em"argoB tam"i,n se permite @ue el
programador pueda de!inir el signi!icado la mayora de estos operadores cuando se apli@uen a o"jetos
de tipos @ue ,l (aya de!inidoB y esto es a lo @ue se le conoce como redefinici!n de o"erador&
8tese @ue en realidad la posi"ilidad de rede!inir un operador no aporta ninguna nueva
!uncionalidad al lenguaje y slo se (a incluido en C# para !acilitar la legi"ilidad del cdigo& Por
ejemploB si tenemos una clase Complejo @ue representa nCmeros complejos podramos de!inir una
!uncin Sumar=? para sus o"jetos de modo @ue a trav,s de ella se pudiese conseguir la suma de dos
o"jetos de esta clase como muestra este ejemploA
Complejo c1 = new Complejo(3,2); // c1 = 3 + 2i
Complejo c2 = new Complejo(5,2); // c2 = 5 + 2i
Complejo c3 = c1.Sumar(c2); // c3 = 8 + 4i
Sin em"argoB el cdigo sera muc(o m$s legi"le e intuitivo si en ve/ de tenerse @ue usar el m,todo
Sumar=? se rede!iniese el signi!icado del operador D para @ue al aplicarlo entre o"jetos Complejo
devolviese su suma& Con elloB el cdigo anterior @uedara asA
Complejo c1 = new Complejo(3,2); // c1 = 3 + 2i
Complejo c2 = new Complejo(5,2); // c2 = 5 + 2i
Complejo c3 = c1 + c2; // c3 = 8 + 4i
[sta es precisamente la utilidad de la rede!inicin de operadoresA (acer m$s claro y legi"le el cdigoB
no (acerlo m$s corto& Por tantoB cuando se rede!ina un operador es importante @ue se le d, un
signi!icado intuitivo ya @ue si no se ira contra de la !iloso!a de la rede!inicin de operadores& Por
ejemploB aun@ue sera posi"le rede!inir el operador G para @ue cuando se aplicase entre o"jetos de tipo
Complejo devuelva su suma o imprimiese los valores de sus operandos en la ventana de consolaB sera
a"surdo (acerlo ya @ue m$s @ue clari!icar el cdigo lo @ue (ara sera di!icultar su comprensin&
)e todas !ormasB suele ser "uena idea @ue cada ve/ @ue se rede!ina un operador en un tipo de dato
tam"i,n se d, una de!inicin de un m,todo @ue !uncione de !orma e@uivalente al operador& -s desde
lenguajes @ue no soporten la rede!inicin de operadores tam"i,n podr$ reali/arse la operacin y el tipo
ser$ m$s reutili/a"le&
'efinici%n de redefiniciones de operadores
Sinta*is $eneral de rede"inicin de operador
#a !orma en @ue se rede!ine un operador depende del tipo de operador del @ue se trateB ya @ue no es
lo mismo de!inir un operador unario @ue uno "inario& Sin em"argoB como regla general podemos
considerar @ue se (ace de!iniendo un m,todo pC"lico y est$tico cuyo nom"re sea el sm"olo del
operador a rede!inir y venga precedido de la pala"ra reservada o"erator& %s decirB se sigue una sinta*is
de la !ormaA
public static <tipoDevuelto> operator <smbolo>(<operandos>)
{
<cuerpo>
}
#os modi!icadores "ublic y static pueden permutarse si se deseaB lo @ue es importante es @ue
siempre apare/can en toda rede!inicin de operador& Se pueden rede!inir tanto operadores unarios como
"inariosB y en joperandos6 se (a de incluir tantos par$metros como operandos pueda tomar el
operador a rede!inirB ya @ue cada uno representar$ a uno de sus operandos& Por CltimoB en jcuerpo6 se
(an de escri"ir las instrucciones a ejecutar cada ve/ @ue se apli@ue la operacin cuyo operador es
jsm"olo6 a operandos de los tipos indicados en joperandos6&
jtipo)evuelto6 no puede ser voidB pues por de!inicin toda operacin tiene un resultadoB por lo @ue
todo operador (a de devolver algo& -dem$sB permitirlo complicara innecesariamente el compilador y
,ste tendra @ue admitir instrucciones poco intuitivas =como aD"J si el * estuviese rede!inido con valor
de retorno void para los tipos de a y "?
-dem$sB los operadores no pueden rede!inirse con total li"ertad ya @ue ello tam"i,n di!icultara sin
necesidad la legi"ilidad del cdigoB por lo @ue se (an introducido las siguientes restricciones al
rede!inirlosA
-l menos uno de los operandos (a de ser del mismo tipo de dato del @ue sea miem"ro la
rede!inicin del operador& Como puede deducirseB ello implica @ue aun@ue puedan
so"recargarse los operadores "inarios nunca podr$ (acerse lo mismo con los unarios ya @ue su
Cnico par$metro slo puede ser de un Cnico tipo =el tipo dentro del @ue se de!ina? -dem$sB ello
tam"i,n provoca @ue no pueden rede!inirse las conversiones ya incluidas en la 0C# por@ue al
menos uno de los operandos siempre (a"r$ de ser de algCn nuevo tipo de!inido por el usuario&
8o puede alterarse sus reglas de precedenciaB asociatividadB u"icacin y nCmero de operandosB
pues si ya de por s es di!cil para muc(os recordarlas cuando son !ijasB muc(o m$s lo sera si
pudiesen modi!icarse segCn los tipos de sus operandos&
8o puede de!inirse nuevos operadores ni com"inaciones de los ya e*istentes con nuevos
signi!icados =por ejemplo GG para representar e*ponenciacin?B pues ello complicara
innecesariamente el compiladorB el lenguaje y la legi"ilidad del cdigo cuando en realidad es
algo @ue puede simularse de!iniendo m,todos&
8o todos los operadores incluidos en el lenguaje pueden rede!inirseB pues muc(os de ellos
=como .B ne%B &B etc&? son "$sicos para el lenguaje y su rede!inicin es invia"leB poco Ctil o
di!icultara innecesariamente la legi"ilidad del cdigo& -dem$sB no todos los rede!ini"les se
rede!inen usando la sinta*is general (asta a(ora vistaB aun@ue en su momento se ir$n e*plicando
cu$les son los rede!ini"les y cu$les son las peculiaridades de a@uellos @ue re@uieran una
rede!inicin especial&
- continuacin se muestra cmo se rede!inira el signi!icado del operador * para los o"jetos
Complejo del ejemplo anteriorA
class Complejo;
{

public float ParteReal;
public float ParteImaginaria;

public Complejo (float parteReal, float parteImaginaria)
{
this.ParteReal = parteReal;
this.ParteImaginaria = parteImaginaria;
}

public static Complejo operator +(Complejo op1, Complejo op2)
{
Complejo resultado = new Complejo();
resultado.ParteReal = op1.ParteReal + op2.ParteReal;
resultado.ParteImaginaria = op1.ParteImaginaria
+ op2.ParteImaginaria;
return resultado;
}
}
%s !$cil ver @ue lo @ue en el ejemplo se (a rede!inido es el signi!icado del operador * para @ue
cuando se apli@ue entre dos o"jetos de clase Complejo devuelva un nuevo o"jeto Complejo cuyas
partes real e imaginaria sea la suma de las de sus operandos&
Se considera errneo incluir la pala"ra reservada ne% en la rede!inicin de un operadorB ya @ue no
pueden ocultarse rede!iniciones de operadores en tanto @ue estos no se aplican utili/ando el nom"re
del tipo en @ue est,n de!inidos& #as Cnicas posi"les coincidencias se daran en situaciones como la del
siguiente ejemploA
using System;
class A
{
public static int operator +(A obj1, B obj2)
{
Console.WriteLine("Aplicado + de A");
return 1;
}
}
class B:A
{
public static int operator +(A obj1, B obj2)
{
Console.WriteLine("Aplicado + de B");
return 1;
}

public static void Main()
{
A o1 = new A();
B o2 = new B();
Console.WriteLine("o1+o2={0}", o1+o2);
}
}
Sin em"argoB m$s @ue una ocultacin de operadores lo @ue se tiene es un pro"lema de am"ig<edad
en la de!inicin del operador * entre o"jetos de tipos - y 0B de la @ue se in!ormar$ al compilar ya @ue
el compilador no sa"r$ cu$l versin del operador de"e usar para traducir oFDo9 a cdigo "inario&
+ede"inicin de operadores unarios
#os Cnicos operadores unarios rede!ini"les sonA ,B *B +B QB **B ++B true y falseB y toda rede!inicin de
un operador unario (a de tomar un Cnico par$metro @ue (a de ser del mismo tipo @ue el tipo de dato al
@ue pertene/ca la rede!inicin&
#os operadores ** y ++ siempre (a de rede!inirse de manera @ue el tipo de dato del o"jeto devuelto
sea el mismo @ue el tipo de dato donde se de!inen& Cuando se usen de !orma pre!ija se devolver$ ese
o"jetoB y cuando se usen de !orma posti!ja el compilador lo @ue (ar$ ser$ devolver el o"jeto original
@ue se les pas como par$metro en lugar del indicado en el return& Por ello es importante no modi!icar
dic(o par$metro si es de un tipo re!erencia y @ueremos @ue estos operadores tengan su signi!icado
tradicional& 1n ejemplo de cmo (acerlo es la siguiente rede!inicin de ** para el tipo ComplejoA

public static Complejo operator ++ (Complejo op)
{
Complejo resultado = new Complejo(op.ParteReal + 1, op.ParteImaginaria);
return resultado;
}
8tese @ue si (u"i,semos rede!inido el ** de esta otra !ormaA
public static Complejo operator ++ (Complejo op)
{
op.ParteReal++;
return op;
}
%ntonces el resultado devuelto al aplic$rselo a un o"jeto siempre sera el mismo tanto si !ue aplicado
de !orma pre!ija como si lo !ue de !orma posti!ijaB ya @ue en am"os casos el o"jeto devuelto sera el
mismo& Sin em"argoB eso no ocurrira si Complejo !uese una estructuraB ya @ue entonces op no sera el
o"jeto original sino una copia de ,ste y los cam"ios @ue se le (iciesen en el cuerpo de la rede!inicin de
** no a!ectaran al o"jeto originalB @ue es el @ue se devuelve cuando se usa ** de manera post!ija&
+especto a los operadores true y falseB estos indican respectivamenteB cuando se (a de considerar
@ue un o"jeto representa el valor lgico cierto y cuando se (a de considerar @ue representa el valor
lgico !alsoB por lo @ue sus rede!iniciones siempre (an de devolver un o"jeto de tipo bool @ue indi@ue
dic(a situacin& -dem$sB si se rede!ine uno es o"ligatorio rede!inir tam"i,n el otroB pues siempre es
posi"le usar indistintamente uno u otro para determinar el valor lgico @ue un o"jeto de ese tipo
represente&
%n realidad los operadores true y false no pueden usarse directamente en el cdigo !uenteB sino @ue
rede!inirlos para un tipo de dato es Ctil por@ue permiten utili/ar o"jetos de ese tipo en e*presiones
condicionales tal y como si de un valor lgico se tratase& Por ejemploB podemos rede!inir estos
operadores en el tipo Complejo de modo @ue consideren cierto a todo complejo distinto de : D :i y
!also a : D :iA
public static bool operator true(Complejo op)
{
return (op.ParteReal != 0 || op.ParteImaginaria != 0);
}
public static bool operator false(Complejo op)
{
return (op.ParteReal == 0 && op.ParteImaginaria == 0);
}
Con estas rede!inicionesB un cdigo como el @ue sigue mostrara por pantalla el mensaje %s ciertoA
Complejo c1 = new Complejo(1, 0); // c1 = 1 + 0i
if (c1)
System.Console.WriteLine("Es cierto");
+ede!inicin de operadores "inarios
#os operadores "inarios rede!ini"les son *B +B GB AB LB NB OB PB HHB IIB &&B ,&B IB HB I& y H& .oda
rede!inicin @ue se (aga de ellos (a de tomar dos par$metros tales @ue al menos uno sea del mismo tipo
@ue el tipo de dato del @ue es miem"ro la rede!inicin&
Hay @ue tener en cuenta @ue a@uellos de estos operadores @ue tengan complementario siempre (an
de rede!inirse junto con ,ste& %s decirB siempre @ue se rede!ina en un tipo el operador I tam"i,n (a de
rede!inirse en ,l el operador HB siempre @ue se rede!ina I& (a de rede!inirse H&B y siempre @ue se
rede!ina && (a de rede!inirse ,&&
.am"i,n (ay @ue se7alar @ueB como puede deducirse de la lista de operadores "inarios rede!ini"les
dadaB no es rede!inir directamente ni el operador de asignacin M ni los operadores compuestos =*&B +&B
etc&? Sin em"argoB en el caso de estos Cltimos dic(a rede!inicin ocurre de manera autom$tica al
rede!inir su parte Kno &L %s decirB al rede!inir * @uedar$ rede!inido consecuentemente *&B al rede!inir G
lo (ar$ G&B etc&
Por otra parteB tam"i,n ca"e se7alar @ue no es posi"le rede!inir directamente los operadores NN y OO&
%sto se de"e a @ue el compilador los trata de una manera especial @ue consiste en evaluarlos
pere/osamente& Sin em"argoB es posi"le simular su rede!inicin rede!iniendo los operadores unarios
true y falseB los operadores "inarios N y O y teniendo en cuenta @ue NN y OO se evalCan asA
NNA Si tenemos una e*presin de la !orma * 33 yB se aplica primero el operador false a *& Si
devuelve falseB entonces * 33 y devuelve el resultado de evaluar *J y si noB entonces devuelve
el resultado de evaluar * 3 y
OOA Si tenemos una e*presin de la !orma * pp yB se aplica primero el operador true a *& Si
devuelve trueB se devuelve el resultado de evaluar *J y si noB se devuelve el de evaluar * p y&
-edefiniciones de operadores de conversi%n
%n el Tema *: 0s!e%tos -1i%os ya vimos @ue para convertir o"jetos de un tipo de dato en otro se
puede usar un operador de conversin @ue tiene la siguiente sinta*isA
(<tipoDestino>) <expresin>
#o @ue este operador (ace es devolver el o"jeto resultante de convertir al tipo de dato de nom"re
jtipo)estino6 el o"jeto resultante de evaluar je*presin6 Para @ue la conversin pueda aplicarse es
preciso @ue e*ista alguna de!inicin de cmo se (a de convertir a jtipo)estino6 los o"jetos del tipo
resultante de evaluar je*presin6 %sto puede indicarse introduciendo como miem"ro del tipo de esos
o"jetos o del tipo jtipo)estino6 una rede!inicin del operador de conversin @ue indi@ue cmo (acer
la conversin del tipo del resultado de evaluar je*presin6 a jtipo)estino6
#as rede!iniciones de operadores de conversin pueden ser de dos tiposA
E)"l0citas: #a conversin slo se reali/a cuando se usen e*plcitamente los operadores de
conversin antes comentado&
Im"l0citas: #a conversin tam"i,n se reali/a autom$ticamente cada ve/ @ue se asigne un o"jeto
de ese tipo de dato a un o"jeto del tipo jtipo)estino6& %stas conversiones son m$s cmodas @ue
las e*plcitas pero tam"i,n m$s peligrosas ya @ue pueden ocurrir sin @ue el programador se d,
cuenta& Por elloB slo de"eran de!inirse como implcitas las conversiones seguras en las @ue no
se puedan producir e*cepciones ni perderse in!ormacin al reali/arlas&
%n un mismo tipo de dato pueden de!inirse mCltiples conversiones siempre y cuando el tipo origen
de las mismas sea di!erente& Por tantoB no es v$lido de!inir a la ve/ en un mismo tipo una versin
implcita de una cierta conversin y otra e*plcita&
#a sinta*is @ue se usa para (acer rede!inir una operador de conversin es parecida a la usada para
cual@uier otro operador slo @ue no (ay @ue darle nom"reB toma un Cnico par$metro y (ay @ue preceder
la pala"ra reservada o"erator con las pala"ras reservadas e)"licit o im"licit segCn se de!ina la
conversin como e*plcita o implcita& Por ejemploB para de!inir una conversin implcita de Complejo
a float podra (acerseA
public static implicit operator float(Complejo op)
{
return op.ParteReal;
}
8tese @ue el tipo del par$metro usado al de!inir la conversin se corresponde con el tipo de dato del
o"jeto al @ue se puede aplicar la conversin =ti"o origen?B mientras @ue el tipo del valor devuelto ser$
el tipo al @ue se realice la conversin =ti"o destino? Con esta de!inicin podran escri"irse cdigos
como el siguienteA
Complejo c1 = new Complejo(5,2); // c1 = 5 + 2i
float f = c1; // f = 5
8tese @ue en la conversin de Complejo a float se pierde in!ormacin =la parte imaginaria?B por lo
@ue sera mejor de!inir la conversin como e*plcita sustituyendo en su de!inicin la pala"ra reservada
im"licit por e)"licit& %n ese casoB el cdigo anterior (a"ra de cam"iarse porA
Complejo c1 = new Complejo(5,2); // c1 = 5 + 2i
float f = (float) c1; // f = 5
Por otro ladoB si lo @ue (acemos es rede!inir la conversin de float a Complejo conA
public static implicit operator Complejo(float op)
{
return (new Complejo(op, 0));
}
%ntonces se podra crear o"jetos Complejo asA
Complejo c2 = 5; // c2 = 5 + 0i
V,ase @ue en este caso nunca se perder$ in!ormacin y la conversin nunca !allar$B por lo @ue es
per!ectamente v$lido de!inirla como implcita& -dem$sB ntese como rede!iniendo conversiones
implcitas puede conseguirse @ue los tipos de!inidos por el usuario puedan iniciali/arse directamente a
partir de valores literales tal y como si !uesen tipos "$sicos del lenguaje&
%n realidadB cuando se de!inan conversiones no tiene por@u,s siempre ocurrir @ue el tipo destino
indicado sea el tipo del @ue sea miem"ro la rede!inicinB sino @ue slo (a de cumplirse @ue o el tipo
destino o el tipo origen sean de dic(o tipo& O seaB dentro de un tipo de dato slo pueden de!inirse
conversiones de ese tipo a otro o de otro tipo a ese& Sin em"argoB al permitirse conversiones en am"os
sentidos (ay @ue tener cuidado por@ue ello puede producir pro"lemas si se solicitan conversiones para
las @ue e*ista una de!inicin de cmo reali/arlas en el tipo !uente y otra en el tipo destino& Por ejemploB
el siguiente cdigo provoca un error al compilar de"ido a elloA
class A
{
static void Main(string[] args)
{
A obj = new B(); // Error: Conversin de B en A ambigua
}

public static implicit operator A(B obj)
{
return new A();
}
}
class B
{
public static implicit operator A(B obj)
{
return new A();
}
}
%l pro"lema de este tipo de errores es @ue puede resulta di!cil descu"rir sus causas en tanto @ue el
mensaje @ue el compilador emite indica @ue no se pueden convertir los o"jetos - en o"jetos 0 pero no
aclara @ue ello se de"a a una am"ig<edad&
Otro error con el @ue (ay @ue tener cuidado es con el (ec(o de @ue puede ocurrir @ue al me/clar
rede!iniciones implcitas con m,todos so"recargados puedan (a"er am"ig<edades al determinar a @u,
versin del m,todo se (a de llamar& Por ejemploB dado el cdigoA
using System;
class A
{
public static implicit operator A(B obj)
{
return new A();
}

public static void MtodoSobrecargado(A o)
{
Console.WriteLine("Versin que toma A");
}

public static void MtodoSobrecargado(C o)
{
Console.WriteLine("Versin que toma C");
}

static void Main(string[] args)
{
MtodoSobrecargado(new B());
}
}
class B
{
public static implicit operator C(B obj)
{
return new C();
}
}
class C
{}
-l compilarlo se producir$ un error de"ido a @ue en la llamada a M,todoSo"recargado=? el
compilador no puede deducir a @u, versin del m,todo se desea llamar ya @ue e*isten conversiones
implcitas de o"jetos de tipo 0 en cual@uiera de los tipos admitidos por sus distintas versiones& Para
resolverlo lo mejor especi!icar e*plcitamente en la llamada la conversin a aplicar usando el operador
;< Por ejemploB para usar usar la versin del m,todo @ue toma como par$metro un o"jeto de tipo - se
podra (acerA
MtodoSobrecargado ( (A) new B());
Sin em"argoB (ay @ue tener cuidado ya @ue si en ve/ del cdigo anterior se tuvieseA
class A
{
public static implicit operator A(B obj)
{
return new A();
}
public static void MtodoSobrecargado(A o)
{
Console.WriteLine("Versin que toma A");
}

public static void MtodoSobrecargado(C o)
{
Console.WriteLine("Versin que toma C");
}

static void Main(string[] args)
{
MtodoSobrecargado(new B());
}
}
class B
{
public static implicit operator A(B obj)
{
return new A();
}

public static implicit operator C(B obj)
{
return new C();
}
}
class C
{}
%ntonces el !uente compilara con normalidad y al ejecutarlo se mostrara el siguiente mensaje @ue
demuestra @ue se (a usado la versin del m,todo @ue toma un o"jeto C&
inalmenteB (ay @ue se7alar @ue no es posi"le de!inir cual@uier tipo de conversinB sino @ue a@uellas
para las @ue ya e*ista un mecanismo prede!inido en el lenguaje no son v$lidas& %s decirB no pueden
de!inirse conversiones entre un tipo y sus antecesores =por el polimor!ismo ya e*isten?B ni entre un tipo
y ,l mismoB ni entre tipos e inter!aces por ellos implementadas =las inter!aces se e*plicar$n en el Tema
&5: "#ter3a%es?
'ele!ados y eventos
Concepto de dele!ado
1n delegado es un tipo especial de clase cuyos o"jetos pueden almacenar re!erencias a uno o
m$s m,todos de tal manera @ue a trav,s del o"jeto sea posi"le solicitar la ejecucin en cadena de
todos ellos&
#os delegados son muy Ctiles ya @ue permiten disponer de o"jetos cuyos m,todos puedan ser
modi!icados din$micamente durante la ejecucin de un programa& )e (ec(oB son el mecanismo
"$sico en el @ue se "asa la escritura de aplicaciones de ventanas en la plata!orma &8%.& Por
ejemploB si en los o"jetos de una clase 0utton @ue represente a los "otones est$ndar de Nindo's
de!inimos un campo de tipo delegadoB podemos conseguir @ue cada "otn @ue se cree ejecute un
cdigo di!erente al ser pulsado sin m$s @ue almacenar el cdigo a ejecutar por cada "otn en su
campo de tipo delegado y luego solicitar la ejecucin todo este cdigo almacenado cada ve/ @ue
se pulse el "otn&
Sin em"argoB tam"i,n son Ctiles para muc(simas otras cosas tales como asociacin de cdigo a
la carga y descarga de ensam"ladosB a cam"ios en "ases de datosB a cam"ios en el sistema de
arc(ivosB a la !inali/acin de operaciones asncronasB la ordenacin de conjuntos de elementosB
etc& %n generalB son Ctiles en todos a@uellos casos en @ue interese pasar m,todos como par$metros
de otros m,todos&
-dem$sB los delegados proporcionan un mecanismo mediante el cual unos o"jetos pueden
solicitar a otros @ue se les noti!i@ue cuando ocurran ciertos sucesos& Para elloB "astara seguir el
patrn consistente en (acer @ue los o"jetos noti!icadores dispongan de algCn campo de tipo
delegado y (acer @ue los o"jetos interesados almacenen m,todos suyos en dic(os campos de modo
@ue cuando ocurra el suceso apropiado el o"jeto noti!icador simule la noti!icacin ejecutando
todos los m,todos as asociados a ,l&
'efinici%n de dele!ados
1n delegado no es m$s @ue un tipo especial de su"clase S(stem.MulticastEelegate& Sin
em"argoB para de!inir estas clases no se puede utili/ar el mecanismo de (erencia normal sino @ue
(a de seguirse la siguiente sinta*is especialA
<modificadores> delegate <tipoRetorno> <nombreDelegado> (<parmetros>);
jnom"re)elegado6 ser$ el nom"re de la clase delegado @ue se de!ineB mientras @ue
jtipo+etorno6 y jpar$metros6 se corresponder$nB respectivamenteB con el tipo del valor de
retorno y la lista de par$metros de los m,todos cuyos cdigos puede almacenar en su interior los
o"jetos de ese tipo delegado =objetos delegados?
1n ejemplo de cmo de!inir un delegado de nom"re )eleg cuyos o"jetos puedan almacenar
m,todos @ue devuelvan un string y tomen como par$metro un int esA
delegate void Deleg(int valor);
La clase #ystem$&ulticast'ele!ate
Wa se (a dic(o @ue la sinta*is especial de de!inicin de delegados no es m$s @ue una !orma especial
de!inir su"clases de S(stem.MulticastEelegate& %sta clase a su ve/ deriva de S(stem.EelegateB @ue
representa a o"jetos delegados @ue slo puede almacenar un Cnico m,todo& Por tantoB todos los o"jetos
delegado @ue se de!inan contar$n con los siguientes miem"ros comunes (eredados de estas clasesA
object TargetA Propiedad de slo lectura @ue almacena el o"jeto al @ue pertenece el Cltimo
m,todo a7adido al o"jeto delegado& Si es un m,todo de clase vale null&
MethodInfo MethodA Propiedad de slo lectura @ue almacena un o"jeto
S(stem.Ceflection.MethodInfo con in!ormacin so"re el Cltimo m,todo a7adido al o"jeto
=nom"reB modi!icadoresB etc&? Para sa"er cmo acceder a estos datos puede consultar la
documentacin incluida en el S)] so"re la clase MethodInfo
Eelegate-. getInvocation:ist;<A Permite acceder a todos los m,todos almacenados en un
delegadoB ya @ue devuelve una ta"la cuyos elementos son delegados cada uno de los cuales
almacenan unoB y slo unoB de los m,todos del original& %stos delegados se encuentran
ordenados en la ta"la en el mismo orden en @ue sus m,todos !ueron !ue almacenados en el
o"jeto delegado original&
%ste m,todo es especialmente Ctil por@ue a trav,s de la ta"la @ue retorna se pueden (acer cosas tales
como ejecutar los m,todos del delegado en un orden di!erente al de su almacenamientoB procesar los
valores de retorno de todas las llamadas a los m,todos del delegado originalB evitar @ue una e*cepcin
en la ejecucin de uno de los m,todos impida la ejecucin de los dem$sB etc&
-parte de estos m,todos de o"jetoB la clase S(stem.MulticastEelegate tam"i,n cuenta con los
siguientes m,todos de tipo de uso !recuenteA
static Eelegate Combine;Eelegate fuenteU Eelegate destino<A )evuelve un nuevo o"jeto
delegado @ue almacena la concatenacin de los m,todos de !uente con los de destino& Por tantoB
ntese @ue estas tres instrucciones son e@uivalentesA
objDelegado += new D(obj1.g);
objDelegado = objDelegado + new D(obj1.g);
objDelegado = (D) MulticastDelegate.Combine(objDelegado, new D(obj1.g);
%s m$sB en realidad el compilador de C# lo @ue (ace es convertir toda aplicacin del operador *
entre delegados en una llamada a Combine;< como la mostrada&
Hay @ue tener cuidado con los tipos de los delegados a com"inar ya @ue (an de ser e*actamente los
mismos o si no se lan/a una S(stem.FrgumentE)ce"tionB y ello ocurre aCn en el caso de @ue dic(os
slo se di!erencien en su nom"re y no en sus tipos de par$metros y valor de retorno&
static Eelegate Combine;Eelegate-. tabla<A )evuelve un nuevo delegado cuyos m,todos
almacenados son la concatenacin de todos los de la lista @ue se le pasa como par$metro y en el
orden en @ue apareciesen en ella& %s una "uena !orma de crear delegados con muc(os m,todos
sin tener @ue aplicar *& varias veces& .odos los o"jetos delegados de la ta"la (an de ser del
mismo tipoB pues si no se producira una S(stem.FrgumentE)ce"tion&
static Eelegate Cemove;Eelegate originalU Eelegate a=orrar<A )evuelve un nuevo delegado
cuyos m,todos almacenados son el resultado de eliminar de original los @ue tuviese a0orrar&
Por tantoB estas instrucciones son e@uivalentesA

objDelegado -= new D(obj1.g);
objDelegado - objDelegado - new D(obj1.g);
objDelegado = (D) MulticastDelegate.Remove(objDelegado, new D(obj1.g);
8uevamenteB lo @ue (ace el compilador de C# es convertir toda aplicacin del operador + entre
delegados en una llamada a Cemove;< como la mostrada& Por tantoB al igual @ue con +&B para "orrar
m,todos de o"jeto se (a de especi!icar en a0orrar un o"jeto delegado @ue contenga re!erencias a
m,todos asociados a e*actamente los mismos o"jetos @ue los almacenados en original&
static Eelegate CreateEelegate ;T("e ti"oU MehodInfo mKtodo<A Wa se us este m,todo en
el ejemplo de compro"acin de tipos del epgra!e :De3i#i%i'# de dele(ados; de este mismo
tema& Como recordar$ permite crear din$micamente o"jetos delegadosB ya @ue devuelve un
o"jeto delegado del tipo indicado @ue almacena una re!erencia al m,todo representado por su
segundo par$metro&
Llamadas asncronas
#a !orma de llamar a m,todos @ue (asta a(ora se (a e*plicado reali/a la llamada de manera
s0ncronaB lo @ue signi!ica @ue la instruccin siguiente a la llamada no se ejecuta (asta @ue no
!inalice el m,todo llamado& Sin em"argoB a todo m,todo almacenado en un o"jeto delegado
tam"i,n es posi"le llamar de manera as0ncrona a trav,s de los m,todos del mismoB lo @ue consiste
en @ue no se espera a @ue aca"e de ejecutarse para pasar a la instruccin siguiente a su llamada
sino @ue su ejecucin se deja en manos de un (ilo aparte @ue se ir$ ejecut$ndolo en paralelo con el
(ilo llamante&
Por tanto los delegados proporcionan un cmodo mecanismo para ejecutar cual@uier m,todo
asncronamenteB pues para ello "asta introducirlo en un o"jeto delegado del tipo apropiado& Sin
em"argoB este mecanismo de llamada asncrona tiene una limitacinB y es @ue slo es v$lido para
o"jetos delegados @ue almacenen un Cnico m,todo&
Para (acer posi"le la reali/acin de llamadas asncronasB aparte de los m,todos (eredados de
S(stem.MulticastEelegate todo delegado cuenta con estos otros dos @ue el compilador de!ine a
su medida en la clase en @ue traduce la de!inicin de su tipoA
'.sync4esult /egin'nvoke(<parmetros>, .sync5allback cb, 6bject o)

<tipoRetorno> (nd'nvoke(<parmetrosRefOut>, '.&ync4esult ar)

=eginInvo'e;< crea un (ilo @ue ejecutar$ los m,todos almacenados en el o"jeto delegado so"re
el @ue se aplica con los par$metros indicados en +!ar2metros, y devuelve un o"jeto
IFs(ncCesult @ue almacenar$ in!ormacin relativa a ese (ilo =por ejemploB a trav,s de su
propiedad de slo lectura bool IsCom"lete puede consultarse si (a terminado su la"or? Slo tiene
sentido llamarlo si el o"jeto delegado so"re el @ue se aplica almacena un Cnico m,todoB pues si no
se lan/a una S(stem.FrgumentE)ce"tion&
%l par$metro c" de =eginInvo'e;< es un o"jeto de tipo delegado @ue puede almacenar m,todos
a ejecutar cuando el (ilo antes comentado !inalice su tra"ajo& - estos m,todos el C#+ les pasar$
autom$ticamente como par$metro el IFs(ncCesult devuelto por =eginInvo'e;<B estando as
de!inido el delegado destinado a almacenarlosA
public delegate void .&ync5allback('.&ync4esult obj);
Por su parteB el par$metro o de =eginInvo'e puede usarse para almacenar cual@uier
in!ormacin adicional @ue se considere oportuna& %s posi"le acceder a ,l a trav,s de la propiedad
object Fs(ncState del o"jeto IFs(ncCesult devuelto por =eginInvo'e;<
%n caso de @ue no se desee ejecutar ningCn cdigo especial al !inali/ar el (ilo de ejecucin
asncrona o no desee usar in!ormacin adicionalB puede darse sin ningCn tipo de pro"lema el valor
null a los Cltimos par$metros de =eginInvo'e;< segCn corresponda&
inalmenteB EndInvo'e;< se usa para recoger los resultados de la ejecucin asncrona de los
Implementaci%n interna de los dele!ados
Cuando (acemos una de!inicin de delegado de la !ormaA
<modificadores> delegate <tipoRetorno> <nombre>(<parmetros>);
%l compilador internamente la trans!orma en una de!inicin de clase de la !ormaA
<modificadores> class <nombre>:&ystem#Multicast2elegate
{
private object _target;
private int _methodPtr;
private Multicast2elegate _prev;

public <nombre>(object objetivo, int punteroMtodo)
{...}

public virtual <tipoRetorno> 'nvoke(<parmetros>)
{...}

public virtual '.sync4esult /egin'nvoke(<parmetros>,
.sync5allback cb, Object o)
{...}

public virtual <tipoRetorno> (nd'nvoke(<parmetrosRefOut>,
'.&ync4esult ar)
{...}
}
#o primero @ue llama la atencin al leer la de!inicin de esta clase es @ue su constructor no se parece
en a"soluto al @ue (emos estado usando (asta a(ora para crear o"jetos delegado& %sto se de"e a @ue en
realidadB a partir de los datos especi!icados en la !orma de usar el constructor @ue el programador
utili/aB el compilador es capa/ de determinar los valores apropiados para los par$metros del verdadero
constructorB @ue sonA
object objetivo contiene el o"jeto al cual pertenece el m,todo especi!icadoB y su valor se
guarda en el campo Xtarget& Si es un m,todo est$tico almacena null&
in! pun!ero"!odo contiene un entero @ue permite al compilador determinar cu$l es el m,todo
del o"jeto al @ue se desea llamarB y su valor se guarda en el campo Xmethod1tr& SegCn donde
se (aya de!inido dic(o m,todoB el valor de este par$metro proceder$ de las ta"las MethodEef o
MethodCef de los metadatos&
%l campo privado X"rev de un delegado almacena una re!erencia al delegado previo al mismo en la
cadena de m,todos& %n realidadB en un o"jeto delegado con mCltiples m,todos lo @ue se tiene es una
cadena de o"jetos delegados cada uno de los cuales contiene uno de los m,todos y una re!erencia =en
X"rev? a otro o"jeto delegado @ue contendr$ otro de los m,todos de la cadena&
Cuando se crea un o"jeto delegado con ne% se da el valor null a su campo X"rev para as indicar
@ue no pertenece a una cadena sino @ue slo contiene un m,todo& Cuando se com"inen dos o"jetos
delegados =con * o Eelegate.Combine;<? el campo X"rev del nuevo o"jeto delegado creado enla/ar$ a
los dos originalesJ y cuando se eliminen m,todos de la cadena =con M o Eelegate.Cemove;<? se
actuali/ar$n los campos X"rev de la cadena para @ue salten a los o"jetos delegados @ue contenan los
m,todos eliminados&
Cuando se solicita la ejecucin de los m,todos almacenados en un delegado de manera asncrona lo
@ue se (ace es llamar al m,todo Invo'e;< del mismo& Por ejemploB una llamada como estaA
objDelegado(49);
%s convertida por el compilador enA
objDelegado.Invoke(49);
-un@ue Invo'e;< es un m,todo pC"licoB C# no permite @ue el programador lo llame e*plcitamente&
Sin em"argoB otros lenguajes gestionados s @ue podran permitirlo&
%l m,todo Invo'e;< se sirve de la in!ormacin almacenada en XtargetB Xmethod1tr y X"revB para
determinar a cu$l m,todo se (a de llamar y en @u, orden se le (a de llamar& -sB la implementacin de
Invo'e;< ser$ de la !ormaA
public virtual <tipoRetorno> 'nvoke(<parmetros>)
{
if (_prev!=null)
_prev.Invoke(<parmetros>);
return _target._methodPtr(<parmetros>);
}
O"viamente la sinta*is Xtarget&Xmethod1tr no es v$lida en C#B ya @ue Xmethod1tr no es un m,todo
sino un campo& Sin em"argoB se (a escrito as para poner de mani!iesto @ue lo @ue el compilador (ace
es generar el cdigo apropiado para llamar al m,todo perteneciente al o"jeto indicado en Xtarget e
identi!icado con el valor de Xmethod1tr
8tese @ue la instruccin if incluida se usa para asegurar @ue las llamadas a los m,todos de la cadena
se (agan en ordenA si el o"jeto delegado no es el Cltimo de la cadena& =X"rev,&null? se llamar$ antes al
m,todo Invo'e;< de su predecesor&
Por CltimoB slo se7alar @ueB como es lgicoB en caso de @ue los m,todos @ue el o"jeto delegado
pueda almacenar no tengan valor de retorno =,ste sea void?B el cuerpo de Invo'e;< slo vara en @ue la
pala"ra reservada return es eliminada del mismo&
Eventos
Concepto de e#ento
1n evento es una variante de las propiedades para los campos cuyos tipos sean delegados& %s decirB
permiten controlar la !orman en @ue se accede a los campos delegados y dan la posi"ilidad de asociar
cdigo a ejecutar cada ve/ @ue se a7ada o elimine un m,todo de un campo delegado&
Sinta*is bsica de de"inicin de e#entos
#a sinta*is "$sica de de!inicin de un evento consiste en de!inirlo como cual@uier otro campo con la
Cnica peculiaridad de @ue se le (a de anteponer la pala"ra reservada event al nom"re de su tipo =@ue
ser$ un delegado? O seaB se sigue la sinta*isA
<modificadores> event <tipoDelegado> <nombreEvento>$
Por ejemploB para de!inir un evento de nom"re Prue"a y tipo delegado ) se (araA
public event D Prueba;
.am"i,n pueden de!inirse mCltiples eventos en una misma lnea separando sus nom"res mediante
comas& Por ejemploA
public event D Prueba1, Prueba2;
)esde cdigo u"icado dentro del mismo tipo de dato donde se (aya de!inido el evento se puede usar
el evento tal y como si de un campo delegado normal se tratase& Sin em"argoB desde cdigo u"icado
e*ternamente se imponen una serie de restricciones @ue permiten controlar la !orma en @ue se accede al
mismoA
8o se le puede aplicar los m,todos (eredados de S(stem.MulticastEelegate&
Slo se le puede aplicar dos operacionesA a7adido de m,todos con *& y eliminacin de m,todos
con +&& )e este modo se evita @ue se use sin @uerer & en ve/ de *& +& y se sustituyan todos
los m,todos de la lista de m,todos del campo delegado por otro @ue en realidad se le @uera
a7adir o @uitar =si ese otro valiese nullB ello incluso podra provocar una
S(stem.NullCeferenceE)ce"tion?
8o es posi"le llamar a los m,todos almacenados en un campo delegado a trav,s del mismo&
%sto permite controlar la !orma en @ue se les llamaB ya @ue o"liga a @ue la llamada tenga @ue
(acerse a trav,s de algCn m,todo pC"lico de!inido en la de!inicin del tipo de dato donde el
evento !ue de!inido&
Sinta*is completa de de"inicin de e#entos
#a verdadera utilidad de un evento es @ue permite controlar la !orma en @ue se asocian y @uitan
m,todos de los o"jetos delegados con *& y +&& Para ello se (an de de!inir con la siguiente sinta*is
avan/adaA
<modificadores> event <tipoDelegado> <nombreEvento>
{
add
{
<cdigoAdd>
}

remove
{
<cdigoRemove>
}
}

Con esta sinta*is no pueden de!inirse varios eventos en una misma lnea como ocurra con la "$sica&
Su signi!icado es el siguienteA cuando se asocie un m,todo con *& al evento se ejecutar$ el
jcdigo-dd6B y cuando se le @uite alguno con M& se ejecutar$ el jcdigo+emove6& %sta sinta*is es
similar a la de los "lo@ues setAget de las propiedades pero con una importante di!erenciaA aun@ue
pueden permutarse las secciones add y removeB es o"ligatorio incluir siempre a am"as&
#a sinta*is "$sica es en realidad una !orma a"reviada de usar la avan/ada& -sB la de!inicin pu"lic
event ) Prue"a=int valor?J la interpretara el compilador comoA
private D prueba
public event D Prueba
{
[Method'mpl(Method'ml6ptions#&ynchronied)]
add
{
prueba = (D) Delegate.Combine(prueba, value);
}
[Method'mpl(Method'ml6ptions#&ynchronied)]
remove
{
prueba = (D) Delegate.Remove(prueba, value);
}
}
%s decirB el compilador de!inir$ un campo delegado privado y cdigos para add y remove @ue (agan
@ue el uso de *& y +& so"re el evento tenga el e!ecto @ue normalmente tendran si se aplicasen
directamente so"re el campo privado& Como se veB dentro de estos m,todos se puede usar value para
(acer re!erencia al operando derec(o de los operadores *& y +&& %l atri"uto
S(stem.Cuntime.Intero"Services.MethodIm"l @ue precede a los "lo@ues add y remove slo se
incluye para asegurar @ue un cam"io de (ilo no pueda interrumpir la ejecucin de sus cdigos
asociados&
#as restricciones de uso de eventos desde cdigos e*ternos al tipo donde se (an de!inido se de"en a
@ue en realidad ,stos no son o"jetos delegados sino @ue el o"jeto delegado es el campo privado @ue
internamente de!ine el compilador& %l compilador traduce toda llamada al evento en una llamada al
campo delegado& Como este es privadoB por eso slo pueda accederse a ,l desde cdigo de su propio
tipo de dato&
%n realidadB el compilador internamente traduce las secciones add y remove de la de!inicin de un
evento en m,todos de la !ormaA
void add7<nombreEvento>(<tipoDelegado> value)
void remove7<nombreEvento>(<tipoDelegado> value)
.oda aplicacin de *& y 5M a un evento no es convertida en una llamada al campo privado sino en
una llamada al m,todo addAremove apropiadoB como se puede o"servar anali/ando el MSI# de
cual@uier !uente donde se usen *& y 5M so"re eventos& -dem$sB como estos m,todos devuelven void
,se ser$ el tipo del valor devuelto al aplicar *& 5M =y no el o"jeto asignado?B lo @ue evitar$ @ue cdigo
e*terno al tipo donde se (aya de!inido el evento pueda acceder directamente al campo delegado
privado&
Si en ve/ de la sinta*is "$sica usamos la completa no se de!inir$ autom$ticamente un campo
delegado por cada evento @ue se de!inaB por lo @ue tampoco ser$ posi"le (acer re!erencia al mismo
desde cdigo u"icado en la misma clase donde se (a de!inido& Sin em"argo ello permite @ue el
programador pueda determinarB a trav,s de secciones add y removeB cmo se almacenar$n los
m,todos& Por ejemploB para a(orrar memoria se puede optar por usar un diccionario donde almacenar
los m,todos asociados a varios eventos de un mismo o"jeto en lugar de usar un o"jeto delegado por
cada uno&
)ado @ue las secciones add y remove se traducen como m,todosB los eventos tam"i,n podr$n
participar en el mecanismo de (erencia y rede!iniciones tpico de los m,todos& %s decirB en
jmodi!icadores6 aparte de modi!icadores de acceso y el modi!icador staticB tam"i,n se podr$n incluir
los modi!icadores relativos a (erencia& %n este sentido (ay @ue precisar algoA un evento de!inido como
abstract (a de de!inirse siempre con la sinta*is "$sica =no incluir$ secciones add o remove?
Estructuras
Concepto de estructura
1na estructura es un tipo especial de clase pensada para representar o"jetos ligeros& %s decirB @ue
ocupen poca memoria y de"an ser manipulados con velocidadB como o"jetos @ue representen puntosB
!ec(asB etc& %jemplos de estructuras incluidas en la 0C# son la mayora de los tipos "$sicos =e*cepto
string y object?B y de (ec(o las estructuras junto con la rede!inicin de operadores son la !orma ideal
de de!inir nuevos tipos "$sicos a los @ue se apli@uen las mismas optimi/aciones @ue a los prede!inidos&
'iferencias entre clases y estructuras
- di!erencia de una clase y !iel a su espritu de Kligere/aLB una estructura no puede derivar de ningCn
tipo y ningCn tipo puede derivar de ella& Por estas ra/ones sus miem"ros no pueden incluir
modi!icadores relativos a (erenciaB aun@ue con una e*cepcinA pueden incluir override para rede!inir
los miem"ros de S(stem.bject&
Otra di!erencia entre las estructuras y las clases es @ue sus varia"les no almacenan re!erencias a
/onas de memoria din$mica donde se encuentran almacenados o"jetos sino directamente re!erencian a
o"jetos& Por ello se dice @ue las clases son ti"os referencia y las estructuras son ti"os valorB siendo
posi"le tanto encontrar o"jetos de estructuras en pila =no son campos de clases? como en memoria
din$mica =son campos de clases?
1na primera consecuencia de esto es @ue los accesos a miem"ros de o"jetos de tipos valor son
muc(o m$s r$pidos @ue los accesos a miem"ros de pilasB ya @ue es necesario pasar por una re!erencia
menos a la (ora de acceder a ellos& -dem$sB el tiempo de creacin y destruccin de estructuras tam"i,n
es in!erior& )e (ec(oB la destruccin de los o"jetos almacenados en pila es pr$cticamente inaprecia"le
ya @ue se reali/a con un simple decremento del puntero de pila y no interviene en ella el recolector de
"asura&
Otra consecuencia de lo anterior es @ue cuando se realicen asignaciones entre varia"les de tipos
valorB lo @ue se va a copiar en la varia"le destino es el o"jeto almacenado por la varia"le !uente y no la
direccin de memoria din$mica a la @ue apunta"a ,sta& Por ejemploB dado el siguiente tipo =ntese @ue
las estructuras se de!inen igual @ue las clases pero usando la pala"ra reservada struct en ve/ de class?A
struct Point
{
public int x, y;

public Point(int x, int y)
{
this.x = x;
this.y = y;
}
}
Si usamos este tipo en un cdigo como el siguienteA
Punto p = new Punto(10,10);
Punto p2 = p;
p2.x = 100;
Console.WriteLine(p.x);
#o @ue se mostrar$ por pantalla ser$ F:& %sto se de"e a @ue el valor de * modi!icado es el de p9B @ue
como es una copia de p los cam"ios @ue se le (agan no a!ectar$n a p& Sin em"argoB si Punto (u"iese
sido de!inido como una clase entonces s @ue se (u"iese mostrado por pantalla F::B ya @ue en ese caso
lo @ue se (a"ra copiado en p9 (a"ra sido una re!erencia a la misma direccin de memoria din$mica
re!erenciada por pB por lo @ue cual@uier cam"io @ue se (aga en esa /ona a trav,s de p9 tam"i,n a!ectar$
a p&
)e lo anterior se deduce @ue la asignacin entre o"jetos de tipos estructuras es muc(o m$s lenta @ue
la asignacin entre o"jetos de clasesB ya @ue se (a de copiar un o"jeto completo y no solo una
re!erencia& Para aliviar esto al pasar o"jetos de tipos estructura como par$metrosB se da la posi"ilidad de
pasarlos como par$metros por re!erencia =modi!icador ref? o par$metros de salida =out? en ve/ de
como par$metros de entrada&
.odas las estructuras derivan implcitamente del tipo S(stem./alueT("eB @ue a su ve/ deriva de la
clase primigenia S(stem.bject& /alueT("e tiene los mismos miem"ros @ue su padreB y la Cnica
di!erencia se7ala"le entre am"os es @ue en /alueT("e se (a rede!inido ESuals;< de modo @ue
devuelva true si los o"jetos comparados tienen el mismo valor en todos sus campos y false si no& %s
decirB la comparacin entre estructuras con ESuals;< se reali/a por valor&
+especto a la implementacin de la igualdad en los tipos de!inidos como estructurasB tam"i,n es
importante tener muy en cuenta @ue el operador && no es en principio aplica"le a las estructuras @ue
de!ina el programador& Si se desea @ue lo tenga (a de d$rsele e*plcitamente una rede!inicin al de!inir
dic(as estructuras&
.o+in! y unbo+in!
)ado @ue toda estructura deriva de S(stem.bjectB (a de ser posi"le a trav,s del polimor!ismo
almacenar o"jetos de estos tipos en o"jetos object& Sin em"argoB esto no puede (acerse directamente
de"ido a las di!erencias sem$nticas y de almacenamiento @ue e*isten entre clases y estructurasA un
object siempre (a de almacenar una re!erencia a un o"jeto en memoria din$mica y una estructura no
tiene por@u, estarlo& Por ello (a de reali/$rsele antes al o"jeto de tipo valor una conversin conocida
como bo)ing& +ecprocamenteB al proceso de conversin de un object @ue contenga un o"jeto de un
tipo valor al tipo valor original se le denomina unbo)ing&
%l proceso de "o*ing es muy sencillo& Consiste en envolver el o"jeto de tipo valor en un o"jeto de un
tipo re!erencia creado espec!icamente para ello& Por ejemploB para un o"jeto de un tipo valor .B el tipo
re!erencia creado sera de la !ormaA
class T_Box
{
T value;
T_Box(T t)
{
value = t;
}
}
%n realidad todo esto ocurre de !orma transparente al programadorB el cual simplemente asigna el
o"jeto de tipo valor a un o"jeto de tipo re!erencia como si de cual@uier asignacin polimr!ica se
tratase& Por ejemploA
int p = new Punto(10,10);
object o = p; // boxing. Es equivalente a object o = new Punto_Box(p);
%n realidad la clase envoltorio arri"a escrita no se crea nuncaB pero conceptualmente es como si se
crease& %sto se puede compro"ar viendo a trav,s del siguiente cdigo @ue el verdadero tipo del o"jeto o
del ejemplo anterior sigue siendo Punto =y no Puntoa0o*?A
Console.WriteLine((p is Punto));
#a salida por pantalla de este cdigo es .rueB lo @ue con!irma @ue se sigue considerando @ue en
realidad p almacena un Punto =recu,rdese @ue el operador is slo devuelve true si el o"jeto @ue se le
pasa como operando i/@uierdo es del tipo @ue se le indica como operando derec(o?
%l proceso de un"o*ing es tam"i,n transparente al programador& Por ejemploB para recuperar como
Punto el valor de tipo Punto almacenado en el o"jeto o anterior se (araA
p = (Punto) o; // Es equivalente a ((Punto_Box) o).value
O"viamente durante el un"o*ing se (ar$ una compro"acin de tipo para asegurar @ue el o"jeto
almacenado en o es realmente de tipo Punto& %sta compro"acin es tan estricta @ue se (a de cumplir
@ue el tipo especi!icado sea e*actamente el mismo @ue el tipo original del o"jetoB no vale @ue sea un
compati"le& Por tantoB este cdigo es inv$lidoA
int i = 123;
object o = i;
long l = (long) o // Error: o contiene un int, no un long
Sin em"argoB lo @ue si sera v$lido es (acerA
long l = (long) (int) o;
Como se puede apreciar en el constructor del tipo envoltorio creadoB durante el "o*ing el envoltorio
@ue se crea reci"e una copia del valor del o"jeto a convertirB por lo @ue los cam"ios @ue se le (agan no
a!ectar$n al o"jeto original& Por elloB la salida del siguiente cdigo ser$ F:A
Punto p = new Punto(10,10);
object o = p; // boxing
p.X = 100;
Console.WriteLine( ((Punto) o).X); // unboxing
Sin em"argoB si Punto se (u"iese de!inido como una clase entonces s @ue se mostrara por pantalla
un F:: ya @ue entonces no se (ara "o*ing en la asignacin de p a o sino @ue se aplicara el mecanismo
de polimor!ismo normalB @ue consiste en tratar p a trav,s de o como si !uese de tipo o"ject pero sin
reali/arse ninguna conversin&
%l pro"lema del "o*ing y el un"o*ing es @ue son procesos lentosB ya @ue implican la creacin y
destruccin de o"jetos envoltorio& Por ello puede interesar evitarlos en a@uellas situaciones donde la
velocidad de ejecucin de la aplicacin sea crticaB y para ello se proponen varias t,cnicasA
Si el pro"lema se de"e al paso de estructuras como par$metros de m,todos gen,ricos @ue tomen
par$metros de tipo objectB puede convenir de!inir so"recargas de esos m,todos @ue en lugar de
tomar objects tomen o"jetos de los tipos estructura @ue en concreto la aplicacin utili/a
- partir de la versin 9&: de C#B se pueden utili/ar las denominadas "lantillas o genKricosB @ue no
son m$s @ue de!iniciones de tipos de datos en las @ue no se indica cu$l es el tipo e*acto de ciertas
varia"les sino @ue se deja en !uncin de par$metros a los @ue puede d$rseles distintos valores al crear
cada o"jeto de ese tipo& -sB en ve/ de crearse o"jetos con m,todos @ue tomen par$metros objectB se
podran ir creando di!erentes versiones del tipo segCn la estructura con la se vaya a tra"ajar& %l Tema
9&: No<edades de C= 9.: e*plica esto m$s detalladamente&
Muc(as veces conviene (acer un"o*ing para poder acceder a miem"ros espec!icos de ciertas
estructuras almacenadas en objectsB aun@ue a continuacin vuelva a necesitarse realmacenar la
estructura en un object& Para evitar esto una posi"ilidad sera almacenar en el o"jecto no
directamente la estructura sino un o"jeto de una clase envolvente creada a medida por el
programador y @ue incluya los miem"ros necesarios para (acer las operaciones anteriores& -s
se evitara tener @ue (acer un"o*ingB pues se convertira de object a esa claseB @ue no es un tipo
valor y por tanto no implica un"o*ing&
Con la misma ideaB otra posi"ilidad sera @ue el tipo estructura implementase ciertas inter!aces
mediante las @ue se pudiese (acer las operaciones antes comentadas& -un@ue las inter!aces no
se tratar$n (asta el Tema &5: "#ter3a%esB por a(ora "asta sa"er @ue las inter!aces son tam"i,n
tipos re!erencia y por tanto convertir de object a un tipo inter!a/ no implica un"o*ing&
Constructores de estructuras
#os constructores de las estructuras se comportan de una !orma distinta a los de las clases& Por un
ladoB no pueden incluir ningCn iniciali/ador "ase de"ido a @ue como no puede (a"er (erencia el
compilador siempre sa"e @ue (a de llamar al constructor sin par$metros de S(stem./alueT("e& Por
otroB dentro de su cuerpo no se puede acceder a sus miem"ros (asta iniciali/arlosB pues para a(orrar
tiempo no se les da ningCn valor inicial antes de llamar al constructor&
Sin em"argoB la di!erencia m$s importante entre los constructores de am"os tipos se encuentra en la
implementacin del constructor sin par$metrosA como los o"jetos estructura no pueden almacenar el
valor por de!ecto null cuando se declaran sin usar constructor ya @ue ese valor indica re!erencia a
posicin de memoria din$mica indeterminada y los o"jetos estructura no almacenan re!erenciasB toda
estructura siempre tiene de!inido un constructor sin par$metros @ue lo @ue (ace es darle en esos casos
un valor por de!ecto a los o"jetos declarados& %se valor consiste en poner a cero toda la memoria
ocupada por el o"jetoB lo @ue tiene el e!ecto de dar como valor a cada campo el cero de su tipoRF9S& Por
ejemploB el siguiente cdigo imprime un : en pantallaA
Punto p = new Punto();
Console.WriteLine(p.X);
W el siguiente tam"i,nA
using System;
struct Punto
{
public int X,Y;
}
class EjemploConstructorDefecto
{
)unto p;
public static void Main()
{
Console.WriteLine(p.X);
}
}
Sin em"argoB el (ec(o de @ue este constructor por de!ecto se apli@ue no implica @ue se pueda
acceder a las varia"les locales sin antes iniciali/arlas con otro valor& Por ejemploB el siguiente
!ragmento de cdigo de un m,todo sera incorrectoA
Punto p;
Console.WriteLine(p.X); // X no inicializada
Sin em"ragoB como a las estructuras declaradas sin constructor no se les da el valor por de!ecto nullB
s @ue sera v$lidoA
Punto p;
p.X = 2;
Console.WriteLine(p.X);
Para asegurar un valor por de!ecto comCn a todos los o"jetos estructuraB se pro(i"e a los
programadores darles su propia de!inicin del constructor sin par$metros& Mientras @ue en las clases es
opcional implementarlo y si no se (ace el compilador introduce uno por de!ectoB en las estructuras no
es v$lido (acerlo& -dem$sB aCn en el caso de @ue se de!inan otros constructoresB el constructor sin
par$metros seguir$ siendo introducido autom$ticamente por el compilador a di!erencia de cmo ocurra
con las clases donde en ese caso el compilador no lo introduca&
Por otro ladoB para conseguir @ue el valor por de!ecto de todos los o"jetos estructuras sea el mismoB
se pro("e darles una valor inicial a sus campos en el momento de declararlosB pues si no el constructor
por de!ecto (a"ra de tenerlos en cuenta y su ejecucin sera m$s ine!iciente& Por esta ra/nB los
constructores de!inidos por el programador para una estructura (an de iniciali/ar todos sus miem"ros
no est$ticos en tanto @ue antes de llamarlos no se les da ningCn valor inicial&
8tese @ue de"ido a la e*istencia de un constructor por de!ecto cuya implementacin escapa de
manos del programadorB el cdigo de los m,todos de una estructura puede tener @ue considerar la
posi"ilidad de @ue se acceda a ellos con los valores resultantes de una iniciali/acin con ese
constructor& Por ejemploB dadoA
struct A
{
public readonly string S;

public A(string s)
{
if (s==null)
throw (new ArgumentNullException());
this.S = s;
}
}
8ada asegura @ue en este cdigo los o"jetos de clase - siempre se inicialicen con un valor distinto
de null en su campo SB pues aun@ue el constructor de!inido para - comprue"a @ue eso no ocurra
lan/ando una e*cepcin en caso de @ue se le pase una cadena @ue valga nullB si el programador usa el
constructor por de!ecto crear$ un o"jeto en el @ue S valga null& -dem$sB ni si@uiera es v$lido
especi!icar un valor inicial a S en su de!inicinB ya @ue para iniciali/ar r$pidamente las estructuras sus
campos no est$ticos no pueden tener valores iniciales&
Enumeraciones
Concepto de enumeraci%n
1na enumeraci!n o ti"o enumerado es un tipo especial de estructura en la @ue los literales de los
valores @ue pueden tomar sus o"jetos se indican e*plcitamente al de!inirla& Por ejemploB una
enumeracin de nom"re .ama7o cuyos o"jetos pudiesen tomar los valores literales Pe@ue7oB Mediano
o ;rande se de!inira asA

enum Tamao
{
Pequeo,
Mediano,
Grande
}
Para entender "ien la principal utilidad de las enumeraciones vamos a ver antes un pro"lema muy
tpico en programacinA si @ueremos de!inir un m,todo @ue pueda imprimir por pantalla un cierto te*to
con di!erentes tama7osB una primera posi"ilidad sera dotarlo de un par$metro de algCn tipo entero @ue
indi@ue el tama7o con el @ue se desea mostrar el te*to& - estos nCmeros @ue los m,todos interpretan
con signi!icados espec!icos se les suele denominar nWmeros m$gicosB y su utili/acin tiene los
inconvenientes de @ue di!iculta la legi"ilidad del cdigo =(ay @ue recordar @u, signi!ica para el m,todo
cada valor del nCmero? y su escritura =(ay @ue recordar @u, nCmero (a pas$rsele al m,todo para @ue
!uncione de una cierta !orma?
1na alternativa mejor para el m,todo anterior consiste en de!inirlo de modo @ue tome un par$metro
de tipo .ama7o para @ue as el programador usuario no tenga @ue recordar la correspondencia entre
tama7os y nCmeros& V,ase as como la llamada =9? del ejemplo @ue sigue es muc(o m$s legi"le @ue la
=F?A
obj.MuestraTexto(2); // (1)
obj.MuestraTexto(Tamao.Mediano); // (2)
-dem$sB estos literales no slo !acilitan la escritura y lectura del cdigo sino @ue tam"i,n pueden ser
usados por (erramientas de documentacinB depuradores u otras aplicaciones para sustituir nCmeros
m$gicos y mostrar te*tos muc(os m$s legi"les&
Por otro ladoB usar enumeraciones tam"i,n !acilita el mantenimiento del cdigo& Por ejemploB si el
m,todo =F? anterior se (u"iese de!inido de !orma @ue F signi!icase tama7o pe@ue7oB 9 mediano y O
grandeB cuando se @uisiese incluir un nuevo tama7o intermedio entre pe@ue7o y mediano (a"ra @ue
darle un valor superior a O o in!erior a F ya @ue los dem$s estaran cogidosB lo @ue rompera el orden de
menor a mayor entre nCmeros y tama7os asociados& Sin em"argoB usando una enumeracin no
importara mantener el orden relativo y "astara a7adirle un nuevo literal&
Otra ventaja de usar enumeraciones !rente a nCmeros m$gicos es @ue ,stas participan en el
mecanismo de compro"acin de tipos de C# y el C#+& -sB si un m,todo espera un o"jeto .ama7o y se
le pasa uno de otro tipo enumerado se producir$B segCn cuando se detecte la inco(erenciaB un error en
compilacin o una e*cepcin en ejecucin& Sin em"argoB si se (u"iesen usado nCmeros m$gicos del
mismo tipo en ve/ de enumeraciones no se (a"ra detectado nadaB pues en am"os casos para el
compilador y el C#+ seran simples nCmeros sin ningCn signi!icado especial asociado&
'efinici%n de enumeraciones
Wa (emos visto un ejemplo de cmo de!inir una enumeracin& Sin em"argoB la sinta*is completa @ue
se puede usar para de!inirlas esA
enum <nombreEnumeracin> : <tipoBase>
{
<literales>
}
%n realidad una enumeracin es un tipo especial de estructura =luego S(stem./alueT("e ser$ tipo
padre de ella? @ue slo puede tener como miem"ros campos pC"licos constantes y est$ticos& %sos
campos se indican en B y como sus modi!icadores son siempre los mismos no (ay @ue especi!icarlos =de
(ec(oB es errneo (acerlo?
%l tipo por de!ecto de las constantes @ue !orman una enumeracin es intB aun@ue puede d$rseles
cual@uier otro tipo "$sico entero =b(teB sb(teB shortB ushortB uintB intB long o ulong? indic$ndolo en
jtipo0ase6& Cuando se (aga esto (ay @ue tener muy presente @ue el compilador de C# slo admite @ue
se indi@uen as los alias de estos tipos "$sicosB pero no sus nom"res reales =S(stem.=(teB
S(stem.S=(teB etc&?
Si no se especi!ica valor inicial para cada constanteB el compilador les dar$ por de!ecto valores @ue
empiecen desde : y se incrementen en una unidad para cada constante segCn su orden de aparicin en
la de!inicin de la enumeracin& -sB el ejemplo del principio del tema es e@uivalente aA

enum Tamao:int
{
Pequeo = 0,
Mediano = 1,
Grande = 2
}
%s posi"le alterar los valores iniciales de cada constante indic$ndolos e*plcitamente como en el
cdigo reci,n mostrado& Otra posi"ilidad es alterar el valor "ase a partir del cual se va calculando el
valor de las siguientes constantes como en este otro ejemploA

enum Tamao
{
Pequeo,
Mediano = 5,
Grande
}
%n este Cltimo ejemplo el valor asociado a Pe@ue7o ser$ :B el asociado a Mediano ser$ VB y el
asociado a ;rande ser$ Z ya @ue como no se le indica e*plcitamente ningCn otro se considera @ue este
valor es el de la constante anterior m$s F&
O"viamenteB el nom"re @ue se de a cada constante (a de ser di!erente al de las dem$s de su misma
enumeracin y el valor @ue se de a cada una (a de estar incluido en el rango de valores admitidos por
su tipo "ase& Sin em"argoB nada o"liga a @ue el valor @ue se de a cada constante tenga @ue ser di!erente
al de las dem$sB y de (ec(o puede especi!icarse el valor de una constante en !uncin del valor de otra
como muestra este ejemploA

enum Tamao
{
Pequeo,
Mediano = Pequeo,
Grande = Pequeo + Mediano
}
%n realidadB lo Cnico @ue importa es @ue el valor @ue se d, a cada literalB si es @ue se le da alguno
e*plcitamenteB sea una e*presin constante cuyo resultado se encuentre en el rango admitido por el
tipo "ase de la enumeracin y no provo@ue de!iniciones circulares& Por ejemploB la siguiente de!inicin
de enumeracin es incorrecta ya @ue en ella los literales Pe@ue7o y Mediano se (an de!inido
circularmenteA

enum TamaoMal
{
Pequeo = Mediano,
Mediano = Pequeo,
Grande
}
8tese @ue tam"i,n la siguiente de!inicin de enumeracin tam"i,n sera incorrecta ya @ue en ella el
valor de 0 depende del de - implcitamente =sera el de - m$s F?A
enum EnumMal
{
A = B,
B
}
/so de enumeraciones
#as varia"les de tipos enumerados se de!inen como cual@uier otra varia"le =sinta*is jnom"re.ipo6
jnom"reVaria"le6? Por ejemploA
Tamao t;
%l valor por de!ecto para un o"jeto de una enumeracin es :B @ue puede o no corresponderse con
alguno de los literales de!inidos para ,sta& -sB si la t del ejemplo !uese un campo su valor sera
.ama7o&Pe@ue7o& .am"i,n puede d$rsele otro valor al de!inirlaB como muestra el siguiente ejemplo
donde se le da el valor .ama7o&;randeA
Tamao t = Tamao.Grande; // Ahora t vale Tamao.Grande
8tese @ue a la (ora de (acer re!erencia a los literales de una enumeracin se usa la sinta*is
jnom"re%numeracin6.jnom"re#iteral6B como es lgico si tenemos en cuenta @ue en realidad los
literales de una enumeracin son constantes pu"licas y est$ticasB pues es la sinta*is @ue se usa para
acceder a ese tipo de miem"ros& %l Cnico sitio donde no es necesario preceder el nom"re del literal de
jnom"re%numeracin6. es en la propia de!inicin de la enumeracinB como tam"i,n ocurre con
cual@uier constante est$tica&
%n realidad los literales de una enumeracin son constantes de tipos enteros y las varia"les de tipo
enumerado son varia"les del tipo entero "ase de la enumeracin& Por eso es posi"le almacenar valores
de enumeraciones en varia"les de tipos enteros y valores de tipos enteros en varia"les de
enumeraciones& Por ejemploA
int i = Tamao.Pequeo; // Ahora i vale 0
Tamao t = (Tamao) 0; // Ahora t vale Tamao.Pequeo (=0)
t = (Tamao) 100; // Ahora t vale 100, que no se corresponde
// con ningn literal
Como se ve en el Cltimo ejemploB tam"i,n es posi"le darle a una enumeracin valores enteros @ue
no se correspondan con ninguno de sus literales&
)ado @ue los valores de una enumeracin son enterosB es posi"le aplicarles muc(as de las
operaciones @ue se pueden aplicar a los mismosA &&B ,&B HB IB H&B I&B *B +B PB NB OB QB **B ++ y sizeof&
Sin em"argoB (ay @ue concretar @ue los operadores "inarios * y M no pueden aplicarse entre dos
operandos de enumeracionesB sino @ue al menos uno de ellos (a de ser un tipo enteroJ y @ue OB N y P
slo pueden aplicarse entre enumeraciones&
La clase #ystem$Enum
.odos los tipos enumerados derivan de S(stem.EnumB @ue deriva de S(stem./alueT("e y ,sta a su
ve/ deriva de la clase primigenia S(stem.bject& -parte de los m,todos (eredados de estas clases
padres ya estudiadosB toda enumeracin tam"i,n dispone de otros m,todos (eredados de
S(stem.EnumB los principales de los cuales sonA
static T("e getJnderl(ingT("e;T("e enum<A )evuelve un o"jeto S(stem.T("e con
in!ormacin so"re el tipo "ase de la enumeracin representada por el o"jeto S(stem.T("e @ue
se le pasa como par$metroRFOS&
string ToString;string formato<A Cuando a un o"jeto de un tipo enumerado se le aplica el
m,todo ToString;< (eredado de objectB lo @ue se muestra es una cadena con el nom"re del
literal almacenado en ese o"jeto& Por ejemplo =ntese @ue 9rite:ine;< llama autom$ticamente
al ToString;< de sus argumentos no string?A
Tamao t = Color.Pequeo;
Console.WriteLine(t); // Muestra por pantalla la cadena "Pequeo"
Como tam"i,n puede resultar interasante o"tener el valor num,rico del literalB se (a so"recargado
S(stem.Enum el m,todo anterior para @ue tome como par$metro una cadena @ue indica cmo se desea
mostrar el literal almacenado en el o"jeto& Si esta cadena es nulaB vaca o vale g;g muestra el literal
como si del m,todo ToString;< est$ndar se trataseB pero si vale g)g o gPg lo @ue muestra es su valor
num,rico =en decimal si vale g)g y en (e*adecimal si vale gPg? Por ejemploA

Console.WriteLine(t.ToString("X")); // Muestra 0
Console.WriteLine(t.ToString("G")); // Muestra Pequeo
%n realidadB los valores de !ormato son insensi"les a la capitali/acin y da igual si en ve/ de g;g se usa
ggg o si en ve/ de gPg se usa g*g&
static string Dormat;T("e enumU object valor:iteralU string formato<A unciona de !orma
parecida a la so"recarga de ToString;< recien vistaB slo @ue a(ora no es necesario disponer de
ningCn o"jeto del tipo enumerado cuya representacin de literal se desea o"tener sino @ue "asta
indicar el o"jeto T("e @ue lo representa y el nCmero del literal a o"tener& Por ejemploA
Console.Write(Enum.Format(typeof(Tamao), 0, "G"); // Muestra Pequeo
Si el valor#iteral indicado no estuviese asociado a ningCn literal del tipo enumerador representado por
enumB se devolvera una cadena con dic(o nCmero& Por el contrarioB si (u"iesen varios literales en la
enumeracin con el mismo valor num,rico asociadoB lo @ue se devolvera sera el nom"re del declarado
en Cltimo lugar al de!inir la enumeracin&
static object 1arse;T("e enumU string nombre+ *ool mayusculas:<: Crea un o"jeto de un tipo
enumerado cuyo valor es el correspondiente al literal de nom"re asociado nom"re& Si la
enumeracin no tuviese ningCn literal con ese nom"re se lan/ara una FrgumentE)ce"tionB y
para determinar cmo se (a de "uscar el nom"re entre los literales de la enumeracin se utili/a
el tercer par$metro =es opcional y por de!ecto vale false? @ue indica si se (a de ignorar la
capitali/acin al "uscarlo& 1n ejemplo del uso de este m,todo esA
Tamao t = (Tamao) Enum.Parse(typeof(Tamao), "Pequeo");
Console.WriteLine(t) // Muestra Pequeo
-parte de crear o"jetos a partir del nom"re del literal @ue almacenar$nB 1arse;< tam"i,n permite
crearlos a partir del valor num,rico del mismo& Por ejemploA
Tamao t = (Tamao) Enum.Parse(typeof(Tamao), "0");
Console.WriteLine(t) // Muestra Pequeo
%n este casoB si el valor indicado no se correspondiese con el de ninguno de los literales de la
enumeracin no saltara ninguna e*cepcinB pero el o"jeto creado no almacenara ningCn literal v$lido&
Por ejemploA
Tamao t = (Tamao) Enum.Parse(typeof(Tamao), "255");
Console.WriteLine(t) // Muestra 255
static object-. #et/alues;T("e enum<A )evuelve una ta"la con los valores de todos los
literales de la enumeracin representada por el o"jeto S(stem.T("e @ue se le pasa como
par$metro& Por ejemploA
object[] tabla = Enum.GetValues(typeof(Tamao));
Console.WriteLine(tabla[0]); // Muestra 0, pues Pequeo = 0
Console.WriteLine(tabla[1]); // Muestra 1, pues Mediano = 1
Console.WriteLine(tabla[2]); // Muestra 1, pues Grande = Pequeo+Mediano
static string #etName;T("e enumU object valor<A )evuelve una cadena con el nom"re del
literal de la enumeracin representada por enum @ue tenga el valor especi!icado en valor& Por
ejemploB este cdigo muestra Pe@ue7o por pantallaA
Console.WriteLine(Enum.GetName(typeof(Tamao), 0)); //Imprime Pequeo
Si la enumeracin no contiene ningCn literal con ese valor devuelve nullB y si tuviese varios con ese
mismo valor devolvera slo el nom"re del Cltimo& Si se @uiere o"tener el de todos es mejor usar
#etNames;<B @ue se usa como #etName;< pero devuelve un string-. con los nom"res de todos los
literales @ue tengan el valor indicado ordenados segCn su orden de de!inicin en la enumeracin&
static bool isEefined ;T("e enumU object valor<A )evuelve un "ooleano @ue indica si algCn
literal de la enumeracin indicada tiene el valor indicado&
Enumeraciones de fla!s
Muc(as veces interesa dar como valores de los literales de una enumeracin Cnicamente valores @ue
sean potencias de dosB pues ello permite @ue mediante operaciones de "its N y O se puede tratar los
o"jetos del tipo enumerado como si almacenasen simult$neamente varios literales de su tipo& - este
tipo de enumeraciones las llamaremos enumeraciones de flagsB y un ejemplo de ellas es el siguienteA
enum ModificadorArchivo
{
Lectura = 1,
Escritura = 2,
Oculto = 4,
Sistema = 8
}
Si @ueremos crear un o"jeto de este tipo @ue represente los modi!icadores de un arc(ivo de lectura5
escritura podramos (acerA
ModificadorArchivo obj =
ModificadorArchivo.Lectura | ModificadorArchivo.Escritura
%l valor del tipo "ase de la enumeracin @ue se (a"r$ almacenado en o"j es OB @ue es el resultado de
(acer la operacin O+ entre los "its de los valores de los literales #ectura y %scritura& -l ser los
literales de Modi!icador-rc(ivo potencias de dos slo tendr$n un Cnico "it a F y dic(o "it ser$
di!erente en cada uno de ellosB por lo @ue la Cnica !orma de generar un O =Cltimos dos "its a F?
com"inando literales de Modi!icador-rc(ivo es com"inando los literales #ectura =Cltimo "it a F? y
%scritura =penCltimo "it a F? Por tantoB el valor de o"j identi!icar$ unvocamente la com"inacin de
dic(os literales&
)e"ido a esta com"ina"ilidad no se de"e determinar el valor literal de los o"jetos
Modi!icador-rc(ivo tal y como si slo pudiesen almacenar un Cnico literalB pues su valor num,rico no
tendra por@u, corresponderse con el de ningCn literal de la enumeracin Por ejemploA
bool permisoLectura = (obj == ModificadorArchivo.Lectura);// false
-un@ue los permisos representados por o"j incluan permiso de lecturaB se devuelve false por@ue el
valor num,rico de o"j es O y el del Modi!icador-rc(ivo&#ectura es F& Si lo @ue @ueremos es compro"ar
si o"j contiene permiso de lecturaB entonces (a"r$ @ue usar el operador de "its N para aislarlo del resto
de literales com"inados @ue contieneA

bool permisoLectura =
(ModificadorArchivo.Lectura == (obj & ModificadorArchivo.Lectura));//true
OB lo @ue es lo mismoA

bool permisoLectura = ( (obj & ModificadorArchivo.Lectura) != 0);//true
-simismoB si directamente se intenta mostrar por pantalla el valor de un o"jeto de una enumeracin
@ue almacene un valor @ue sea com"inacin de literalesB no se o"tendr$ el resultado esperado =nom"re
del literal correspondiente a su valor? Por ejemploB dadoA
Console.Write(obj); // Muestra 3
Se mostrar$ un O por pantalla ya @ue en realidad ningCn literal de Modi!icador-rc(ivo tiene
asociado dic(o valor& Como lo natural sera @ue se desease o"tener un mensaje de la !orma #ecturaB
%scrituraB los m,todos ToString;< y Dormat;< de las enumeraciones ya vistos admiten un cuarto valor
gg para su par$metro !ormato =su nom"re viene de !lags? con el @ue se consigue lo anterior& Por tantoA

Console.Write(obj.ToString("F")); // Muestra Lectura, Escritura
%sto se de"e a @ue cuando Dormat;< detecta este indicador =ToString;< tam"i,nB pues para generar
la cadena llama internamente a Dormat;<? y el literal almacenado en el o"jeto no se corresponde con
ninguno de los de su tipo enumeradoB entonces lo @ue (ace es mirar uno por uno los "its a uno del valor
num,rico asociado de dic(o literal y a7adirle a la cadena a devolver el nom"re de cada literal de la
enumeracin cuyo valor asociado slo tenga ese "it a unoB us$ndo como separador entre nom"res un
car$cter de coma&
8tese @ue nada o"liga a @ue los literales del tipo enumerado tengan por@u, (a"erse de!inido como
potencias de dosB aun@ue es lo m$s conveniente para @ue gg sea CtilB pues si la enumeracin tuviese
algCn literal con el valor del o"jeto de tipo enumerado no se reali/ara el proceso anterior y se
devolvera slo el nom"re de ese literal&
Por otro ladoB si alguno de los "its a F del valor num,rico del o"jeto no tuviese el correspondiente
literal con slo ese "it a F en la enumeracin no se reali/ara tampoco el proceso anterior y se
devolvera una cadena con dic(o valor num,rico&
1na posi"ilidad m$s cmoda para o"tener el mismo e!ecto @ue con gg es marcar la de!inicin de la
enumeracin con el atri"uto DlagsB con lo @ue ni si@uiera sera necesario indicar !ormato al llamar a
ToString;< O seaB si se de!ine Modi!icador-rc(ivo asA

[8lags]
enum ModificadorArchivo
{
Lectura = 1,
Escritura = 2,
Oculto = 4,
Sistema = 8
}

%ntonces la siguiente llamada producir$ como salida #ecturaB %scrituraA
Console.Write(obj); // Muestra Lectura, Escritura
%sto se de"e a @ue en ausencia del modi!icador ggB Dormat;< mira dentro de los metadatos del tipo
enumerado al @ue pertenece el valor num,rico a mostrar si ,ste dispone del atri"uto Dlags& Si es as
!unciona como si se le (u"iese pasado gg&
.am"i,n ca"e destacar @ueB para crear o"jetos de enumeraciones cuyo valor sea una com"inacin de
valores de literales de su tipo enumeradoB el m,todo m,todo 1arse;< de Enum permite @ue la cadena
@ue se le especi!ica como segundo par$metro cuente con mCltiples literales separados por comas& Por
ejemploB un o"jeto Modi!icador-rc(ivo @ue represente modi!icadores de lectura y ocultacin puede
crearse conA
ModificadorArchivo obj =
(ModificadorArchivo) Enum.Parse(typeof(ModificadorArchivo)
,"Lectura,Oculto"));
Hay @ue se7alar @ue esta capacidad de crear o"jetos de enumeraciones cuyo valor almacenado sea
una com"inacin de los literales de!inidos en dic(a enumeracin es totalmente independiente de si al
de!inirla se utili/ el atri"uto Dlags o no&
Interfaces
Concepto de interfa*
1na interfaz es la de!inicin de un conjunto de m,todos para los @ue no se da implementacinB sino
@ue se les de!ine de manera similar a como se de!inen los m,todos a"stractos& %s m$sB una inter!a/
puede verse como una !orma especial de de!inir clases a"stractas @ue tan slo contengan miem"ros
a"stractos&
Como las clases a"stractasB las inter!aces son tipos re!erenciaB no puede crearse o"jetos de ellas sino
slo de tipos @ue deriven de ellasB y participan del polimor!ismo& Sin em"argoB tam"i,n tienen
numerosas di!erencias con ,stasA
Es "osible definir ti"os Sue deriven de m$s de una interfaz& %sto se de"e a @ue los
pro"lemas @ue se podran presentar al crear tipos @ue (ereden de varios padres se de"en a la
di!cil resolucin de los con!lictos derivados de la (erencia de varias implementaciones
di!erentes de un mismo m,todo& Sin em"argoB como con las inter!aces esto nunca podr$ ocurrir
en tanto @ue no incluyen cdigoB se permite la (erencia mCltiple de las mismas&
#as estructuras no pueden (eredar de clases pero s de inter!acesB y las inter!aces no pueden
derivar de clasesB pero s de otras inter!aces&
.odo tipo @ue derive de una inter!a/ (a de dar una implementacin de todos los miem"ros @ue
(ereda de estaB y no como ocurre con las clases a"stractas donde es posi"le no darla si se de!ine
como a"stracta tam"i,n la clase (ija& )e esta manera @ueda de!inido un contrato en la clase @ue
la (ereda @ue va a permitir poder usarla con seguridad en situaciones polimr!icasA toda clase
@ue (erede una inter!a/ implementar$ todos los m,todos de la misma& Por esta ra/n se suele
denominar im"lementar una inter!a/ al (ec(o de (eredar de ella&
8tese @ue de"ido a estoB no suele convenir ampliar inter!aces ya de!inidas e implementadasB puesto
@ue cual@uier a7adido invalidar$ sus implementaciones (asta @ue se de!ina en las mismas un
implementacin para dic(o a7adido& Sin em"argoB si se (ereda de una clase a"stracta este pro"lema no
se tendr$ siempre @ue el miem"ro a7adido a la clase a"stracta no sea a"stracto&
#as inter!aces slo pueden tener como miem"ros m,todos normalesB eventosB propiedades e
indi/adoresJ pero no pueden incluir de!iniciones de camposB operadoresB constructoresB
destructores o miem"ros est$ticos& -dem$sB todos los miem"ros de las inter!aces son
implcitamente pC"licos y no se les puede dar ningCn modi!icador de acceso =ni si@uiera "ublicB
pues se supone?
'efinici%n de interfaces
#a sinta*is general @ue se sigue a la (ora de de!inir una inter!a/ esA
<modificadores> interface <nombre>:<interfacesBase>
{
<miembros>
}
#os jmodi!icadores6 admitidos por las inter!aces son los mismos @ue los de las clases %s decirB
"ublicU internalU "rivateU "rotectedU "rotected internal o ne% =e igualmenteB los cuatro Cltimos slo
son aplica"les a inter!aces de!inidas dentro de otros tipos?
%l jnom"re6 de una inter!a/ puede ser cual@uier identi!icador v$lidoB aun@ue por convenio se suele
usar I como primer car$cter del mismo =ICompara"leB I-B etc?
#os jmiem"ros6 de las inter!aces pueden ser de!iniciones de m,todosB propiedadesB indi/adores o
eventosB pero no camposB operadoresB constructores o destructores& #a sinta*is @ue se sigue para de!inir
cada tipo de miem"ro es la misma @ue para de!inirlos como a"stractos en una clase pero sin incluir
abstract por suponerse implcitamenteA
MKtodos: jtipo+etorno6 jnom"reM,todo6;+!ar2metros,<T
1ro"iedades: jtipo6 jnom"rePropiedad6 Zse!; ge!;[
#os "lo@ues get y set pueden intercam"iarse y puede no incluirse uno de ellos =propiedad de slo
lectura o de slo escritura segCn el caso?B pero no los dos&
Indizadores: jtipo6 this-jndices6. Zse!; ge!;[
-l igual @ue las propiedadesB los "lo@ues set y get pueden intercam"iarse y o"viarse uno de ellos al
de!inirlos&
Eventos: event jdelegado6 jnom"re%vento6T
8tese @ue a di!erencia de las propiedades e indi/adoresB no es necesario indicar nada so"re sus
"lo@ues add y remove& %sto se de"e a @ue siempre se (an de implementar am"osB aun@ue si se usa la
sinta*is "$sica el compilador les da una implementacin por de!ecto autom$ticamente&
Cual@uier de!inicin de un miem"ro de una inter!a/ puede incluir el modi!icador ne% para indicar
@ue pretende ocultar otra (eredada de alguna inter!a/ padre& Sin em"argoB el resto de modi!icadores no
son v$lidos ya @ue implcitamente siempre se considera @ue son "ublic y abstract& -dem$sB una
inter!a/ tampoco puede incluir miem"ros de tipoB por lo @ue es incorrecto incluir el modi!icador static
al de!inir sus miem"ros&
Cada inter!a/ puede (eredar de varias inter!acesB @ue se indicaran en jinter!aces0ase6 separadas
por comas& %sta lista slo puede incluir inter!acesB pero no clases o estructurasJ y a continuacin se
muestra un ejemplo de cmo de!inir una inter!a/ IC @ue (ereda de otras dos inter!aces I- y I0A
public delegate void D (int x);
interface IA
{
int PropiedadA{get;}
void Comn(int x);
}
interface IB
{
int this [int ndice] {get; set;}
void Comn(int x);
}
interface IC: IA, IB
{
event D EventoC;
}
8tese @ue aun@ue las inter!aces padres de IC contienen un m,todo comCn no (ay pro"lema alguno
a la (ora de de!inirlas& %n el siguiente epgra!e veremos cmo se resuelven las am"ig<edades @ue por
esto pudiesen darse al implementar IC&
Implementaci%n de interfaces
Para de!inir una clase o estructura @ue implemente una o m$s inter!aces "asta incluir los nom"res de
las mismas como si de una clase "ase se tratase 5separ$ndolas con comas si son varias o si la clase
de!inida (ereda de otra clase5 y asegurar @ue la clase cuente con de!iniciones para todos los miem"ros
de las inter!aces de las @ue (ereda 5lo @ue se puede conseguir de!ini,ndolos en ella o (ered$ndolos de
su clase padre&
#as de!iniciones @ue se den de miem"ros de inter!aces (an de ser siempre pC"licas y no pueden
incluir overrideB pues como sus miem"ros son implcitamente abstract se so"reentiende& Sin em"argoB
s pueden d$rsele los modi!icadores como virtual abstract y usar override en rede!iniciones @ue se
les den en clases (ijas de la clase @ue implemente la inter!a/&
Cuando una clase deriva de m$s de una inter!a/ @ue incluye un mismo miem"roB la implementacin
@ue se le d, servir$ para todas las inter!aces @ue cuenten con ese miem"ro& Sin em"argoB tam"i,n es
posi"le dar una implementacin di!erente para cada una usando una im"lementaci!n e)"l0citaB lo @ue
consiste en implementar el miem"ro sin el modi!icador "ublic y anteponiendo a su nom"re el nom"re
de la inter!a/ a la @ue pertenece seguido de un punto =car$cter .?
Cuando un miem"ro se implementa e*plcitamenteB no se le pueden dar modi!icadores como en las
implementaciones implcitasB ni si@uiera virtual o abstract& 1na !orma de simular los modi!icadores
@ue se necesiten consiste en darles un cuerpo @ue lo @ue (aga sea llamar a otra !uncin @ue s cuente
con esos modi!icadores&
%l siguiente ejemplo muestra cmo de!inir una clase C# @ue implemente la inter!a/ ICA
class CL:IC
{
public int PropiedadA
{
get {return 5;}
set {Console.WriteLine("Asignado{0} a PropiedadA", value);}
}

void IA.Comn(int x)
{
Console.WriteLine("Ejecutado Comn() de IA");
}

public int this[int ndice]
{
get { return 1;}
set { Console.WriteLine("Asignado {0} a indizador", value); }
}

void IB.Comn(int x)
{
Console.WriteLine("Ejecutado Comn() de IB");
}

public event D EventoC;
}

Como se veB para implementar la inter!a/ IC (a sido necesario implementar todos sus miem"rosB
incluso los (eredados de I- y I0B de la siguiente maneraA
-l %ventoC se le (a dado la implementacin por de!ectoB aun@ue si se @uisiese se podra (a"er
dado una implementacin espec!ica a sus "lo@ues add y remove&
-l m,todo ComCn=? se le (a dado una implementacin para cada versin (eredada de una de las
clases padre de ICB us$ndose para ello la sinta*is de implementacin e*plcita antes comentada&
8tese @ue no se (a incluido el modi!icador "ublic en la implementacin de estos miem"ros&
- la Propiedad- se le (a dado una implementacin con un "lo@ue set @ue no apareca en la
de!inicin de Propiedad- en la inter!a/ I-& %sto es v$lido (acerlo siempre y cuando la
propiedad no se (aya implementado e*plcitamenteB y lo mismo ocurre con los indi/adores y en
los casos en @ue en ve/ de set sea get el "lo@ue e*tra implementado&
Otra utilidad de las implementaciones e*plcitas es @ue son la Cnica manera de conseguir poder dar
implementacin a m,todos ocultados en las de!iniciones de inter!aces& Por ejemploB si tenemosA
interface IPadre
{
int P{get;}
}
interface IHija:Padre
{
new int P();
}
#a Cnica !orma de poder de!inir una clase donde se d, una implementacin tanto para el m,todo P=?
como para la propiedad PB es usando implementacin e*plcita asA
class C: IHija
{
void IPadre.P {}
public int P() {.}
}
O asA
class C: IHija
{
public void P() {}
int IHija.P() {}
}
O asA
class C: IHija
{
void IPadre.P() {}
int IHija.P() {}
}
Pero como no se puede implementar es sin ninguna implementacin e*plcitaB pues se producira un
error al tener am"os miem"ros las misma signatura& %s decirB la siguiente de!inicin no es correctaA
class C: IHija
{
public int P() {} // ERROR: Ambos miembros tienen la misma signatura
public void P(){}
}
%s posi"le reimplementar en una clase (ija las de!iniciones @ue su clase padre diese para los m,todos
@ue (ered de una inter!a/& Para (acer eso "asta (acer @ue la clase (ija tam"i,n (erede de esa inter!a/ y
dar en ella las de!iniciones e*plcitas de miem"ros de la inter!a/ @ue se estimen convenientesB
consider$ndose @ue las implementaciones para los dem$s ser$n las (eredadas de su clase padre& Por
ejemploA
using System;

interface IA
{
void F();
}

class C1: IA
{
public void F()
{
Console.WriteLine("El F() de C1");
}
}

class C2: C1, IA
{// Sin implementacin explcita no redefinira, sino ocultara
void IA.F()
{
Console.WriteLine("El F() de C2");
}

public static void Main()
{
IA obj = new C1();
IA obj2 = new C2();
obj.F();
obj2.F();
}

+eimplementar un miem"ro de una inter!a/ de esta manera es parecido a rede!inir los miem"ros
reimplementadosB slo @ue a(ora la rede!inicin sera solamente accesi"le a trav,s de varia"les del tipo
de la inter!a/& -sB la salida del ejemplo anterior seraA

%l =? de CF
%l =? de C9

Hay @ue tener en cuenta @ue de esta manera slo pueden (acerse reimplementaciones de miem"ros si
la clase donde se reimplementa (ereda directamente de la inter!a/ implementada e*plcitamente o de
alguna inter!a/ derivada de ,sta& -sB en el ejemplo anterior sera incorrecto (a"er (ec(oA

class C2:C1 //La lista de herencias e interfaces implementadas por C2 slo
incluye a C1
{
void IA.f(); // ERROR: Aunque C1 herede de IA, IA no se incluye
directamente
// en la lista de interfaces implementadas por C2
}
%s importante se7alar @ue el nom"re de inter!a/ especi!icado en una implementacin e*plcita (a de
ser e*actamente el nom"re de la inter!a/ donde se de!ini el miem"ro implementadoB no el de alguna
su"clase de la misma& Por ejemploA
interface I1
{
void F()
}
interface I2:I1
{}
class C1:I2
{
public void I2.F(); //ERROR: habra que usar I1.F()
}
%n el ejemplo anteriorB la lnea comentada contiene un error de"ido a @ue =? se de!ini dentro de la
inter!a/ IFB y aun@ue tam"i,n pertene/ca a I9 por@ue ,sta lo (ereda de IFB a la (ora de implementarlo
e*plcitamente (ay @ue pre!ijar su nom"re de IFB no de I9&
,cceso a miembros de una interfa*
Se puede acceder a los miem"ros de una inter!a/ implementados en una clase de manera no e*plcita
a trav,s de varia"les de esa clase como si de miem"ros normales de la misma se tratase& Por ejemploB
este cdigo mostrara un cinco por pantallaA
CL c = new CL();
Console.WriteLine(c.PropiedadA);
Sin em"argoB tam"i,n es posi"le de!inir varia"les cuyo tipo sea una inter!a/& -un@ue no e*isten
constructores de inter!acesB estas varia"les pueden iniciali/arse gracias al polimor!ismo asign$ndoles
o"jetos de clases @ue implementen esa inter!a/& -sB el siguiente cdigo tam"i,n mostrara un cinco por
pantallaA
IA a = new CL();
Console.WriteLine(a.PropiedadA);
8tese @ue a trav,s de una varia"le de un tipo inter!a/ slo se puede acceder a miem"ros del o"jeto
almacenado en ella @ue est,n de!inidos en esa inter!a/& %s decirB los Cnicos miem"ros v$lidos para el
o"jeto a anterior seran Propiedad- y ComCn=?
%n caso de @ue el miem"ro al @ue se pretenda acceder (aya sido implementado e*plcitamenteB slo
puede accederse a ,l a trav,s de varia"les del tipo inter!a/ al @ue pertenece y no a trav,s de varia"les de
tipos @ue (ereden de ellaB ya @ue la de!inicin de estos miem"ros es privada al no llevar modi!icador de
acceso& Por ejemploA
CL cl = new CL();
IA a = cl;
IB b = cl;
// Console.WriteLine(cl.Comn()); // Error: Comn()
// fue implementado explcitamente
Console.WriteLine(a.Comn());
Console.WriteLine(b.Comn());
Console.WriteLine(((IA) cl).Comn());
Console.WriteLine(((IB) cl).Comn());
Cada ve/ @ue se llame a un m,todo implementado e*plcitamente se llamar$ a la versin del mismo
de!inida para la inter!a/ a trav,s de la @ue se accede& Por elloB la salida del cdigo anterior ser$A
%jecutado ComCn=? de I-
%jecutado ComCn=? de I0
%jecutado ComCn=? de I-
%jecutado ComCn=? de I0
Se puede dar tanto una implementacin implcita como una e*plcita de cada miem"ro de una
inter!a/& #a e*plcita se usar$ cuando se acceda a un o"jeto @ue implemente esa inter!a/ a trav,s de una
re!erencia a la inter!a/B mientras @ue la implcita se usar$ cuando el acceso se (aga a trav,s de una
re!erencia del tipo @ue implementa la inter!a/& Por ejemploB dado el siguiente cdigoA
interface I
{object Clone();}
class Clase:I
{
public object Clone()
{
Console.WriteLine("Implementacin implcita");
}
public object IClonable.Clone()
{
Console.WriteLine("Implementacin explcita");
}

public static void Main()
{
Clase obj = new Clase();
((I) obj).Clone();
obj.Clone();
}
}
%l resultado @ue por pantalla se mostrar$ tras ejecutarlo esA
Implementacin e*plcita
Implementacin implcita
-cceso a miem"ros de inter!aces y "o*ing
%s importante se7alar @ue aun@ue las estructuras puedan implementar inter!aces tal y como lo (acen las
clasesB el llamarlas a trav,s de re!erencias a la inter!a/ supone una gran p,rdida de rendimientoB ya @ue
como las inter!aces son tipos re!erencia ello implicara la reali/acin del ya visto proceso de "o*ing&
Por ejemploB en el cdigoA
using System;

interface IIncrementable
{ void Incrementar();}

struct Estructura:IIncrementable
{
public int Valor;

public void Incrementar()
{
Valor++;
}

static void Main()
{
Estructura o = new Estructura();
Console.WriteLine(o.Valor);
((IIncrementable) o).Incrementar();
Console.WriteLine(o.Valor);
o.Incrementar();
Console.WriteLine(o.Valor);
}
}
#a salida o"tenida ser$A
:
:
F
)onde ntese @ue el resultado tras la primera llamada a Incrementar=? sigue siendo el mismo ya @ue
como se le (a (ec(o a trav,s de un re!erencia a la inter!a/B (a"r$ sido aplicado so"re la copia de la
estructura resultante del "o*ing y no so"re la estructura original& Sin em"argoB la segunda llamada s
@ue se aplica a la estructura ya @ue se reali/a directamente so"re el o"jeto originalB y por tanto
incrementa su campo Valor&
E+cepciones
Concepto de e*cepcin.
#as e)ce"ciones son el mecanismo recomendado en la plata!orma &8%. para propagar los @ue se
produ/can durante la ejecucin de las aplicaciones =divisiones por ceroB lectura de arc(ivos no
disponi"lesB etc&? 0$sicamenteB son o"jetos derivados de la clase S(stem.E)ce"tion @ue se generan
cuando en tiempo de ejecucin se produce algCn error y @ue contienen in!ormacin so"re el mismo&
%sto es una di!erencia respecto a su implementacin en el CDD tradicional @ue les proporciona una
cierta (omogeneidadB consistencia y sencille/B pues en ,ste podan ser valores de cual@uier tipo&
.radicionalmenteB el sistema @ue en otros lenguajes y plata!ormas se (a venido usando para in!ormar
estos errores consista simplemente en (acer @ue los m,todos en cuya ejecucin pudiesen producirse
devolvieran cdigos @ue in!ormasen so"re si se (an ejecutado correctamente oB en caso contrarioB so"re
cu$l !ue el error producido& Sin em"argoB las e*cepciones proporcionan las siguientes ventajas !rente a
dic(o sistemaA
Claridad: %l uso de cdigos especiales para in!ormar de error suele di!icultar la legi"ilidad del
!uente en tanto @ue se me/clan las instrucciones propias de la lgica del mismo con las
instrucciones propias del tratamiento de los errores @ue pudiesen producirse durante su
ejecucin& Por ejemploA
int resultado = obj.Mtodo();
if (resultado == 0) // Sin errores al ejecutar obj.Mtodo();
{...}
else if (resultado == 1) // Tratamiento de error de cdigo 1
{...}
else if (resultado == 2) // Tratamiento de error de cdigo 2
...

Como se ver$B utili/ando e*cepciones es posi"le escri"ir el cdigo como si nunca se !uesen a producir
errores y dejar en una /ona aparte todo el cdigo de tratamiento de erroresB lo @ue contri"uye a !acilitar
la legi"ilidad de los !uentes&
M$s informaci!n: - partir del valor de un cdigo de error puede ser di!cil deducir las causas
del mismo y conseguirlo muc(as veces implica tenerse @ue consultar la documentacin @ue
proporcionada so"re el m,todo @ue lo provocB @ue puede incluso @ue no especi!i@ue
claramente su causa&
Por el contrarioB una e*cepcin es un o"jeto @ue cuenta con campos @ue descri"en las causas del error y
a cuyo tipo suele d$rsele un nom"re @ue resuma claramente su causa& Por ejemploB para in!ormar
errores de divisin por cero se suele utili/ar una e*cepcin prede!inida de tipo
Eivide=(\eroE)ce"tion en cuyo campo Message se detallan las causas del error producido
Tratamiento asegurado: Cuando se utili/an cdigos de error nada o"liga a tratarlos en cada
llamada al m,todo @ue los pueda producirB e ignorarlos puede provocar m$s adelante en el
cdigo comportamientos inesperados de causas di!ciles de descu"rir&
Cuando se usan e*cepciones siempre se asegura @ue el programador trate toda e*cepcin @ue pueda
producirse o @ueB si no lo (aceB se a"orte la ejecucin de la aplicacin mostr$ndose un mensaje
indicando dnde se (a producido el error&
-(ora "ienB tradicionalmente en lenguajes como CDD el uso de e*cepciones siempre (a tenido las
desventajas respecto al uso de cdigos de error de complicar el compilador y dar lugar a cdigos m$s
lentos y di!ciles de optimi/ar en los @ue tras cada instruccin @ue pudiese producir e*cepciones el
compilador de"e introducir las compro"aciones necesarias para detectarlas y tratarlas as como para
compro"ar @ue los o"jetos creados sean correctamente destruidos si se producen&
Sin em"argoB en la plata!orma &8%. desaparecen los pro"lemas de complicar el compilador y
di!icultar las optimi/aciones ya @ue es el C#+ @uien se encarga de detectar y tratar las e*cepciones y es
su recolector de "asura @uien se encarga asegurar la correcta destruccin de los o"jetos& O"viamente el
cdigo seguir$ siendo algo m$s lentoB pero es un pe@ue7o sacri!icio @ue merece la pena (acer en tanto
@ue ello asegura @ue nunca se producir$n pro"lemas di!ciles de detectar derivados de errores
ignorados&
%a clase S.stem.E*ception
Como ya se (a dic(oB todas las e*cepciones derivan de un tipo prede!inido en la 0C# llamado
S(stem.E)ce"tion& #os principales miem"ros @ue (eredan de ,ste sonA
string Message Zvirtual getT[A Contiene un mensaje descriptivo de las causas de la e*cepcin&
Por de!ecto este mensaje es una cadena vaca =]^?
E)ce"tion InnerE)ce"tion Zvirtual getT[A Si una e*cepcin !ue causada como consecuencia de
otraB esta propiedad contiene el o"jeto S(stem.E)ce"tion @ue representa a la e*cepcin @ue la
caus& -s se pueden !ormar cadenas de e*cepciones de cual@uier longitud& Si se desea o"tener
la Cltima e*cepcin de la cadena es mejor usar el m,todo virtual E)ce"tion
#et=aseE)ce"tion;<
string Stac'Trace Zvirtual getT[: Contiene la pila de llamadas a m,todos @ue se tena en el
momento en @ue se produjo la e*cepcin& %sta pila es una cadena con in!ormacin so"re cu$l es
el m,todo en @ue se produjo la e*cepcinB cu$l es el m,todo @ue llam a esteB cu$l es el @ue
llam a ese otroB etc&
string Source Zvirtual getT virtual setT[A -lmacena in!ormacin so"re cu$l !ue la aplicacin u
o"jeto @ue caus la e*cepcin&
Method=ase TargetSite Zvirtual getT[A -lmacena cu$l !ue el m,todo donde se produjo la
e*cepcin en !orma de o"jeto S(stem.Ceflection.Method=ase& Puede consultar la
documentacin del S)] si desea cmo o"tener in!ormacin so"re las caractersticas del m,todo
a trav,s del o"jeto Method=ase&
string ?el":in' Zvirtual getT[: Contiene una cadena con in!ormacin so"re cu$l es la 1+I
donde se puede encontrar in!ormacin so"re la e*cepcin& %l valor de esta cadena puede
esta"lecerse con virtual E)ce"tion Set?el":in' ;string JCI<B @ue devuelve la e*cepcin
so"re la @ue se aplica pero con la 1+I ya actuali/ada&
Para crear o"jetos de clase S(stem.E)ce"tion se puede usar los constructoresA
E)ce"tion;<
E)ce"tion;string msg<
E)ce"tion;string msgU E)ce"tion causante<
%l primer constructor crea una e*cepcin cuyo valor para Message ser$ ]^ y no causada por ninguna
otra e*cepcin =InnerE)ce"tion valdr$ null? %l segundo la crea con el valor indicado para MessageB y
el Cltimo la crea con adem$s la e*cepcin causante indicada&
%n la pr$cticaB cuando se crean nuevos tipos derivados de S(stem.E)ce"tion no se suele rede!inir
sus miem"ros ni a7adirles nuevosB sino @ue slo se (ace la derivacin para distinguir una e*cepcin de
otra por el nom"re del tipo al @ue pertenecen& -(ora "ienB es conveniente respetar el convenio de darles
un nom"re aca"ado en E)ce"tion y rede!inir los tres constructores antes comentados&
E*cepciones prede"inidas comunes
%n el espacio de nom"res S(stem de la 0C# (ay prede!inidas mCltiples e*cepciones derivadas de
S(stem.E)ce"tion @ue se corresponden con los errores m$s comunes @ue pueden surgir durante la
ejecucin de una aplicacin& %n la Tabla se recogen algunasA
.ipo de la e*cepcin Causa de @ue se produ/ca la e*cepcin
FrgumentE)ce"tion Pasado argumento no v$lido ="ase de e*cepciones de
argumentos?
FrgumentNullE)ce"tion Pasado argumento nulo
FrgumentutfCangeE)ce"tion Pasado argumento !uera de rango
Frra(T("eMistmatchE)ce"tion -signacin a ta"la de elemento @ue no es de su tipo
CME)ce"tion %*cepcin de o"jeto COM
Eivide=(\eroE)ce"tion )ivisin por cero
Inde)utfCangeE)ce"tion qndice de acceso a elemento de ta"la !uera del rango
v$lido =menor @ue cero o mayor @ue el tama7o de la
ta"la?
InvalidCastE)ce"tion Conversin e*plcita entre tipos no v$lida
Invalid"erationE)ce"tion Operacin inv$lida en estado actual del o"jeto
Intero"E)ce"tion 0ase de e*cepciones producidas en comunicacin con
cdigo inseguro
NullCeferenceE)ce"tion -cceso a miem"ro de o"jeto @ue vale null
verflo%E)ce"tion )es"ordamiento dentro de conte*to donde se (a de
compro"ar los des"ordamientos =e*presin constanteB
instruccin chec'edB operacin chec'ed u opcin del
compilador Achec'ed?
utfMemor(E)ce"tion alta de memoria para crear un o"jeto con ne%
SE?E)ce"tion %*cepcin SH% del -PI NinO9
Stac'verflo%E)ce"tion )es"ordamiento de la pilaB generalmente de"ido a un
e*cesivo nCmero de llamadas recurrentes&
T("eInizializationE)ce"tion Ha ocurrido alguna e*cepcin al iniciali/ar los campos
est$ticos o el constructor est$tico de un tipo& %n
InnerE)ce"tion se indica cu$l es&
%*cepciones prede!inidas de uso !recuente
O"viamenteB es conveniente @ue si las aplicaciones @ue escri"amos necesiten lan/ar e*cepciones
relativas a errores de los tipos especi!icados en la Tabla _B lancen precisamente las e*cepciones
indicadas en esa ta"la y no cual@uier otra Hya sea de!inida por nosotros mismos o prede!inida en la
0C# con otro signi!icado&
%an0amiento de e*cepciones. 'nstruccin t)ro(
Para in!ormar de un error no "asta con crear un o"jeto del tipo de e*cepcin apropiadoB sino @ue
tam"i,n (ay pas$rselo al mecanismo de propagacin de e*cepciones del C#+& - esto se le llama
lanzar la e)ce"ci!nB y para (acerlo se usa la siguiente instruccinA
throw <objetoExcepcinALanzar>$
Por ejemploB para lan/ar una e*cepcin de tipo Eivide=(\eroE)ce"tion se podra (acerA
throw new DivideByZeroException();
Si el o"jeto a lan/ar vale nullB entonces se producir$ una NullCeferenceE)ce"tion @ue ser$ lan/ada
en ve/ de la e*cepcin indicada en la instruccin thro%&
Captura de e*cepciones. 'nstruccin tr.
1na ve/ lan/ada una e*cepcin es posi"le escri"ir cdigo @ue es encargue de tratarla& Por de!ectoB si
este cdigo no se escri"e la e*cepcin provoca @ue la aplicacin a"orte mostrando un mensaje de error
en el @ue se descri"e la e*cepcin producida =in!ormacin de su propiedad Message? y dnde se (a
producido =in!ormacin de su propiedad Stac'Trace? -sB dado el siguiente cdigo !uente de ejemploA
using System;

class PruebaExcepciones
{
static void Main()
{
A obj1 = new A();
obj1.F();
}
}

class A
{
public void F()
{
G();
}

static public void G()
{
int c = 0;
int d = 2/c;
}
}
-l compilarlo no se detectar$ ningCn error ya @ue al compilador no le merece la pena calcular el
valor de c en tanto @ue es una varia"leB por lo @ue no detectar$ @ue dividir 9Ic no es v$lido& Sin
em"argoB al ejecutarlo se intentar$ dividir por cero en esa instruccin y ello provocar$ @ue a"orte la
aplicacin mostrando el siguiente mensajeA
1n(andled %*ceptionA System&)ivide0yrero%*ceptionA -ttempted to divide "y /ero
at Prue"a%*cepciones&Main=?
Como se veB en este mensaje se indica @ue no se (a tratado una e*cepcin de divisin por cero =tipo
Eivide=(\eroE)ce"tion? dentro del cdigo del m,todo Main=? del tipo Prue"a%*cepciones& Si al
compilar el !uente (u"i,semos utili/ado la opcin AdebugB el compilador (a"ra creado un !ic(ero ."db
con in!ormacin e*tra so"re las instrucciones del ejecuta"le generado @ue permitira @ue al ejecutarlo
se mostrase un mensaje muc(o m$s detallado con in!ormacin so"re la instruccin e*acta @ue provoc
la e*cepcinB la cadena de llamadas a m,todos @ue llevaron a su ejecucin y el nCmero de lnea @ue
cada una ocupa en el !uenteA
1n(andled %*ceptionA System&)ivide0yrero%*ceptionA -ttempted to divide "y /ero&
at -&;=? in %A\c#\%j\ej&csAline 99
at -&=? in %A\c#\%j\ej&csAline FZ
at Prue"a%*cepciones&Main=? in %A\c#\%j\ej&csAline G
Si se desea tratar la e*cepcin (ay @ue encerrar la divisin dentro de una instrucci!n tr( con la
siguiente sinta*isA

try
<instrucciones>
catch (<excepcin1>)
<tratamiento1>
catch (<excepcin2>)
<tratamiento2>
...
finally
<instruccionesFinally>
%l signi!icado de tr( es el siguienteA si durante la ejecucin de las jinstrucciones6 se lan/a una
e*cepcin de tipo je*cepcinF6 =o alguna su"clase suya? se ejecutan las instrucciones jtratamientoF6B
si !uese de tipo je*cepcin96 se ejecutara jtratamiento96B y as (asta @ue se encuentre una cl$usula
catch @ue pueda tratar la e*cepcin producida& Si no se encontrase ninguna y la instruccin tr(
estuviese anidada dentro de otraB se mirara en los catch de su tr( padre y se repetira el proceso& Si al
!inal se recorren todos los tr( padres y no se encuentra ningCn catch compati"leB entonces se "uscara
en el cdigo desde el @ue se llam al m,todo @ue produjo la e*cepcin& Si as se termina llegando al
m,todo @ue inici el (ilo donde se produjo la e*cepcin y tampoco all se encuentra un tratamiento
apropiado se a"orta dic(o (iloJ y si ese (ilo es el principal =el @ue contiene el punto de entrada? se
a"orta el programa y se muestra el mensaje de error con in!ormacin so"re la e*cepcin lan/ada ya
visto&
-sB para tratar la e*cepcin del ejemplo anterior de modo @ue una divisin por cero provo@ue @ue a
d se le asigne el valor :B se podra rescri"ir ;=? de esta otra !ormaA
static public void G()
{
try
{
int c = 0;
int d = 2/c;
}
catch (DivideByZeroException)
{ d=0; }
}
Para simpli!icar tanto el compilador como el cdigo generado y !avorecer la legi"ilidad del !uenteB
en los catchs se "usca siempre orden de aparicin te*tualB por lo @ue para evitar catchs a"surdos no se
permite de!inir catchs @ue puedan capturar e*cepciones captura"les por catchs posteriores a ellos en su
misma instruccin tr(&
.am"i,n (ay @ue se7alar @ue cuando en jinstrucciones6 se lance una e*cepcin @ue sea tratada por
un catch de algCn tr( 5ya sea de la @ue contiene las jinstrucciones6B de algCn tr( padre suyo o de
alguno de los m,todos @ue provocaron la llamada al @ue produjo la e*cepcin5 se seguir$ ejecutando a
partir de las instrucciones siguientes a ese tr(&
%l "lo@ue finall( es opcionalB y si se incluye (a de (acerlo tras todas los "lo@ues catch& #as
jinstruccionesinally6 de este "lo@ue se ejecutar$n tanto si se producen e*cepciones en
jinstrucciones6 como si no& %n el segundo caso sus instrucciones se ejecutar$n tras las
jinstrucciones6B mientras @ue en el primero lo (ar$n despu,s de tratar la e*cepcin pero antes de
seguirse ejecutando por la instruccin siguiente al tr( @ue la trat& Si en un tr( no se encuentra un
catch compati"leB antes de pasar a "uscar en su tr( padre o en su m,todo llamante padre se ejecutar$n
las jinstruccionesinally6&
Slo si dentro de un "lo@ue finall( se lan/ase una e*cepcin se a"orta la ejecucin del mismo& )ic(a
e*cepcin sera propagada al tr( padre o al m,todo llamante padre del tr( @ue contuviese el finall(&
-un@ue los "lo@ues catch y finall( son opcionalesB toda instruccin tr( (a de incluir al menos un
"lo@ue catch o un "lo@ue finall(&
%l siguiente ejemplo resume cmo !unciona la propagacin de e*cepcionesA
using System;

class MiException:Exception {}

class Excepciones
{
public static void Main()
{
try
{
Console.WriteLine("En el try de Main()");
Mtodo();
Console.WriteLine("Al final del try de Main()");
}
catch (MiException)
{
Console.WriteLine("En el catch de Main()");
}
finally
{
Console.WriteLine("finally de Main()");
}

}

public static void Mtodo()
{
try
{
Console.WriteLine("En el try de Mtodo()");
Mtodo2();
Console.WriteLine("Al final del try de Mtodo()");
}
catch (OverflowException)
{
Console.WriteLine("En el catch de Mtodo()");
}
finally
{
Console.WriteLine("finally de Mtodo()");
}

}

public static void Mtodo2()
{
try
{
Console.WriteLine("En el try de Mtodo2()");
throw new MiException();
Console.WriteLine("Al final del try de Mtodo2()");
}
catch (DivideByZeroException)
{
Console.WriteLine("En el catch de Mtodo2()");
}
finally
{
Console.WriteLine("finally de Mtodo2()");
}
}
}
8tese @ue en este cdigo lo Cnico @ue se (ace es de!inir un tipo nuevo de e*cepcin llamado
Mi%*ception y llamarse en el Main;< a un m,todo llamado M,todo=? @ue llama a otro de nom"re
M,todo9=? @ue lan/a una e*cepcin de ese tipo& Viendo la salida de este cdigo es !$cil ver el recorrido
seguido durante la propagacin de la e*cepcinA
%n try de Main=?
%n try de M,todo=?
%n try de M,todo9=?
!inally de M,todo9
!inally de M,todo
%n catc( de Main=?
!inally de Main=?
Como se puede o"servarB (ay muc(os 9rite:ine;< @ue nunca se ejecutan ya @ue en cuanto se lan/a
una e*cepcin se sigue ejecutando tras la instruccin siguiente al tr( @ue la trat =aun@ue ejecutando
antes los finall( pendientesB como se deduce de la salida del ejemplo? )e (ec(oB el compilador se dar$
cuenta @ue la instruccin siguiente al thro% nunca se ejecutar$ e in!ormar$ de ello con un mensaje de
aviso&
#a idea tras este mecanismo de e*cepciones es evitar me/clar cdigo normal con cdigo de
tratamiento de errores& %n jinstrucciones6 se escri"ira el cdigo como si no pudiesen producirse
erroresB en las cl$usulas catch se trataran los posi"les erroresB y en el finall( se incluira el cdigo a
ejecutar tanto si producen errores como si no =suele usarse para li"erar recursos ocupadosB como
!ic(eros o cone*iones de red a"iertas?
%n realidadB tam"i,n es posi"le escri"ir cada cl$usula catch de!iniendo una varia"le @ue se podr$
usar dentro del cdigo de tratamiento de la misma para (acer re!erencia a la e*cepcin capturada& %sto
se (ace con la sinta*isA

catch (<tipoExcepcin> <nombreVariable>)
{
<tratamiento>
}
8tese @ue en tanto @ue todas las e*cepciones derivan de S(stem.E)ce"tionB para de!inir una
cl$usula catch @ue pueda capturar cual@uier tipo de e*cepcin "asta usarA

catch(System.Exception <nombreObjeto>)
{
<tratamiento>
}
%n realidad la sinta*is anterior slo permite capturar las e*cepciones propias de la plata!orma &8%.B
@ue derivan de S(stem.E)ce"tion& Sin em"argoB lenguajes como CDD permiten lan/ar e*cepciones no
derivadas de dic(a claseB y para esos casos se (a incluido en C# una variante de catch @ue s @ue
realmente puede capturar e*cepciones de cual@uier tipoB tanto si derivan de S(stem.E)ce"tion como si
no& Su sinta*is esA
catch
{
<tratamiento>
}
Como puede deducirse de su sinta*isB el pro"lema @ue presenta esta Cltima variante de catch es @ue
no proporciona in!ormacin so"re cu$l es la e*cepcin capturadaB por lo @ue a veces puede resultar
poco Ctil y si slo se desea capturar cual@uier e*cepcin derivada de S(stem.E)ce"tion es mejor usar
la sinta*is previamente e*plicada&
%n cual@uier casoB am"os tipos de cl$usulas catch slo pueden ser escritas como la Cltima cl$usula
catch del tr(B ya @ue si no las cl$usulas catch @ue le siguiesen nunca llegaran a ejecutarse de"ido a
@ue las primeras capturaran antes cual@uier e*cepcin derivada de S(stem.E)ce"tion&
+especto al uso de thro%B (ay @ue se7alar @ue (ay una !orma e*tra de usarlo @ue slo es v$lida
dentro de cdigos de tratamiento de e*cepciones =cdigos jtratamientoi6 de las cl$usulas catch? %sta
!orma de uso consiste en seguir simplemente esta sinta*isA
throw;
%n este caso lo @ue se (ace es relan/ar la misma e*cepcin @ue se captur en el "lo@ue catch dentro
de cuyo de cdigo de tratamiento se usa el thro%T Hay @ue precisar @ue la e*cepcin relan/ada es
precisamente la capturadaB y aun@ue en el "lo@ue catch se la modi!i@ue a trav,s de la varia"le @ue la
representaB la versin relan/ada ser$ la versin original de la misma y no la modi!icada&
-dem$sB cuando se relance una e*cepcin en un tr( con cl$usula finall(B antes de pasar a reprocesar
la e*cepcin en el tr( padre del @ue la relan/ se ejecutar$ dic(a cl$usula&
'nstruccin t)ro(
#a instrucci!n thro% ya se (a visto @ue se usa para lan/ar e*cepciones de este modoA
throw <objetoExcepcinALanzar>$
%n caso de @ue no se indi@ue ningCn jo"jeto%*cepcin-#an/ar6 se relan/ar$ el @ue se estuviese
tratando en ese momentoB aun@ue esto slo es posi"le si el thro% se (a escrito dentro del cdigo de
tratamiento asociado a alguna cl$usula catch&
Como esta instruccin ya (a sido e*plicada a !ondo en este mismo temaB para m$s in!ormacin so"re
ella puede consultarse el epgra!e E1%e!%io#es del mismo&
Otras instrucciones
#as instrucciones vistas (asta a(ora son comunes a muc(os lenguajes de programacin& Sin
em"argoB en C# tam"i,n se (a incluido un "uen nCmero de nuevas instrucciones propias de este
lenguaje& %stas instrucciones se descri"en en los siguientes apartadosA
'nstrucciones c)ec1ed . unc)ec1ed
#as instrucciones chec'ed y unchec'ed permiten controlar la !orma en @ue tratar$n los
des"ordamientos @ue ocurran durante la reali/acin de operaciones aritm,ticas con tipos "$sico
enteros& uncionan de !orma similar a los operadores chec'ed y unchec'ed ya vistos en el Tema *:
0s!e%tos l1i%osB aun@ue a di!erencia de ,stos son aplica"les a "lo@ues enteros de instrucciones y no a
una Cnica e*presin& -sB la instrucci!n chec'ed se usa de este modoA
checked
<instrucciones>
.odo des"ordamiento @ue se produ/ca al reali/ar operaciones aritm,ticas con enteros en
jinstrucciones6 provocar$ @ue se lance una e*cepcin S(stem.verflo%E)ce"tion& Por su parteB la
instrucci!n unchec'ed se usa asA
unchecked
<instrucciones>
%n este casoB todo des"ordamiento @ue se produ/ca al reali/ar operaciones aritm,ticas con tipos
"$sicos enteros en jinstrucciones6 ser$ ignorado y lo @ue se (ar$ ser$ tomar el valor resultante de
@uedarse con los "its menos signi!icativos necesarios&
Por de!ectoB en ausencia de estas instrucciones las e*presiones constantes se evalCan como si se
incluyesen dentro de una instruccin chec'ed y las @ue no constantes como si se incluyesen dentro de
una instruccin unchec'ed& Sin em"argoB a trav,s de la opcin Achec'ed del compilador es posi"le
tanto (acer @ue por de!ecto se comprue"en los des"ordamientos en todos los casos para as siempre
poder detectarlos y tratarlos&
)esde Visual Studio&8%.B la !orma de controlar el tipo de compro"aciones @ue por de!ecto se (ar$n
es a trav,s de /ie% @ 1ro"et( 1ages @ Configuration Settings @ =uild @ Chec' for overflo%
underflo%&
%l siguiente cdigo muestra un ejemplo de cmo usar am"as instruccionesA
using System;

class Unchecked
{
static short x = 32767; // Valor maximo del tipo short

public static void Main()
{
unchecked
{
Console.WriteLine((short) (x+1)); // (1)
Console.WriteLine((short) 32768); // (2)
}
}
%n un principio este cdigo compilaraB pero los des"ordamientos producidos por el (ec(o de @ue
O9YZG no es un valor @ue se pueda representar con un short =FZ "its con signo? provocaran @ue
apareciese por pantalla dic(o valor truncadoB mostr$ndoseA
5O9YZG
5O9ZYG
Sin em"argoB si sustituy,semos la instruccin unchec'ed por chec'edB el cdigo anterior ni si@uiera
compilara ya @ue el compilador detectara @ue se va a producir un des"ordamiento en =9? de"ido a @ue
O9YZG es constante y no representa"le con un short&
Si eliminamos la instruccin =9? el cdigo compilara ya @ue =*DF? no es una e*presin constante y
por tanto el compilador no podra detectar des"ordamiento al compilar& Sin em"argoB cuando se
ejecutase la aplicacin se lan/ara una S(stem.verflo%E)ce"tion&
'nstruccin loc1
#a instrucci!n loc' es Ctil en aplicaciones concurrentes donde mCltiples (ilos pueden estar
accediendo simult$neamente a un mismo recursoB ya @ue lo @ue (ace es garanti/ar @ue un (ilo no pueda
acceder a un recurso mientras otro tam"i,n lo est, (aciendo& Su sinta*is es la siguienteA
lock (<objeto>)
<instrucciones>

Su signi!icado es el siguienteA ningCn (ilo puede ejecutar las jinstrucciones6 del "lo@ue indicado si
otro las est$ ejecutandoB y si alguno lo intenta se @uedar$ esperando (asta @ue aca"e el primero& %sto
tam"i,n a!ecta a "lo@ues de jinstrucciones6 de cual@uier otro loc' cuyo jo"jeto6 sea el mismo& %ste
jo"jeto6 (a de ser de algCn tipo re!erencia&
%n realidadB la instruccin anterior es e@uivalente a (acerA
System.Threading.Monitor.Enter(<objeto>);
try
{
<instrucciones>
}
finally
{
System.Threading.Monitor.Exit(<objeto>);
}
Sin em"argoB usar loc' tiene dos ventajasA es m$s compacto y e!iciente =jo"jeto6 slo se evalCa una
ve/?
1na "uena !orma de garanti/ar la e*clusin mutua durante la ejecucin de un m,todo de un cierto
o"jeto es usando this como jo"jeto6 %n el caso de @ue se tratase de un m,todo de tipoB en tanto @ue
this no tiene sentido dentro de estos m,todos est$ticos una "uena alternativa sera usar el o"jeto
S(stem.T("e @ue representase a ese tipo& Por ejemploA
class C
{
public static void F()
{
lock(typeof(C))
{
// ... Cdigo al que se accede exclusivamente
}
}
}
'nstruccin usin$
#a instrucci!n using !acilita el tra"ajo con o"jetos @ue tengan @ue ejecutar alguna tarea de limpie/a
o li"eracin de recursos una ve/ @ue termine de ser Ctiles& -un@ue para estos menesteres ya est$n los
destructoresB dado su car$cter indeterminista puede @ue en determinadas ocasiones no sea conveniente
con!iar en ellos para reali/ar este tipo de tareas& #a sinta*is de uso de esta instruccin es la siguienteA
using (<tipo> <declaraciones>)
<instrucciones>
%n jdeclaraciones6 se puede indicar uno o varios o"jetos de tipo jtipo6 separados por comas& %stos
o"jetos ser$n de slo lectura y slo ser$n accesi"les desde jinstrucciones6& -dem$sB (an de
implementar la inter!a/ S(stem.IEis"osable de!inida como sigueA
interface IDisposable
{
void Dispose()
}
%n la implementacin de Eis"ose;< se escri"ira el cdigo de limpie/a necesarioB pues el signi!icado
de using consiste en @ue al aca"ar la ejecucin de jinstrucciones6B se llama autom$ticamente al
m,todo Eis"ose;< de los o"jetos de!inidos en jdeclaraciones6&
Hay @ue tener en cuenta @ue la llamada a )ispose=? se (ace sea cual sea la ra/n de @ue se deje de
ejecutar las jinstrucciones6 %s decirB tanto si se (a producido una e*cepcin como si se (a aca"ado su
ejecucin normalmente o con una instruccin de saltoB Eis"ose;< es siempre llamado& %n realidad una
instruccin using comoA
using (R1 r1 = new R1())
{
r1.F();
}
%s tratada por el compilador comoA
{
R1 r1 = new R1()
try
{
r1.F();
}
finally
{
if (r1!=null)
((IDisposable) r1).Dispose();
}
}
Si se declarasen varios o"jetos en jdeclaraciones6B a Eis"ose;< se le llamara en el orden inverso a
como !ueron declarados& #o mismo ocurre si se anidasen varias instrucciones usingA primero se
llamara al Eis"ose;< de las varia"les declaradas en los using internos y luego a las de los e*ternos&
-sB estas dos instrucciones son e@uivalentesA
using (Recurso obj = new Recurso(), obj2= new Recurso())
{
r1.F();
r2.F();
}
using (Recurso obj = new Recurso())
{
using (Recurso obj2= new Recurso())
{
r1.F();
r2.F();
}
}
%l siguiente ejemplo resume cmo !unciona la sentencia usingA
using System;
class A:IDisposable
{
public void Dispose()
{
Console.WriteLine("Llamado a Dispose() de {0}", Nombre);
}

public A(string nombre)
{
Nombre = nombre;
}
string Nombre;
}
class Using
{
public static void Main()
{
A objk = new A("objk");
using (A obj1 = new A("obj1"), obj2 = new A("objy"))
{
Console.WriteLine("Dentro del using");
}
Console.WriteLine("Fuera del using");
}
}
#a salida por pantalla resultante de ejecutar este ejemplo ser$A
)entro del using
#lamando a )ispose=? de o"jy
#lamando a )ispose=? de o"jF
uera del using
Como se deduce de los mensajes de salida o"tenidosB justo antes de salirse del using se llama a los
m,todos Eis"ose;< de los o"jetos declarados en la seccin jdeclaraciones6 de dic(a instruccin y en el
mismo orden en @ue !ueron declarados&
'nstruccin "i*ed
#a instrucci!n fi)ed se utili/a para !ijar o"jetos en memoria de modo @ue el recolector de "asura no
pueda moverlos durante la ejecucin de un cierto "lo@ue de instrucciones&
%sta instruccin slo tiene sentido dentro de regiones de cdigo inseguroB concepto @ue se trata en el
Tema &8: C'di(o i#se($roB por lo @ue ser$ all es donde se e*pli@ue a !ondo cmo utili/arla& -@u slo
diremos @ue su sinta*is de uso esA
fixed(<tipoPunteros> <declaracionesPunterosAFijar>)
<instrucciones>
Ftributos
Conce"to de atributo
1n atributo es in!ormacin @ue se puede a7adir a los metadatos de un mdulo de cdigo& %sta
in!ormacin puede ser re!erente tanto al propio mdulo o el ensam"lado al @ue pertene/ca como a los
tipos de datos de!inidos en ,lB sus miem"rosB los par$metros de sus m,todosB los "lo@ues set y get de
sus propiedades e indi/adores o los "lo@ues add y remove de sus eventos&
%n C# se incluyen numerosos modi!icadores @ue nos permiten asociar in!ormacin a los metadatos
de un mdulo& Por ejemploB con los modi!icadores "ublicB "rotectedB "rivateB internal o "rotected
internal podemos a7adir in!ormacin so"re la visi"ilidad de los tipos del mdulo y de sus miem"ros&
Pues "ienB los atri"utos pueden verse como un mecanismo mediante el cual el programador puede crear
sus propios modi!icadores&
1n ejemplo de atri"uto podra ser uno llamado -yuda @ue pudiese pre!ijar las de!iniciones de
miem"ros de tipos e indicase cu$l es la 1+# donde se pudiese encontrar in!ormacin detallada con
ayuda so"re el signi!icado del miem"ro pre!ijado&
/tili*aci%n de atributos
Para colocar un atri"uto a un elemento "asta pre!ijar la de!inicin de dic(o elemento con una
estructura de esta !ormaA
[<nombreAtributo>(<parmetros>)]
%sta estructura (a de colocarse incluso antes @ue cual@uier modi!icador @ue pudiese acompa7ar la
de!inicin del elemento a atri"uir&
#os par$metros de un atri"uto pueden ser opcionalesB y si se usa sin especi!icar valores para sus
par$metros no (ay por@u, @ue usar par,ntesis vacos como en las llamadas a m,todosB sino @ue "asta
usar el atri"uto indicando slo la sinta*is -jnom"re-tri"uto6.
#os par$metros de un atri"uto pueden ser de dos tiposA
1ar$metros sin nombre: Se usan de !orma similar a los par$metros de los m,todosB slo @ue
no pueden contar con modi!icadores ref u out&
1ar$metros con nombre: Son opcionales y pueden colocarse en cual@uier posicin en la lista
de jpar$metros6 del atri"uto& #o Cltimo se de"e a @ue para darles valor se usa la sinta*is
jnom"rePar$metro6&jvalor6B con lo el compilador no depender$ de la posicin en @ue se les
pasen los valores para determinar a @u, par$metro se le est$ dando cada valorB sino @ue reci"e
e*plcita su nom"re&
Para evitar con!lictos entre par$metros con nom"re y par$metros sin nom"reB los primeros siempre
se (an de incluir despu,s de los segundosB no siendo posi"le me/clarlos indiscriminadamente&
Si se desean especi!icar varios atri"utos para un mismo elemento se pueden indicar todos ellos entre
unos mismos corc(etes separados por comas& %s decirB de la !ormaA
[<atributo1>(<parametros1>), <atributo2>(<parmetros>), ...]
-un@ue tam"i,n sera posi"le especi!icarlos por separado& O seaB de esta otra !ormaA
[<atributo1>(<parametros1>)] [<atributo2>(<parmetros>)] ...
Hay casos en los @ue por la u"icacin del atri"uto no se puede determinar de manera unvoca a cu$l
elemento se le desea aplicarB ya @ue podra ser aplica"le a varios& %n esos casosB para evitar
am"ig<edades lo @ue se (ace es usar el atri"uto pre!ijando su nom"re de un indicador de ti"o de
elementoB @uedando as la sinta*is a usarA
[<indicadorElemento>:<nombreAtributo>(<parmetros>)]
-un@ue cada implementacin de C# puede incluir sus propios indicadores de tipo de elementoB todas
ellas incluir$n al menos los siguientesA
assembl(: Indica @ue el atri"uto se aplica al ensam"lado en @ue se compile el cdigo !uente @ue
lo contenga& -l de!inir atri"utos de ensam"lado es o"ligatorio incluir este indicadorB ya @ue
estos atri"utos se colocan precediendo cual@uier de!inicin de clase o espacio de nom"res y si
no se incluyesen se con!undira con atri"utos de tipoB @ue se colocan en el mismo sitio&
module: Indica @ue el atri"uto se aplica al mdulo en @ue se compile el cdigo !uente @ue lo
contenga& -l igual @ue el indicador assembl(B (ay @ue incluirlo siempre para de!inir este tipo
de atri"utos por@ue si no se con!undiran con atri"utos de tipoB ya @ue tam"i,n se (an de u"icar
precediendo las de!iniciones de clases y espacios de nom"res&
t("e: Indica @ue el atri"uto se aplica al tipo cuya de!inicin precede& %n realidad no (ace !alta
utili/arloB pues es lo @ue por de!ecto se considera para todo atri"uto @ue preceda a una
de!inicin de tipo& Sin em"argoB se (a incluido por consistencia con el resto de indicadores de
tipo de atri"uto y por@ue puede resultar conveniente incluirlo ya @ue e*plicitarlo !acilita la
lectura del cdigo&
return: Indica @ue el atri"uto se aplica a un valor de retorno de un m,todoB operadorB "lo@ue
getB o de!inicin de delegado& Si no se incluyese se considerara @ue se aplica a la de!inicin del
m,todoB operadorB "lo@ue get o delegadoB ya @ue estos atri"utos se colocan antes de la misma al
igual @ue los atri"utos de valores de retorno&
"aram: Indica @ue el atri"uto se aplica a un par$metro de un m,todo& Si no se incluyese al
de!inir "lo@ues setB add o remove se considerara @ue el atri"uto se re!iere a los "lo@ues en s y
no al par$metro value en ellos implcito&
method: Indica @ue el atri"uto se aplica al m,todo al @ue precede& %n realidad no es necesario
usarlo por@ueB como se dice en la e*plicacin de los indicadores "aram y returnB es lo @ue se
considera por de!ecto& Sin em"ragoB y como pasa"a con t("eB se incluye por consistencia y
por@ue puede ser "uena idea incluirlo para !acilitar la legi"ilidad del cdigo con su
e*plicitacin&
event: Indica @ue el atri"uto se aplica al evento a cuya de!inicin precede& %n realidad no es
necesario incluirlo por@ue es lo @ue se considera por de!ectoB pero nuevamente se (a incluido
por consistencia y para !acilitar la lectura del cdigo&
"ro"ert(: Indica @ue el atri"uto se aplica a la propiedad a cuya de!inicin precede& [ste
tam"i,n es un indicador innecesario e incluido tan slo por consistencia y para !acilitar la
legi"ilidad del cdigo&
field: Indica @ue el atri"uto se aplica al cuya de!inicin precede& Como otros indicadoresB slo
se incluye por consistencia y para (acer m$s legi"le el cdigo
'efinici%n de nuevos atributos
Especi"icacin del nombre del atributo
Se considera @ue un atri"uto es toda a@uella clase @ue derive de S(stem.Fttribute& Por tantoB para
de!inir un nuevo tipo de atri"uto (ay @ue crear una clase @ue derive de ella& Por convenioB a este tipo de
clases suele d$rseles nom"res aca"ados en FttributeB aun@ue a la (ora de usarlas desde C# es posi"le
o"viar dic(o su!ijo& 1n ejemplo de cmo de!inir un atri"uto llamado -yuda esA
using System;
class AyudaAttribute:Attribute
{}
W ejemplos de cmo usarlo pre!ijando la de!inicin de clases sonA
[.yuda]
class A
{}
[.yuda.ttribute]
class B
{}
Puede darse la circunstancia de @ue se (aya de!inido un atri"uto con un cierto nom"re sin su!ijo
-ttri"ute y otro @ue si lo tenga& Como es lgicoB en ese caso cuando se use el atri"uto sin especi!icar el
su!ijo se (ar$ re!erencia a la versin sin su!ijo y cuando se use con su!ijo se (ar$ re!erencia a la versin
con su!ijo&
Especi"icacin del uso de un atributo
Por de!ecto cual@uier atri"uto @ue se de!ina puede preceder la de!inicin de cual@uier elemento del
lenguaje& Si se desea limitar a @u, de!iniciones puede preceder es necesario pre!ijar la clase @ue lo
de!ine con un atri"uto especial llamado S(stem.FttributeJsage& %ste atri"uto consta de los siguientes
par$metros con nom"reA
Fllo%Multi"le: Por de!ecto cada atri"uto slo puede aparecer una ve/ pre!ijando a cada
elemento& )$ndole el valor true a este par$metro se considerar$ @ue puede aparecer mCltiples
veces&
Inherited: Por de!ecto los atri"utos aplicados a una clase no son (eredados en sus clases (ijas&
)$ndole el valor true a este par$metro se consigue @ue s lo sean&
-parte de estos dos par$metrosB FttributeJsage tam"i,n puede contar con un par$metro opcional
sin nom"re @ue indi@ue a @u, tipos de de!iniciones puede preceder& Por de!ecto se considera @ue un
atri"uto puede preceder a cual@uier elementoB lo @ue es e@uivalente a darle el valor
FttributeTargets.Fll a este par$metro& Sin em"rago es posi"le especi!icar otras posi"ilidades d$ndole
valores de la enumeracin S(stem.FttributeTargetsB @ue son los @ue se recogen en la Tabla A
Valor de -ttri"ute.argets Signi!ica @ue el atri"uto puede preceder a&&&
Fll Cual@uier de!inicin
Fssembl( )e!iniciones de espacio de nom"resB consider$ndose @ue el
atri"uto se re!iere al ensam"lado en general&
Module )e!iniciones de espacio de nom"resB consider$ndose @ue el
atri"uto se re!iere al mdulo en su conjunto&
Class )e!iniciones de clases
Eelegate )e!iniciones de delegados
Interface )e!iniciones de inter!aces
Struct )e!iniciones de estructuras
Enum )e!iniciones de enumeraciones
Dield )e!iniciones de campos
Method )e!iniciones de m,todos
Constructor )e!iniciones de constructores
1ro"ert( )e!iniciones de propiedades o indi/adores
Event )e!iniciones de eventos
1arameter )e!iniciones de par$metros de m,todos
Ceturn/alue )e!iniciones de valores de retorno de m,todos
.a"la dA Valores de -ttri"ute.argets
%s posi"le com"inar varios de estos valores mediante operaciones lgicas gorg =car$cter p ? Por
ejemploB si @ueremos de!inir el atri"uto -yuda anterior de modo @ue slo pueda ser usado para pre!ijar
de!iniciones de enumeraciones o de clases se (araA
[.ttribute9sage(.ttribute:argets#5lass ; .ttribute:argetes#(num)]
class Ayuda:Attribute
{}

%s importante resaltar @ue FttributeJsage slo puede incluirse precediendo de!iniciones de otros
atri"utos =o seaB de clases derivadas de S(stem.Fttribute?
Especi"icacin de parmetros #lidos
Se considera @ue los par$metros sin nom"re @ue puede tomar un atri"uto son a@uellos @ue se
especi!i@uen como par$metros en el constructor del tipo @ue lo de!ineB y @ue sus par$metros con
nom"re ser$n las propiedades y campos pC"licosB no est$ticos y de lecturaIescritura de!inidos en dic(o
tipo&
1n ejemplo de cmo de!inir el atri"uto -yuda anterior de modo @ue tome un par$metro sin nom"re
con la 1+# @ue indi@ue dnde encontrar la ayuda so"re el miem"ro o clase al @ue precede y un
par$metro con nom"re llamado -utor @ue indi@ue @ui,n es el autor de esa documentacin esA
[.ttribute9sage(.ttribute:argets#5lass ; .ttribute:argets#(num)]
class Ayuda:Attribute
{
private string autor;
private string url;

public Ayuda(string URL)
{ url=URL; }

public string Autor
{
set {autor = value;}
get {return autor;}
}
}
%jemplos de usos v$lidos de este atri"uto sonA
[.yuda(3http"<<www#josan#com<5lases<.#html3)]
class A {}
[.yuda(3http"<<www#josan#com<5lases</#html3, .utor%3=os> .ntonio3)]
class B {}
#os tipos v$lidos de par$metrosB tanto con nom"re como sin ,lB @ue puede tomar un atri"uto sonA
cual@uier tipo "$sico e*cepto decimal y los tipos enteros sin signoB cual@uier enumeracin pC"licaB
S(stem.T("e o ta"las unidimensionales de elementos de cual@uiera de los anteriores tipos v$lidos&
Lectura de atributos en tiempo de ejecuci%n
Para acceder a los metadatos de cual@uier ensam"lado se utili/an las clases del espacio de nom"res
S(stem.Ceflection& %ste espacio de nom"res es inmenso y e*plicar cmo utili/arlo @ueda !uera del
alcance de este li"roB aun@ue de todos modos a continuacin se dar$n unas ideas "$sicas so"re cmo
acceder a trav,s de sus tipos a los atri"utos incluidos en los ensam"lados&
#a clave para acceder a los atri"utos se encuentra en el m,todo est$tico de la clase S(stem.Fttribute
llamado Fttribute-. #etCustomFttributes;H)I objetoCefle)ivo<B donde j*6 es el tipo de
S(stem.Ceflection @ue representa a los elementos cuyos atri"utos se desea o"tener& #os posi"les tipos
sonA Fssembl(B @ue representa ensam"ladosB Module @ue representa mdulosB MemberInfo @ue
representa miem"ros =incluidos tiposB @ue al !in y al ca"o son miem"ros de espacios de nom"res?B y
1arameterInfo @ue representa par$metros& %l par$metro tomado por este m,todo ser$ el o"jeto @ue
represente al elemento en concreto cuyos metadatos se @uieren o"tener&
Como se veB #etCustomFttributes;< devuelve una ta"la con los atri"utos en !orma de o"jetos
FttributeB @ue es la clase "ase de todos los atri"utosB por lo @ue si a partir de ellos se desease acceder a
caractersticas espec!icas de cada tipo de atri"uto (a"ra @ue aplicar do'ncasting como se coment en
el Tema 5: Clases =para asegurase de @ue las conversiones se realicen con ,*ito recu,rdese @ue se
puede usar el operador is para determinar cu$l es el verdadero tipo de cada atri"uto de esta ta"la?
Para o"tener el o"jeto Fssembl( @ue representa al ensam"lado al @ue pertene/ca el cdigo @ue se
est, ejecutando se usa el m,todo Fssembl( #etE)ecutingFssembl(;< de la clase Fssembl(B @ue se
usa tal y como se muestraA
Assembly ensamblado = Assembly.GetExecutingAssembly();

Otra posi"ilidad sera o"tener ese o"jeto Fssembl( a partir del nom"re del !ic(ero donde se
encuentre almacenado el ensam"lado& Para ello se usa el m,todo Fssembl( :oadDrom;string
rutaEnsamblado< de la clase Fssembl( como se muestraA
Assembly ensamblado = Assembly.LoadFrom("josan.dll");

1na ve/ o"tenido el o"jeto @ue representa a un ensam"ladoB pueden o"tenerse los o"jetos Module
@ue representan a los mdulos @ue lo !orman a trav,s de su m,todo Module-. #etModules;<&
- partir del o"jeto Module @ue representa a un mdulo puede o"tenerse los o"jetos T("e @ue
representan a sus tipos a trav,s de su m,todo T("e-. #etT("es;< Otra posi"ilidad sera usar el
operador t("eof ya visto para o"tener el T("e @ue representa a un tipo en concreto sin necesidad de
crear o"jetos Module o Fssembl(&
%n cual@uier casoB una ve/ o"tenido un o"jeto T("eB a trav,s de sus m,todos DieldInfo-.
#etDields;<B MethodInfo-. #etMethods;<B ConstructorInfo-. #etConstructors;<B EventInfo-.
#etEvents-. y 1ro"ert(Info-. #et1ro"erties;< pueden o"tenerse los o"jetos re!le*ivos @ue
representanB de manera respectivaB a sus camposB m,todosB constructoresB eventos y propiedades o
indi/adores& .anto todos estos o"jetos como los o"jetos T("e derivan de MemberInfoB por lo @ue
pueden ser pasados como par$metros de #etCustomFttributes;< para o"tener los atri"utos de los
elementos @ue representan&
Por otro ladoB a trav,s de los o"jetos MethodInfo y ConstructorInfoB es posi"le o"tener los tipos
re!le*ivos @ue representan a los par$metros de m,todos y constructores llamando a su m,todo
1arameterInfo-. #et1arameters;< -dem$sB en el caso de los o"jetos MethodInfo tam"i,n es posi"le
o"tener el o"jeto @ue representa al tipo de retorno del m,todo @ue representan mediante su propiedad
T("e CeturnT("e ZgetT[&
%n lo re!erente a las propiedadesB es posi"le o"tener los o"jetos MethodInfo @ue representan a sus
"lo@ues get y set a trav,s de los m,todos MethodInfo #etSetMethod;< y MethodInfo
#etSetMethod;< de los o"jetos 1ro"ert(Info @ue las representan& -dem$sB para o"tener los o"jetos
re!le*ivos @ue representen a los ndices de los indi/adores tam"i,n se dispone de un m,todo
1aramterInfo-. #etInde)1arameters;<
W en cuanto a los eventosB los o"jetos EventInfo disponen de m,todos MethodInfo
#etFddMethod;< y MethodInfo #etCemoveMethod;< mediante los @ue es posi"le o"tener los
o"jetos re!le*ivos @ue representan a sus "lo@ues add y remove&
- continuacin se muestra un programa de ejemplo @ue lo @ue (ace es mostrar por pantalla el
nom"re de todos los atri"utos @ue en ,l se (ayan de!inidoA

using System.Reflection;
using System;

[assembly: EjemploEnsamblado]
[module: EjemploModulo]
[AttributeUsage(AttributeTargets.Method)]
class EjemploMtodo:Attribute
{}

[AttributeUsage(AttributeTargets.Assembly)]
class EjemploEnsamblado:Attribute
{}

[AttributeUsage(AttributeTargets.Module)]
class EjemploModulo:Attribute
{}

[AttributeUsage(AttributeTargets.Class)]
class EjemploTipo:Attribute
{}

[AttributeUsage(AttributeTargets.Field)]
class EjemploCampo:Attribute
{}

[EjemploTipo]
class A
{
public static void Main()
{
Assembly ensamblado = Assembly.GetExecutingAssembly();

foreach(Attribute atributo in Attribute.GetCustomAttributes(ensamblado))
Console.WriteLine("ENSAMBLADO: {0}",atributo);

foreach(Module modulo in ensamblado.GetModules())
{
foreach(Attribute atributo in Attribute.GetCustomAttributes(modulo))
Console.WriteLine("MODULO: {0}", atributo);

foreach (:ype tipo in modulo.GetTypes())
{
foreach(Attribute atributo in Attribute.GetCustomAttributes(tipo))
Console.WriteLine("TIPO: {0}", atributo);
foreach (FieldInfo campo in tipo.GetFields())
muestra("CAMPO", campo);
foreach (MethodInfo metodo in tipo.GetMethods())
muestra("METODO", metodo);
foreach (EventInfo evento in tipo.GetEvents())
muestra("EVENTO", evento);
foreach (PropertyInfo propiedad in tipo.GetProperties())
muestra("PROPIEDAD", propiedad);
foreach (ConstructorInfo constructor in tipo.GetConstructors())
muestra("CONSTRUCTOR",constructor);
}
}
}

static private void muestra(string nombre, MemberInfo miembro)
{
foreach (Attribute atributo in Attribute.GetCustomAttributes(miembro))
Console.WriteLine("{0}: {1}", nombre, atributo);
}
}
#o Cnico @ue (ace el Main;< de este programa es o"tener el Fssembl( @ue representa el ensam"lado
actual y mostrar todos sus atri"utos de ensam"lado& #uego o"tiene todos los Modules @ue representa a
los mdulos de dic(o ensam"ladoB y muestra todos los atri"utos de mdulo de cada uno& -dem$sB de
cada mdulo se o"tienen todos los T("es @ue representan a los tipos en ,l de!inidos y se muestran
todos sus atri"utosJ y de cada tipo se o"tienen los o"jetos re!le*ivos @ue representan a sus di!erentes
tipos de miem"ros y se muestran los atri"utos de cada miem"ro&
-parte del m,todo Main;< en el ejemplo se (an incluido de!iniciones de numerosos atri"utos de
ejemplo aplica"les a di!erentes tipos de elemento y se (an diseminado a lo largo del !uente varios usos
de estos atri"utos& Por elloB la salida del programa esA
%8S-M0#-)OA %jemplo%nsam"lado
%8S-M0#-)OA System&)iagnostics&)e"ugga"le-ttri"ute
MO)1#O %jemploModulo
.IPOA System&-ttri"ute1sage-ttri"ute
.IPOA System&-ttri"ute1sage-ttri"ute
.IPOA System&-ttri"ute1sage-ttri"ute
.IPOA System&-ttri"ute1sage-ttri"ute
.IPOA System&-ttri"ute1sage-ttri"ute
.IPOA %jemplo.ipo
M%.O)OA %jemploM,todo
8tese @ue aparte de los atri"utos utili/ados en el cdigo !uenteB la salida del programa muestra @ue
el compilador (a asociado a nivel de ensam"lado un atri"uto e*tra llamado Eebuggable& %ste atri"uto
incluye in!ormacin so"re si pueden aplicarse optimi/aciones al compilar EI. el ensam"lado o si se (a
de reali/ar una tra/a de su ejecucin& Sin em"argoB no conviene !iarse de su implementacin ya @ue no
est$ documentado por Microso!t y puede cam"iar en !uturas versiones de la plata!orma &8%.&
,tributos de compilaci%n
-un@ue la mayora de los atri"utos son interpretados en tiempo de ejecucin por el C#+ u otras
aplicacionesB (ay una serie de atri"utos @ue tienen un signi!icado especial en C# y condicionan el
proceso de compilacin& %stos son los @ue se e*plican a continuacin&
Atributo S.stem.Attribute2sa$e
Wa (emos visto en este mismo tema @ue se usa para indicar dnde se pueden colocar los nuevos
atri"utos @ue el programador de!inaB por lo @ue no se (ar$ m$s (incapi, en ,l&
Atributo S.stem.-bsolete
Puede preceder a cual@uier elemento de un !ic(ero de cdigo !uente para indicar @ue (a @uedado
o"soleto& -dmite los siguientes dos par$metros sin nom"reA
1n primer par$metro de tipo string @ue contenga una cadena con un mensaje a mostrar cuando
al compilar se detecte @ue se (a usado el elemento o"soleto&
1n segundo par$metro de tipo bool @ue indi@ue si se (a de producir un aviso o un error cuando
se detecte el uso del elemento o"soleto& Por de!ecto se muestra un avisoB pero si se da valor true
a este par$metroB el mensaje ser$ de error&
%l siguiente ejemplo muestra como utili/ar este atri"utoA

using System;

class Obsoleta
{
[Obsolete("No usar f(), que est obsoleto.", true)]
public static void f()
{}

public static void Main()
{
f();
}
}
Cuando se compile este programaB el compilador emitir$ el siguiente mensaje de errorA
o"solete&cs=FFBFY?A error CS:ZFdA hO"soleta&!=?i is o"soleteA 8o usar !=?B @ue est$ o"soleto&
Si no se (u"iese especi!icado a bsolete su segundo par$metroB entonces el mensaje sera de aviso
en ve/ de errorA
o"solete&cs=FFBFY?A 'arning CS:ZFGA hO"soleta&!=?i is o"soleteA 8o usar !=?B @ue est$
o"soleto&
-tri"uto System&)iagnostics&Conditional
%ste atri"uto slo puede pre!ijar de!iniciones de m,todosB y permite de!inir si las llamadas al m,todo
pre!ijado se (an de compilar o no& Puede usarse mCltiples veces pre!ijando a un mismo m,todo y toma
un par$metro sin nom"re de tipo string& Slo se compilar$n a@uellas llamadas al m,todo tales @ue en el
momento de (acerlas est, de!inida alguna directiva de preprocesado con el mismo nom"re @ue el
par$metro de alguno de los atri"utos Conditional @ue pre!ijen la de!inicin de ese m,todo&
Como se veB este atri"uto es una "uena !orma de simpli!icar la escritura de cdigo @ue se de"a
compilar condicionalmenteB ya @ue evita tener varias directivas #if @ue encierren cada llamada al
m,todo cuya ejecucin se desea controlar& Sin em"argoB Conditional no controla la compilacin de ese
m,todoB sino slo las llamadas al mismo&
%l siguiente ejemplo muestra cmo usar ConditionalA

using System;
using System.Diagnostics;

class Condicional
{
[Conditional("DEBUG")]
public static void F()
{
Console.WriteLine("F()");
}

public static void Main()
{
F();
}
}
Slo si compilamos el este cdigo de!iniendo la constante de preprocesado )%01; se mostrar$ por
pantalla el mensaje =? %n caso contrarioB nunca se (ar$ la llamada a =?
Hay @ue precisar @ue en realidad Conditional no puede preceder a cual@uier de!inicin de m,todoB
sino @ue en su colocacin (ay impuestas ciertas restricciones especialesA
%l m,todo (a de tener un tipo de retorno void& %sto se de"e a @ue si tuviese otro se podra usar
su valor de retorno como operando en e*presionesB y cuando no !uesen compiladas sus llamadas
esas e*presiones podran no tener sentido y producir errores de compilacin&
Si se aplica a un m,todo virtual todas sus rede!iniciones lo (eredanB siendo errneo aplic$rselo
e*plcitamente a una de ellas& %sto de"e a @ue en tiempo de compilacin puede no sa"erse cu$l
es el verdadero tipo de un o"jetoB y si unas rede!iniciones pudiesen ser condicionales y otras noB
no podra determinarse al compilar si es condicional la versin del m,todo a la @ue en cada caso
se llame&
8o puede atri"uirse a m,todos de!inidos en inter!aces ni a implementaciones de m,todos de
inter!acesB pues son tam"i,n virtuales y podran reimplementarse&
Atributo S.stem.ClsCompliant
Permite especi!icar @ue el compilador (a de asegurarse de @ue el ensam"ladoB tipo de dato o
miem"ro al @ue se aplica es compati"le con el C#S& %llo se le indica =ya sea por nom"re o
posicionalmente? a trav,s de su Cnico par$metro bool IsCom"liantB tal y como se muestra en el
siguiente cdigo ejemploA
using System;

[assembly:CLSCompliant(true)]
public class A
{
public void F(uint x)
{}

public static void Main()
{}
}
Si intenta compilarlo tal cualB o"tendr$ el siguiente mensaje de errorA
error CSO::FA %l tipo de argumento fuintf no es compati"le con C#S
%sto se de"e a @ue el tipo uint no !orma parte del C#SB y en el cdigo se est$ utili/ando como parte
de un m,todo pC"lico aCn cuando mediante el atri"uto C:SCom"liant se est$ indicando @ue se desea
@ue el cdigo sea compati"le con el C#S& Si se le @uitase este atri"utoB o se diese el valor false a su
par$metroB o se de!iniesen la clase - o el m,todo =? como privadosB o se cam"iase el tipo del
par$metro * a un tipo perteneciente al C#S =peB int?B entonces s @ue compilara el cdigo&
8tese @ue cuando el atri"uto C:SCom"liant se aplica a nivel de todo un ensam"ladoB se
comprue"a la adecuacin al C#S de todos sus tipos de datosB mientras @ue si solamente se aplica a un
tipo de datoB slo se compro"ar$ la adecuacin al C#S del mismoJ y si tan slo se aplica a un miem"roB
Cnicamente se compro"ar$ la adecuacin al C#S de ,ste&
Pseudoatributos
#a 0C# proporciona algunos atri"utos @ueB aun@ue se usan de la misma manera @ue el restoB se
almacenan de manera especial en los metadatosB como lo (aran modi!icadores como virtual o "rivate&
Por ello se les denomina "seudoatributosB y no se pueden recuperar mediante el ya visto m,todo
#etCustomFttributes;<B aun@ue para algunos de ellos se proporcionan otro mecanismos de
recuperacin espec!icos& 1n ejemplo es el atri"uto EllIm"ort @ue ya se (a visto @ue se usa para
de!inicin de m,todos e*ternos& -sB dado el siguiente cdigoA
using System.Reflection;
using System.Runtime.InteropServices;
using System;
using System.Diagnostics;

class A
{
[DllImport("kernel32")][Conditional("DEBUG")]

public static extern void CopyFile(string fuente, string destino);

public static void Main()
{

MethodInfo mtodo = typeof(A).GetMethod("CopyFile");
foreach (Attribute atributo in mtodo.GetCustomAttributes(false))
Console.WriteLine(atributo);
}
}
#a salida @ue se o"tendra al ejecutarlo es la siguienteA
System&)iagnostics&Conditional-ttri"ute

)onde como se puede verB no se (a recuperado el pseudoatri"uto EllIm"ort mientras @ue el otro
=Conditional?B @ue es un atri"uto normalB s @ue lo (a (ec(o&
C!digo inseguro
Concepto de c%di!o inse!uro
C!digo inseguro es todo a@u,l !ragmento de cdigo en C# dentro del cual es posi"le (acer uso de
punteros&
1n "untero en C# es una varia"le @ue es capa/ de almacenar direcciones de memoria& ;eneralmente
suele usarse para almacenar direcciones @ue almacenen o"jetosB por lo @ue en esos casos su signi!icado
es similar al de varia"les normales de tipos re!erencia& Sin em"argoB los punteros no cuentan con
muc(as de las restricciones de ,stas a la (ora de acceder al o"jeto& Por ejemploB al accederse a los
elementos de una ta"la mediante un puntero no se pierde tiempo en compro"ar @ue el ndice
especi!icado se encuentre dentro de los lmites de la ta"laB lo @ue permite @ue el acceso se (aga m$s
r$pidamente&
-parte de su mayor e!icienciaB tam"i,n (ay ciertos casos en @ue es necesario disponer del cdigo
inseguroB como cuando se desea (acer llamadas a !unciones escritas en lenguajes no gestionados cuyos
par$metros tengan @ue ser punteros&
%s importante se7alar @ue los punteros son una e*cepcin en el sistema de tipos de &8%.B ya @ue no
derivan de la clase primigenia S(stem.bjectB por lo @ue no dispondr$n de los m,todos comunes a
todos los o"jetos y una varia"le object no podr$ almacenarlos =tampoco e*isten procesos similares al
"o*ing y un"o*ing @ue permitan simularlo?
Compilaci%n de c%di!os inse!uros
%l uso de punteros (ace el cdigo m$s proclive a !allos en tanto @ue se salta muc(as de las medidas
incluidas en el acceso normal a o"jetosB por lo @ue es necesario incluir ciertas medidas de seguridad
@ue eviten la introduccin accidental de esta inseguridad
#a primera medida tomada consiste en @ue e*plcitamente (ay @ue indicar al compilador @ue
deseamos compilar cdigo inseguro& Para elloB al compilador de lnea de comandos (emos de pasarle la
opcin AunsafeB como se muestra el ejemploA
csc cdigoInseguro&cs Iunsa!e

Si no se indica la opcin unsa!eB cuando el compilador detecte algCn !uente con cdigo inseguro
producir$ un mensaje de error como el siguienteA
cdigoInseguro=VB9O?A error CS:9YYA unsa!e code may only appear i! compiling 'it( Iunsa!e
%n caso de @ue la compilacin se vaya a reali/ar a trav,s de Visual Studio&8%.B la !orma de indicar
@ue se desea compilar cdigo inseguro es activando la casilla /ie% @ 1ro"ert( 1ages @ Configuration
1ro"erties @ =uild @ Fllo% unsafe code bloc's
&arcado de c%di!os inse!uros
-parte de !or/arse a indicar e*plcitamente @ue se desea compilar cdigo inseguroB C# tam"i,n
o"liga a @ue todo uso de cdigo inseguro @ue se (aga en un !ic(ero !uente tenga @ue ser e*plcitamente
indicado como tal& - las /onas de cdigo donde se usa cdigo inseguro se les denomina conte)tos
insegurosB y C# o!rece varios mecanismos para marcar este tipo de conte*tos&
1na primera posi"ilidad consiste en preceder un "lo@ue de instrucciones de la pala"ra reservada
unsafe siguiendo la siguiente sinta*isA
unsafe <instrucciones>
%n el cdigo incluido en jinstrucciones6 podr$n de!inirse varia"les de tipos puntero y podr$ (acerse
uso de las mismas& Por ejemploA
public void f()
{
unsafe
{
int *x;
}
}
Otra !orma de de!inir conte*tos inseguros consiste en a7adir el modi!icador unsafe a la de!inicin de
un miem"roB caso en @ue dentro de su de!inicin se podr$ (acer uso de punteros& -s es posi"le de!inir
campos de tipo punteroB m,todos con par$metros de tipos punteroB etc& %l siguiente ejemplo muestra
cmo de!inir dos campos de tipo puntero& 8tese sin em"argo @ue no es posi"le de!inir los dos en una
misma lneaA

struct PuntoInseguro
{
public unsafe int *X; // No es vlido hacer public unsafe int *X, Y;
public unsafe int *Y; // Tampoco lo es hacer public unsafe int *X, *Y;
}
O"viamenteB en un m,todo @ue incluya el modi!icador unsafe no es necesario preceder con dic(a
pala"ra sus "lo@ues de instrucciones inseguros&
Hay @ue tener en cuenta @ue el a7adido de modi!icadores unsafe es completamente inocuo& %s decirB
no in!luye para nada en cmo se (aya de rede!inir y si un m,todo Main;< lo tiene sigue siendo un punto
de entrada v$lido&
1na tercera !orma consiste en a7adir el modi!icador unsafe en la de!inicin de un tipoB caso en @ue
todas las de!iniciones de miem"ros del mismo podr$n incluir cdigo inseguro sin necesidad de a7adir a
cada una el modi!icador unsafe o preceder sus "lo@ues de instrucciones inseguras de la pala"ra
reservada unsafe& Por ejemploA

unsafe struct PuntoInseguro
{
public int * X, *Y;
}

'efinici%n de punteros
Para de!inir una varia"le puntero de un determinado tipo se sigue una sinta*is parecida a la usada
para de!inir varia"les normales slo @ue al nom"re del tipo se le postpone un sm"olo de asterisco =G? O
seaB un puntero se de!ine asA
<tipo> ? <nombrePuntero>$
Por ejemploB una varia"le puntero llamada a @ue pueda almacenar re!erencias a posiciones de
memoria donde se almacenen o"jetos de tipo int se declara asA
int * a;
%n caso de @uererse declarar una ta"la de punterosB entonces el asterisco (ay @ue incluirlo tras el
nom"re del tipo pero antes de los corc(etes& Por ejemploB una ta"la de nom"re t @ue pueda almacenar
punteros a o"jetos de tipo int se declara asA
int*[] t;
Hay un tipo especial de puntero @ue es capa/ de almacenar re!erencias a o"jetos de cual@uier tipo&
[stos punteros se declaran indicando void como jtipo6& Por ejemploA
void * punteroACualquierCosa;
Hay @ue tener en cuenta @ue en realidad lo @ue indica el tipo @ue se d, a un puntero es cu$l es el tipo
de o"jetos @ue se (a de considerar @ue se almacenan en la direccin de memoria almacenada por el
puntero& Si se le da el valor void lo @ue se est$ diciendo es @ue no se desea @ue se considere @ue el
puntero apunta a ningCn tipo espec!ico de o"jeto& %s decirB no se est$ dando in!ormacin so"re el tipo
apuntado&
Se pueden declarar mCltiples varia"les locales de tipo puntero en una misma lnea& %n ese caso el
asterisco slo (ay @ue incluirlo antes del nom"re de la primera& Por ejemploA
int * a, b; // a y b son de tipo int * No sera vlido haberlas definido
como int *a, *b;
Hay @ue tener en cuenta @ue esta sinta*is especial para de!inir en una misma de!inicin varios
punteros de un mismo tipo slo es v$lida en de!iniciones de varia"les locales& -l de!inir campos no
sirve y (ay @ue dar para cada campo una de!inicin independiente&
%l recolector de "asura no tiene en cuenta los datos a los @ue se re!erencie con punterosB pues (a de
conocer cu$l es el o"jeto al re!erenciado por cada varia"le y un puntero en realidad no tiene por@u,
almacenar re!erencias a o"jetos de ningCn tipo en concreto& Por ejemploB pueden tenerse punteros int G
@ue en realidad apunten a o"jeto charB o punteros void G @ue no almacenen in!ormacin so"re el tipo
de o"jeto al @ue de"era considerarse @ue apuntanB o punteros @ue apunte a direcciones donde no (ayan
o"jetosB etc&
Como el recolector de "asura no tra"aja con punterosB no es posi"le de!inir punteros de tipos @ue se
almacenen en memoria din$mica o contengan miem"ros @ue se almacenen en memoria din$micaB ya
@ue entonces podra ocurrir @ue un o"jeto slo re!erenciado a trav,s de punteros sea destruido por
considerar el recolector @ue nadie le re!erencia"a& Por elloB slo es v$lido de!inir punteros de tipos
cuyos o"jetos se puedan almacenar completamente en pilaB pues la vida de estos o"jetos no est$
controlada por el recolector de "asura sino @ue se destruyen cuando se a"andona el $m"ito donde
!ueron de!inidos&
%n concretoB los Cnicos punteros v$lidos son a@uellos @ue apunten a tipos valor "$sicosB
enumeraciones o estructuras @ue no contengan campos de tipos re!erencias& .am"i,n pueden de!inirse
punteros a tipos punteroB como se muestra en el siguiente ejemplo de declaracin de un puntero a
punteros de tipo int llamando puntero-punterosA
int ** punteroApunteros;
O"viamente la anidacin puede (acerse a cual@uier nivel de pro!undidadB pudi,ndose de!inir
punteros a punteros a punterosB o punteros a punteros a punteros a punterosB etc&
&anipulaci%n de punteros
-btencin de direccin de memoria. -perador 3
Para almacenar una re!erencia a un o"jeto en un puntero se puede aplicar al o"jeto el operador
pre!ijo NB @ue lo @ue (ace es devolver la direccin @ue en memoria ocupa el o"jeto so"re el @ue se
aplica& 1n ejemplo de su uso para iniciali/ar un puntero esA
int x =10;
int * px = &x;
%ste operador no es aplica"le a e*presiones constantesB pues ,stas no se almacenan en ninguna
direccin de memoria espec!ica sino @ue se incrustan en las instrucciones& Por elloB no es v$lido (acer
directamenteA
int px = &10; // Error 10 no es una variable con direccin propia
.ampoco es v$lido aplicar N a campos readonl(B pues si estos pudiesen ser apuntados por punteros
se correra el riesgo de poderlos modi!icar ya @ue a trav,s de un puntero se accede a memoria
directamenteB sin tenerse en cuenta si en la posicin accedida (ay algCn o"jetoB por lo @ue muc(o
menos se considerar$ si ,ste es de slo lectura&
#o @ue es s v$lido es almacenar en un puntero es la direccin de memoria apuntada por otro
puntero& %n ese caso am"os punteros apuntaran al mismo o"jeto y las modi!icaciones a ,ste reali/adas
a trav,s de un puntero tam"i,n a!ectaran al o"jeto visto por el otroB de !orma similar a como ocurre
con las varia"les normales de tipos re!erencia& %s m$sB los operadores relacionales tpicos =&&B ,&B HB IB
H& y I&? se (an rede!inido para @ue cuando se apli@uen entre dos punteros de cuales@uiera dos tipos lo
@ue se compare sean las direcciones de memoria @ue estos almacenan& Por ejemploA

int x = 10;
int px = &x;
int px2 = px; // px y px2 apuntan al objeto almacenado en x
Console.WriteLine( px == px2); // Imprime por pantalla True
%n realidad las varia"les so"re las @ue se apli@ue N no tienen por@u, estar iniciali/adas& Por
ejemploB es v$lido (acerA

private void f()
{
int x;
unsafe
{ int px = &x;}
}
%sto se de"e a @ue uno de los principales usos de los punteros en C# es poderlos pasar como
par$metros de !unciones no gestionadas @ue esperen reci"ir punteros& Como muc(as de esas !unciones
(an sido programadas para iniciali/ar los contenidos de los punteros @ue se les pasanB pasarles punteros
iniciali/ados implicara perder tiempo innecesariamente en iniciali/arlos&
Acceso a contenido de puntero. -perador 4
1n puntero no almacena directamente un o"jeto sino @ue suele almacenar la direccin de memoria
de un o"jeto =o seaB apunta a un o"jeto? Para o"tener a partir de un puntero el o"jeto al @ue apunta (ay
@ue aplicarle al mismo el operador pre!ijo GB @ue devuelve el o"jeto apuntado& Por ejemploB el siguiente
cdigo imprime en pantalla un F:A
int x = 10;
int * px= &x;
Console.WriteLine(*px);
%s posi"le en un puntero almacenar null para indicar @ue no apunta a ninguna direccin v$lida& Sin
em"argoB si luego se intenta acceder al contenido del mismo a trav,s del operador G se producir$
generalmente una e*cepcin de tipo NullCeferenceE)ce"tion =aun@ue realmente esto depende de la
implementacin del lenguaje? Por ejemploA
int * px = null;
Console.WriteLine(*px); // Produce una NullReferenceException
8o tiene sentido aplicar G a un puntero de tipo void G ya @ue estos punteros no almacenan
in!ormacin so"re el tipo de o"jetos a los @ue apuntan y por tanto no es posi"le recuperarlos a trav,s de
los mismos ya @ue no se sa"e cuanto espacio en memoria a partir de la direccin almacenada en el
puntero ocupa el o"jeto apuntado yB por tantoB no se sa"e cuanta memoria (ay @ue leer para o"tenerlo&
Acceso a miembro de contenido de puntero. -perador 56
Si un puntero apunta a un o"jeto estructura @ue tiene un m,todo D;< sera posi"le llamarlo a trav,s
del puntero conA
(*objeto).F();
Sin em"argoB como llamar a o"jetos apuntados por punteros es algo "astante (a"itualB para !acilitar
la sinta*is con la @ue (acer esto se (a incluido en C# el operador +IB con el @ue la instruccin anterior
se escri"ira asA
objeto->f();
%s decirB del mismo modo @ue el operador . permite acceder a los miem"ros de un o"jeto
re!erenciado por una varia"le normalB +I permite acceder a los miem"ros de un o"jeto re!erenciado por
un puntero& %n generalB un acceso de la !orma O +I M es e@uivalente a (acer ;GO<.M& Por tantoB al igual
@ue es incorrecto aplicar G so"re punteros de tipo void GB tam"i,n lo es aplicar +I
Con#ersiones de punteros
)e todo lo visto (asta a(ora parece @ue no tiene muc(o sentido el uso de punteros de tipo void G
Pues "ienB una utilidad de este tipo de punteros es @ue pueden usarse como almac,n de punteros de
cual@uier otro tipo @ue luego podr$n ser recuperados a su tipo original usando el operador de
conversin e*plcita& %s decirB igual @ue los o"jetos de tipo object pueden almacenar implcitamente
o"jetos de cual@uier tipoB los punteros void G pueden almacenar punteros de cual@uier tipo y son Ctiles
para la escritura de m,todos @ue puedan aceptar par$metros de cual@uier tipo de puntero&
- di!erencia de lo @ue ocurre entre varia"les normalesB las conversiones entre punteros siempre se
permitenB al reali/arlas nunca se comprue"a si son v$lidas& Por ejemploA
char c = 'A';
char* pc = &c;
void* pv = pc;
int* pi = (int*)pv;
int i = *pi;// Almacena en 16 bits del char de pi + otros 16
// indeterminados
Console.WriteLine(i);
*pi = 123456;// Machaca los 32 bits apuntados por pi

%n este cdigo pi es un puntero a un o"jeto de tipo int =O9 "its?B pero en realidad el o"jeto al @ue
apunta es de tipo char =FZ "its?B @ue es m$s pe@ue7o& %l valor @ue se almacene en i es en principio
inde!inidoB pues depende de lo @ue (u"iese en los FZ "its e*tras resultantes de tratar "v como puntero a
int cuando en realidad apunta"a a un char&
)el mismo modoB conversiones entre punteros pueden terminar produciendo @ue un puntero apunte a
un o"jeto de mayor tama7o @ue los o"jetos del tipo del puntero& %n estos casosB el puntero apuntara a
los "its menos signi!icativos del o"jeto apuntado&
.am"i,n es posi"le reali/ar conversiones entre punteros y tipos "$sicos enteros& #a conversin de un
puntero en un tipo entero devuelve la direccin de memoria apuntada por el mismo& Por ejemploB el
siguiente cdigo muestra por pantalla la direccin de memoria apuntada por ")A
int x = 10;
int *px = &x;
Console.WriteLine((int) px);
Por su parteB convertir cual@uier valor entero en un puntero tiene el e!ecto de devolver un puntero
@ue apunte a la direccin de memoria indicada por ese nCmero& Por ejemploB el siguiente cdigo (ace
@ue ") apunte a la direccin F:9d y luego imprime por pantalla la direccin de memoria apuntada por
") =@ue ser$ F:9d?A
int *px = (int *) 10;
Console.WriteLine((int) px);
8tese @ue aun@ue en un principio es posi"le (acer @ue un puntero almacene cual@uier direccin de
memoriaB si dic(a direccin no pertenece al mismo proceso @ue el cdigo en @ue se use el puntero se
producir$ un error al leer el contenido de dic(a direccin& %l tipo de error (a producir no se indica en
principio en la especi!icacin del lenguajeB pero la implementacin de Microso!t lan/a una re!erencia
NullCeferenceE)ce"tion& Por ejemploB el siguiente cdigo produce una e*cepcin de dic(o tipo al
ejecurtaseA

using System;

class AccesoInvlido
{
public unsafe static void Main()
{
int * px = (int *) 100;
Console.Write(*px); // Se lanza NullReferenceException
}
}
-ritm,tica de punteros
#os punteros se suelen usar para recorrer ta"las de elementos sin necesidad de tener @ue
compro"arse @ue el ndice al @ue se accede en cada momento se encuentra dentro de los lmites de la
ta"la& Por elloB los operadores aritm,ticos de!inidos para los punteros est$n orientados a !acilitar este
tipo de recorridos&
Hay @ue tener en cuenta @ue todos los operadores aritm,ticos aplica"les a punteros dependen del
tama7o del tipo de dato apuntadoB por lo @ue no son aplica"les a punteros void G ya @ue estos no
almacenan in!ormacin so"re dic(o tipo& %sos operadores sonA
** y ++A %l operador ** no suma uno a la direccin almacenada en un punteroB sino @ue le suma
el tama7o del tipo de dato al @ue apunta& -sB si el puntero apunta"a a un elemento de una ta"la
pasar$ a apuntar al siguiente =los elementos de las ta"las se almacenan en memoria
consecutivamente? )el mismo modoB ++ resta a la direccin almacenada en el puntero el tama7o
de su tipo de dato& Por ejemploB una ta"la de F:: elementos a cuyo primer elemento
inicialmente apuntase "t podra recorrerse asA
for (int i=0; i<100; i++)
Console.WriteLine("Elemento{0}={1}", i, (*p)++);
%l pro"lema @ue puede plantear en ciertos casos el uso de ** y ++ es @ue (acen @ue al !inal del
recorrido el puntero deje de apuntar al primer elemento de la ta"la& %llo podra solucionarse
almacenando su direccin en otro puntero antes de iniciar el recorrido y restaur$ndola a partir de ,l tras
!inali/arlo&
* y +A Permiten solucionar el pro"lema de ** y ++ antes comentado de una !orma m$s cmoda
"asada en sumar o restar un cierto entero a los punteros& * devuelve la direccin resultante de
sumar a la direccin almacenada en el puntero so"re el @ue se aplica el tama7o del tipo de dic(o
puntero tantas veces como indi@ue el entero sumado& + tiene el mismo signi!icado pero r estando
dic(a cantidad en ve/ de sumarla& Por ejemploB usando * el "ucle anterior podra rescri"irse asA

for (int i=0; i<100; i++)
Console.WriteLine("Elemento{0}={1}", i, *(p+i));
%l operador + tam"i,n puede aplicarse entre dos punteros de un mismo tipoB caso en @ue devuelve
un long @ue indica cu$ntos elementos del tipo del puntero pueden almacenarse entre las direcciones de
los punteros indicados&
-.A )ado @ue es !recuente usar * para acceder a elementos de ta"lasB tam"i,n se (a rede!inido el
operador -. para @ue cuando se apli@ue a una ta"la (aga lo mismo y devuelva el o"jeto
contenido en la direccin resultante& O sea G;p*i< es e@uivalente a p-i.B con lo @ue el cdigo
anterior e@uivale aA
for (int i=0; i<100; i++)
Console.WriteLine("Elemento{0}={1}", i, p[i]);
8o (ay @ue con!undir el acceso a los elementos de una ta"la aplicando -. so"re una varia"le de tipo
ta"la normal con el acceso a trav,s de un puntero @ue apunte a su primer elemento& %n el segundo caso
no se comprue"a si el ndice indicado se encuentra dentro del rango de la ta"laB con lo @ue el acceso es
m$s r$pido pero tam"i,n m$s proclive a errores di!ciles de detectar&
inalmenteB respecto a la aritm,tica de punterosB (ay @ue tener en cuenta @ue por e!icienciaB en las
operaciones con punteros nunca se comprue"a si se producen des"ordamientosB y en caso de producirse
se truncan los resultados sin avisarse de ello mediante e*cepciones& Por eso (ay @ue tener especial
cuidado al operar con punteros no sea @ue un des"ordamiento no detectado cause errores de causas
di!ciles de encontrar&
Operadores relacionados con c%di!o inse!uro
-perador si0eo". -btencin de tama7o de tipo
%l operador unario y pre!ijo sizeof devuelve un o"jeto int con el tama7o en "ytes del tipo de dato
so"re el @ue se aplica& Slo puede aplicarse en conte*tos inseguros y slo a tipos de datos para los @ue
sea posi"le de!inir punterosB siendo su sinta*is de usoA
sieof(<tipo>)
Cuando se aplica a tipos de datos "$sicos su resultado es siempre constante& Por elloB el compilador
optimi/a dic(os usos de sizeof sustituy,ndolos internamente por su valor =inlining? y considerando @ue
el uso del operador es una e*presin constante& %stas constantes correspondientes a los tipos "$sicos
son las indicadas en la Tabla 2`A
Ti"os Cesultado
s"yteB "yteB "ool F
s(ortB us(ortB c(ar 9
intB uintB !loat X
longB ulongB dou"le G
.a"la F:A +esultados de si/eo! para tipos "$sicos
Para el resto de tipos a los @ue se les puede aplicarB sizeof no tiene por@u, devolver un resultado
constante sino @ue los compiladores pueden alinear en memoria las estructuras incluyendo "its de
relleno cuyo nCmero y valores sean en principio indeterminado& Sin em"argoB el valor devuelto por
sizeof siempre devolver$ el tama7o en memoria e*acto del tipo de dato so"re el @ue se apli@ueB
incluyendo "its de relleno si los tuviese&
8tese @ue es !$cil implementar los operadores de aritm,tica de punteros usando sizeof& Para elloB *
* se de!inira como a7adir a la direccin almacenada en el puntero el resultado de aplicar sizeof a su
tipo de datoB y ++ consistira en restarle dic(o valor& Por su parteB el operador * usado de la !orma P D 8
=P es un puntero de tipo . y 8 un entero? lo @ue devuelve es el resultado de a7adir al puntero
si/eo!=.?48B y P H 8 devuelve el resultado de restarle si/eo!=.?48& Por CltimoB si se usa + para restar
dos punteros PF y P9 de tipo .B ello es e@uivalente a calcular ===long?PF? 5 ==long?P9???Isi/eo!=.?
-perador stac1alloc. Creacin de tablas en pila.
Cuando se tra"aja con punteros puede resultar interesante reservar una /ona de memoria en la pila
donde posteriormente se puedan ir almacenando o"jetos& Precisamente para eso est$ el operador
stac'allocB @ue se usa sigui,ndose la siguiente sinta*isA
stackalloc <tipo>[<nmero>]
stac'alloc reserva en pila el espacio necesario para almacenar contiguamente el nCmero de o"jetos
de tipo jtipo6 indicado en jnCmero6 =reserva si/eo!=jtipo6?4jnCmero6 "ytes? y devuelve un puntero
a la direccin de inicio de ese espacio& Si no @uedase memoria li"re su!iciente para reservarlo se
producira una e*cepcin S(stem.Stac'verflo%E)ce"tion&
stac'alloc slo puede usarse para iniciali/ar punteros declarados como varia"les locales y slo en el
momento de su declaracin&& Por ejemploB un puntero pt @ue apuntase al principio de una regin con
capacidad para F:: o"jetos de tipo int se declarara conA
int * pt = stackalloc int[100];
Sin em"argoB no sera v$lido (acerA
int * pt;
pt = stackalloc int[100];//ERROR:Slo puede usarse stackalloc
//en declaraciones
-un@ue pueda parecer @ue stac'alloc se usa como sustituto de ne% para crear ta"las en pila en lugar
de en memoria din$micaB no (ay @ue con!undirseA stac'alloc slo reserva un espacio contiguo en pila
para o"jetos de un cierto tipoB pero ello no signi!ica @ue se cree una ta"la en pila& #as ta"las son o"jetos
@ue (eredan de S(stem.Frra( y cuentan con los miem"ros (eredados de esta clase y de objectB pero
regiones de memoria en pila reservadas por stac'alloc no& Por ejemploB el siguiente cdigo es inv$lido&

int[] tabla;
int * pt = stackalloc int[100];
tabla = *pt; //ERROR: El contenido de pt es un int, no una tabla (int[])
Console.WriteLine(pt->Length); // ERROR: pt no apunta a una tabla
Sin em"argoB gracias a @ue como ya se (a comentado en este tema el operador -. est$ rede!inido para
tra"ajar con punterosB podemos usarlo para acceder a los di!erentes o"jetos almacenados en las
regiones reservadas con stac'alloc como si !uesen ta"las& Por ejemploB este cdigo guarda en pila los
F:: primeros enteros y luego los imprimeA

class Stackalloc
{
public unsafe static void Main()
{
int * pt = stackalloc int[100];
for (int i=0; i<100; i++)
pt[i] = i;
for(int i=0; i<100; i++)
System.Console.WriteLine(pt[i]);
}
}
8tese @ueB a di!erencia de lo @ue ocurrira si pt !uese una ta"laB en los accesos con ptRiS no se
comprue"a @ue i no supere el nCmero de o"jetos para los @ue se (a reservado memoria& Como
contrapartidaB se tiene el inconveniente de @ue al no ser pt una ta"la no cuenta con los m,todos tpicos
de ,stas y no puede usarse foreach para recorrerla&
Otra ventaja de la simulacin de ta"las con stac'alloc es @ue se reserva la memoria muc(o m$s
r$pido @ue el tiempo @ue se tardara en crear una ta"la& %sto se de"e a @ue reservar la memoria
necesaria en pila es tan sencillo como incrementar el puntero de pila en la cantidad correspondiente al
tama7o a reservarB y no (ay @ue perder tiempo en solicitar memoria din$mica& -dem$sB stac'alloc no
pierde tiempo en iniciali/ar con algCn valor el contenido de la memoriaB por lo @ue la gta"lag se crea
antes pero a costa de @ue luego sea m$s inseguro usarla ya @ue (ay @ue tener cuidado con no leer tro/os
de ella antes de asignarles valores v$lidos&
0ijaci%n de variables apuntadas
-un@ue un puntero slo puede apuntar a datos de tipos @ue puedan almacenarse completamente en
pila =o seaB @ue no sean ni o"jetos de tipos re!erencia ni estructuras con miem"ros de tipos re!erencia?B
nada garanti/a @ue los o"jetos apuntados en cada momento est,n almacenados en pila& Por ejemploB las
varia"les est$ticas de tipo int o los elementos de una ta"la de tipo int se almacenan en memoria
din$mica aCn cuando son o"jetos a los @ue se les puede apuntar con punteros&
Si un puntero almacena la direccin de un o"jeto almacenado en memoria din$mica y el recolector
de "asura cam"ia al o"jeto de posicin tras una compactacin de memoria resultante de una
recoleccinB el valor almacenado en el puntero dejar$ de ser v$lido& Para evitar @ue esto ocurra se
puede usar la instruccin fi)edB cuya sinta*is de uso esA
fixed(<tipo> <declaraciones>)
<instrucciones>
%l signi!icado de esta instruccin es el siguienteA se asegura @ue durante la ejecucin del "lo@ue de
jinstrucciones6 indicado el recolector de "asura nunca cam"ie la direccin de ninguno de los o"jetos
apuntados por los punteros de tipo jtipo6 declarados& %stas jdeclaraciones6 siempre (an de incluir una
especi!icacin de valor inicial para cada puntero declaradoB y si se declaran varios se (an de separar
con comas&
#os punteros declarados en jdeclaraciones6 slo e*istir$n dentro de jinstrucciones6B y al salir de
dic(o "lo@ue se destruir$n& -dem$sB si se les indica como valor inicial una ta"la o cadena @ue valga
null saltar$ una NullCeferenceE)ce"tion& .am"i,n (ay @ue se7alar @ue aun@ue slo pueden declarase
punteros de un mismo tipo en cada fi)edB se puede simular !$cilmente la declaracin de punteros de
distintos tipos anidando varios fi)ed&
Por otro ladoB los punteros declarados en jdeclaraciones6 son de slo lecturaB ya @ue si no podra
cam"i$rseles su valor por el de una direccin de memoria no !ijada y conducir ello a errores di!ciles de
detectar&
1n uso !recuente de fi)ed consiste en apuntar a o"jetos de tipos para los @ue se puedan declarar
punteros pero @ue est,n almacenados en ta"lasB ya @ue ello no se puede (acer directamente de"ido a
@ue las ta"las se almacenan en memoria din$mica& Por ejemploB copiar usando punteros una ta"la de
F:: elementos de tipo int en otra se (ara asA
class CopiaInsegura
{
public unsafe static void Main()
{
int[] tOrigen = new int[100];
int[] tDestino = new int[100];
fixed (int * pOrigen=tOrigen, pDestino=tDestino)
{
for (int i=0; i<100; i++)
pOrigen[i] = pDestino[i];
}
}
}
Como puede deducirse del ejemploB cuando se iniciali/a un puntero con una ta"laB la direccin
almacenada en el puntero en la /ona jdeclaraciones6 del fi)ed es la del primer elemento de la ta"la
=tam"i,n podra (a"erse (ec(o pOrigen M 3tOrigenR:S?B y luego es posi"le usar la aritm,tica de
punteros para acceder al resto de elementos a partir de la direccin del primero ya @ue ,stos se
almacenan consecutivamente&
-l igual @ue ta"lasB tam"i,n puede usarse fi)ed para recorrer cadenas& %n este caso lo @ue (ay @ue
(acer es iniciali/ar un puntero de tipo char G con la direccin del primer car$cter de la cadena a la @ue
se desee @ue apunte tal y como muestra este ejemplo en el @ue se cam"ia el contenido de una cadena
gHolag por gPPPPgA
class CadenaInsegura
{
public unsafe static void Main()
{
string s="Hola";
Console.WriteLine("Cadena inicial: {0}", s);
fixed (char * ps=s)
{
for (int i=0;i<s.Length;i++)
ps[i] = 'A';
}
Console.WriteLine("Cadena final: {0}", s);
}
}
#a salida por pantalla de este Cltimo programa esA
Hola
----
#a ventaja de modi!icar la cadena mediante punteros es @ue sin ellos no sera posi"le (acerlo ya @ue
el indi/ador de!inido para los o"jetos string es de slo lectura&
Cuando se modi!i@uen cadenas mediante punteros (ay @ue tener en cuenta @ueB aun@ue para !acilitar
la comunicacin con cdigo no gestionado escrito en C o CDD las cadenas en C# tam"i,n aca"an en el
car$cter h\:iB no se recomienda con!iar en ello al recorrerlas con punteros por@ue h\:i tam"i,n puede
usarse como car$cter de la cadena& Por elloB es mejor (acer como en el ejemplo y detectar su !inal a
trav,s de su propiedad :ength&
Hay @ue se7alar @ue como fi)ed provoca @ue no pueda cam"iarse de direccin a ciertos o"jetos
almacenados en memoria din$micaB ello puede producir la generacin de (uecos en memoria din$micaB
lo @ue tiene dos e!ectos muy negativosA
%l recolector de "asura est$ optimi/ado para tra"ajar con memoria compactadaB pues si todos
los o"jetos se almacenan consecutivamente en memoria din$mica crear uno nuevo es tan
sencillo como a7adirlo tras el Cltimo& Sin em"argoB fi)ed rompe esta consecutividad y la
creacin de o"jetos en memoria din$mica dentro de este tipo de instrucciones es m$s lenta
por@ue (ay @ue "uscar (uecos li"res&
Por de!ectoB al eliminarse o"jetos de memoria durante una recoleccin de "asura se compacta la
memoria @ue @ueda ocupada para @ue todos los o"jetos se almacenen en memoria din$mica&
Hacer esto dentro de sentencias fi)ed es m$s lento por@ue (ay @ue tener en cuenta si cada
o"jeto se puede o no mover&
Por estas ra/ones es conveniente @ue el contenido del "lo@ue de instrucciones de una sentencia fi)ed
sea el mnimo posi"leB para @ue as el fi)ed se ejecute lo antes posi"le&
Novedades de C# 3.`
Introducci!n
%l 9X de Octu"re de 9::O Microso!t (i/o pC"lico el primer "orrador de lo @ue sera la versin 9&: del
lenguaje C#B incluida en la nueva versin del &8%. rame'or2 conocida con el nom"re clave
9hidbe(& %n ella se introduca una importante novedad en el C#+ consistente en proporcionar soporte
para tipos gen,ricos @ue se pudiesen usar como plantillas en "ase a la @ue de!inir otros tipos& %sto
lgicamente implica"a @ue a los lenguajes &8%. de Microso!t en primer lugarB y presumi"lemente el
resto despu,sB se les (iciesen tam"i,n modi!icaciones orientadas a aprovec(ar esta nueva
!uncionalidad&
%n este tema se e*plican las novedades para ello incluidas en la versin 9&: de C#B as como otras
novedades no directamente relacionadas con los gen,ricos @ue tam"i,n incorporaA los iteradores para
!acilitar la implementacin de las inter!aces IEnumerable e IEnumeratorB los mKtodos an!nimos y
otros mecanismos destinados a !acilitar el tra"ajo con los delegadosB la capacidad de dividir las
de!iniciones de las clases entre varios !ic(eros a trav,s de clases "arcialesB la posi"ilidad de asignar
null a los tipos valor a trav,s de los nuevos ti"os valor anulablesB etc&
%n principioB las modi!icaciones introducidas en C# se (an dise7ado con la idea de mantener el
m$)imo nivel de com"atibilidad con cdigos escritos para las anteriores versiones del lenguaje H
versiones 2.Y5& Por elloB las nuevas pala"ras con signi!icado especial introducidas =%hereB (ieldB etc&?
no se han clasificado como reservadasB de modo @ue seguir$n siendo v$lidos los identi!icadores @ue
se (u"iesen declarados con sus nom"res& Slo se (an introducido unas m0nimas incom"atibilidades
relacionadas con la sinta*is de los gen,ricos @ue se descri"en en el epgra!e 0mbi(>edades del tema&
1enricos
Concepto de $en&ricos
C# 9&: permite especi!icar los tipos utili/ados en las de!iniciones de otros tipos de datos y de
m,todos de !orma parametri/adaB de manera @ue en ve/ de indicarse e*actamente cu$les son se colo@ue
en su lugar un par$metro H"ar$metro ti"o5 @ue se concretar$ en el momento en @ue se vayan a usar =al
crear un o"jeto de la claseB llamar al m,todoBs? - estas de!iniciones se les llama genKricosB y un
ejemplo de una de ellas es el siguienteA
public class A<T>
{
T valor;
public void EstablecerValor(T valor)
{
this.valor = valor;
}
}
%n esta clase no se (an concretando ni el tipo del campo privado valor ni el del Cnico par$metro del
m,todo %sta"lecerValor=? %n su lugar se le especi!icado un par$metro tipo . @ue se concretar$ al
utili/ar la clase& Por ejemploB al crear un o"jeto suyoA
A<int> obj = new A<int>();
%sto creara un o"jeto de la clase gen,rica - con el par$metro tipo . concreti/ado con el argumento
ti"o int& #a primera ve/ @ue el C#+ encuentre esta concreti/acin de . a int reali/ar$ un proceso de
e)"ansi!n o instanciaci!n del genKrico consistente en generar una nueva clase con el resultado de
sustituir en la de!inicin gen,rica toda aparicin de los par$metros tipos por los argumentos tipo& Para
el ejemplo anterior esta clase seraA
public class A<int>
{
int valor;
public void EstablecerValor(int valor)
{
this.valor = valor;
}
}
- los tipos con par$metros tipoB como -j.6B se les llama ti"os genKricos cerradosJ a los
generados al concret$rseles algCn par$metro tipo se le llama ti"os construidosJ y a los generados al
concret$rseles todos ti"os genKricos abiertos& #a relacin esta"lecida entre ellos es similar a la
esta"lecida entre las clases normales y los o"jetosA al igual @ue clases sirven de plantillas en "ase a las
@ue crear o"jetosB los tipos gen,ricos cerrados actCan como plantillas en "ase a las @ue crear tipos
gen,ricos a"iertos& Por esoB en el CDD tradicional se llama"a "lantillas a las construcciones
e@uivalentes a los gen,ricos&
#a e*pansin la (ace el C#+ en tiempo de ejecucinB a di!erencia de lo @ue sucede en otros entornos
=peB CDD? en los @ue se reali/a al compilar& %sto tiene varias ventajasA
Ensamblados m$s "eSueVosA Como slo almacenan el tipo gen,rico cerradoB @ue el C#+ ya
e*pandir$ en tiempo de ejecucinB su tama7o es m$s pe@ue7o y se evita el pro"lema del
e*cesivo in!lado del cdigo "inario generado =code bloat?
-dem$sB para evitar el in!lado de la memoria consumidaB el C#+ reutili/a gran parte del MSI#
generado para la primera e*pansin de un gen,rico por un tipo re!erencia en las siguientes e*pansiones
del mismo por otros tipos re!erenciaB ya @ue todas las re!erencias son al !in y al ca"o punteros @ue en
memoria se representan igual&
Metadatos ricosA -l almacenarse los tipos gen,ricos cerrados en los ensam"ladosB se podr$n
consultar mediante re!le*in y ser aprovec(ados por (erramientas como el IntelliSense de
Visual Studio&8%. para proporcionar ayuda so"re su estructura&
Im"lementaci!n f$cilA Como es el propio C#+ @uien reali/a gran parte del tra"ajo necesario
para dar soporte a los gen,ricosB la inclusin de los mismos en cual@uiera de los lenguajes &8%.
se simpli!ica considera"lemente&
2sos de los $en&ricos
#os gen,ricos no son una novedad introducida por C# en el mundo de la programacinB sino @ue
otros lenguajes como -daB %i!!el o CDD =plantillas? ya las incluyen desde (ace tiempo& Su principal
utilidad esB como su propio nom"re indicaB !acilitar la creacin de cdigo gen,rico @ue pueda tra"ajar
con datos de cual@uier tipo& %sto es especialmente Ctil para crear tipos @ue actCen como colecciones
=pilasB colasB listasB etc&?B cosa @ue C# F&P slo permita crear de!ini,ndolos en "ase a la clase "ase
comCn object& Por ejemploB una cola @ue admitiese o"jetos de cual@uier tipo (a"a @ue declararla como
sigueA
public class Cola
{
object[] elementos;
public int NmeroElementos;

public void Encolar(object valor);
{.}
public object Desencolar()
{.}
}
%l primer pro"lema de esta solucin es lo incmoda y proclive a errores @ue resulta su utili/acinB
pues a la (ora de e*traer valores de la cola (a"r$ @ue convertirlos a su tipo real si se @uieren aprovec(ar
sus miem"ros espec!icos& %s decirA
Cola miCola = new Cola();
miCola.Encolar("Esto es una prueba");
string valorDesencolado = (string) miCola.Desencolar();
-parte de @ue el programador tenga @ue escri"ir =string? cada ve/ @ue @uiera convertir alguna de las
cadenas e*tradas de miCola a su tipo concretoB k@u, ocurrir$ si por error introduce un valor @ue no es
ni string ni de un tipo converti"le a string =por ejemploB un int? y al e*traerlo sigue solicitando su
conversin a string> Pues @ue el compilador no se dar$ cuenta de nada y en tiempo de ejecucin saltar$
una InvalidCastE)ce"tion&
Para resolver esto podra pensarse en derivar un tipo ColaString de Cola cuyos m,todos pC"licos
tra"ajasen directamente con cadenas de te*tos =%ncolar=string valor? y string )esencolar=?? Sin
em"argoB no es una solucin !$cil de reutili/ar ya @ue para cual@uier otro tipo de elementos =peB una
cola de ints? (a"ra @ue derivar una nueva clase de Cola&
Otro pro"lema de am"as soluciones es su "ajo rendimientoB puesto @ue cada ve/ @ue se almacene un
o"jeto de un tipo re!erencia en la cola (a"r$ @ue convertir su re!erencia a una re!erencia a object y al
e*traerlo (a"r$ @ue volverla a trans!ormar en una re!erencia a string& QW para los tipos valor todava es
peor!B en tanto @ue (a"r$ @ue reali/ar "o*ing y un"o*ingB procesos @ue son muc(o m$s lentos @ue las
conversiones de re!erencias&
Si por el contrario se (u"iese de!inido la cola utili/ando gen,ricos tal y como sigueA
public class Cola<T>
{
T[] elementos;
public int NmeroElementos;
public void Encolar(T valor)
{.}
public T Desencolar()
{.}
}
%ntonces la e*traccin de o"jetos de la cola no re@uerira de ningCn tipo de conversin y sera tan
cmoda y clara como sigueA
Cola<string> miCola = new Cola<string>();
miCola.Encolar("Esto es una prueba");
string valorDesencolado = miCola.Desencolar();
Si a(ora por e@uivocacin el programador solicitase almacenar un o"jeto cuyo tipo no !uese ni
string ni converti"le a ,lB o"tendra un error al compilar in!orm$ndole de ello y evitando @ue el !allo
pueda llegar al entorno de ejecucin& -dem$sB el rendimiento del cdigo es muy superior ya @ue no
re@uerir$ conversiones de re!erencias aIdesde object& Si reali/a prue"as podr$ compro"ar @ue la
utili/acin de gen,ricos o!rece mejoras en el rendimiento entorno al 9:t para los tipos re!erenciaB Qy al
9::t para los tipos valor!
Sinta*is
%l C#+ de &8%. 9&: permite de!inir gen,ricamente tanto clases como estructurasB inter!acesB delegados
y m,todos& Para ello "asta con indicar tras el identi!icador de las mismas su lista de sus par$metros
gen,ricos entre sm"olos H y I separados por comas& Con elloB dentro de su de!inicin =miem"ros de
las clasesB cuerpos de los m,todosB etc&? se podr$ usar li"remente esos par$metros en cual@uier sitio en
@ue se espere un nom"re de un tipo& #a siguiente ta"la muestra un ejemplo para cada tipo de
construccin v$lidaA
Ejem"lo declaraci!n Ejem"lo uso

public class Nodo<T>
{
public T Dato;
public Nodo<T> Siguiente;
}

class Nodo8BitAvanzado: Nodo<byte>
{...}

public struct Pareja<T,U>
{
public T Valor1;
public U Valor2;
}

Pareja<int, string> miPareja;
miPareja.Valor1 = 1;
miPareja.Valor2 = "Hola";


interface IComparable<T>
{
int CompararCon(T otroValor);
}

class A: IComparable<Persona>
{

public int
CompararCon(Persona persona)
{...}
}

delegate void Tratar<T>(T valor);

Tratar<int> objTratar =
new Tratar<int>(F);


public void F(int x)
{...}

void intercambiar<T>(ref T valor1,
ref T valor2)
{

T temp = valor1;
valor1 = valor2;
valor2 = temp;

}
decimal d1 = 0, d2 = 1;

this.intercambiar<decimal>
(ref d1, ref d2);

this.intercambiar(ref d1, ref d2);
.a"la FdA %jemplos de declaracin de tipos y miem"ros gen,ricos
8tese @ue todos los ejemplos de nom"res de par$metros gen,ricos (asta a(ora vistos son Cnica letra
mayCsculas =.B 1B etc&? -un@ue o"viamente no es o"ligatorioB sino @ue se les puede dar cual@uier
identi!icador v$lidoB es el convenio de nomenclatura utili/ado en la 0C# del &8%. rame'or2 9&: y el
@ue por tanto se recomienda seguir& #o @ue s es o"ligatorio es no darles nunca un nom"re @ue coincida
con el del tipo o miem"ro al @ue est,n asociados o con el de alguno de los miem"ros de ,ste&
jese adem$s @ue la segunda llamada del ejemplo de utili/acin del m,todo gen,rico intercam"iar=?
no e*plicita el tipo del par$metro gen,rico& %sto se de"e a @ue C# puede reali/ar inferencia de ti"os y
deducir @ueB como para todos par$metros del tipo . se (a especi!icado un valor decimalB . de"e
concretarse como decimal&
%imitaciones
%n principioB dentro de los tipos gen,ricos se puede declarar cual@uier miem"ro @ue se pueda
declarar dentro de un tipo normalB aun@ue e*iste una limitacinA no se pueden declarar puntos de
entrada =m,todos Main;<?ya @ue a ,stos los llama el C#+ al iniciar la ejecucin del programa y no
(a"ra posi"ilidad de concreti/arles los argumentos tipo&
Por su parteB los "ar$metros ti"o se pueden usar en cual@uier sitio en @ue se espere un tipo aun@ue
tam"i,n con ciertas limitacionesA No "ueden usarse en atributosB aliasB "unteros o mKtodos
e)ternosB ni en los nom"res de las clases bases o de las interfaces im"lementadas& Sin em"argoB
e*cepto en el caso de los punterosB en estos sitios s @ue se pueden especi!icar tipos gen,ricos cerradosJ
e incluso en los nom"res de las clases o de las inter!aces "aseB tam"i,n se pueden usar tipos gen,ricos
a"iertos& Por ejemploA
// class A<T>: T {} // Error. No se puede usar T como interfaz
// o clase base
class A<T> {}
interface ',<V> {}
class B<T>: A<T>, ',<string> {} // OK.
)e"e tenerse cuidado al de!inir miem"ros con par$metros tipos ya @ue ello puede dar lugar a sutiles
am"ig<edades tal y como la @ue se tendra en el siguiente ejemploA
class A<T>
{
void F(int x, string s) {}
void F(T x, string s) {}
}
Si se solicitase la e*pansin -jint6B el tipo construido resultante aca"ara teniendo dos m,todos de
id,ntica signatura& -un@ue en principioB el compilador de C# 9&: de"era de asegurar @ue tras cual@uier
e*pansin siem"re se generen ti"os genKricos abiertos v$lidosB produciendo errores de compilacin
en caso contrarioB por el momento no lo (ace y deja compilar clases como la anterior& SencillamenteB si
llamamos al m,todo =? de un o"jeto -jint6B la versin del m,todo @ue se ejecutar$ es la primera& %s
decirB en las so"recargas los "ar$metros ti"o tienen menos "rioridad @ue los concretos&
)onde no resulta conveniente controlar @ue los par$metros gen,ricos puedan dar lugar a m,todos no
v$lidos es en las rede!iniciones de operadores de conversinB en concreto en lo re!erente al control de
@ue las e*pansiones puedan dar lugar a rede!iniciones de las conversiones prede!inidas =como las de
aIdesde object?B puesto @ue si se (iciese los par$metros tipo nunca se podran utili/ar en las
conversiones& Por elloB simplemente se ignoran las conversiones a medida Sue al e)"andirse
"uedan entrar en conflicto con las "redefinidas& Por ejemploB dado el siguiente cdigoA
using System;
public class ConversionGenerica<T>
{
public static implicit operator T(ConversionGenerica<T> objeto)
{
T obj = default(T);
Console.WriteLine("Operador de conversin implcita");
return obj;
}
}
public class Principal
{
public static void Main()
{
ConversionGenerica<Principal> objeto1=
new ConversionGenerica<Principal>();
Principal objeto2 = objeto1; // Conversin no predefinida (a Principal)
Console.WriteLine("Antes de conversin no predefinida");
ConversionGenerica<object> objeto3 = new ConversionGenerica<object>();
object objeto4 = objeto3; // Conversin predefinida (a object)
}
}
%l resultado de su ejecucin demuestra @ue la versin implcita de la conversin solo se ejecuta ante
la conversin no prede!inidaB puesto @ue su salida es la siguienteA
Operador de conversin implcita
-ntes de conversin no prede!inida
)onde nunca (a"r$ am"ig<edades es ante clases como la siguienteB ya @ue sea cual sea el tipo por el
@ue se concretice . siempre ser$ uno y por tanto nunca se podr$ dar el caso de @ue la segunda versin
de =? coincida en signatura con la primeraA
class A<T>
{
void F(int x, string s) {}
void F(T x, T s) {}
}
-s mismoB tam"i,n se admitiran dos m,todos como los siguientesB ya @ue se considera @ue los
"ar$metros ti"o forman "arte de las signaturasA
class A
{
void F<T>(int x, string s) {}
void F(int x, string s) {}
}
W al rede!inir m,todos (a"r$ @ue mantener el mismo nCmero de par$metros tipo en la clase (ija @ue
en la clase padre para as conservar la signatura& %stoB como en el caso de los par$metros normalesB no
implica mantener los nom"res de los par$metros tipoB sino slo su nCmero& Por tantoB cdigos como el
siguiente ser$n per!ectamente v$lidosA
public class A
{
protected virtual void F<T, U>(T parmetro1, U parmetro2)
{}
}
public class B:A
{
protected override void F<X, Y>(X parmetro1, Y parmetro2)
{}
}
+estricciones
Pro"a"lemente a estas alturas ya est, pensado @ue si en tiempo de dise7o no conoce el tipo concreto
de los par$metros gen,ricosB kcmo podr$ escri"ir cdigo @ue los use y !uncione independientemente
de su concreti/acin> %s decirB dado un m,todo comoA
T Opera<T>(T valor1, T valor2)
{
int resultadoComparacin = valor1.CompareTo(valor2);
if (resultadoComparacin>0)
return valor1-valor2 ;
else if(resultadoComparacin<0)
return Math.Pow(valor1, valor2) ;
else
return 2.0d;
}
Si se le llamase con Opera=9&:dB O&9d? no (a"ra pro"lemaB pues los o"jetos double tanto cuentan
con un m,todo Com"areTo;< v$lidoB como tienen de!inida la operacin de restaB se admiten como
par$metros del m,todo 1o%;< de la clase Math y van a generar valores de retorno de su mismo tipo
double& PeroB ky si se le llamase con Opera=g(olagB gadisg?> %n ese casoB aun@ue los o"jetos string
tam"i,n cuentan con un m,todo Com"areTo;< v$lidoB no admiten la operacin de restaB no se puede
pasar como par$metros a 1o%;< y el valor @ue devolvera return 9&:dJ no coincidira con el tipo de
retorno del m,todo&
%sta inconsistencias son !$ciles de solucionar en entornos donde la e*pansin se reali/a en tiempo de
compilacinB pues el compilador in!orma de ellas& Sin em"argoB en los @ue se (ace en tiempo de
ejecucin seran m$s graves ya @ue durante la compilacin pasaran desaperci"idas y en tiempo de
ejecucin podran causar errores di!ciles de detectar& Por elloB C# en principio slo permite @ue con los
o"jetos de tipos gen,ricos se realicen las operaciones gen,ricas a cual@uier tipoA las de object& Por
ejemploB el cdigo @ue sigue sera per!ectamente v$lido ya @ue tan slo utili/a miem"ros de objectA
public static bool RepresentacionesEnCadenaIguales<T,U>
(T objeto1, U objeto2)
{
return objeto1.ToString() == objeto2.ToString();
}

O"viamenteB tam"i,n compilar$ un cdigo en el @ue los par$metros gen,ricos con los @ue se realicen
operaciones no comunes a todos los objects se conviertan antes a tipos concretos @ue s las admitanB
aun@ue entonces si se le pasasen argumentos de tipos no v$lidos para esa conversin saltara una
InvalidCastE)ce"tion en tiempo de ejecucin& Por ejemploB el siguiente m,todo compilar$ pero la
ejecucin !allar$ en tiempo de ejecucin cuando se le pasen par$metros no converti"les a int&
public static int Suma<T,U>(T valor1, U valor2)
{
return ((int) (object) valor1) + ((int) (object) valor2);
}
8tese @ue por seguridad ni si@uiera se permite la conversin directa de un par$metro tipo a
cual@uier otro tipo @ue no sea object y (a sido necesario (acerla indirectamente&
#gicamenteB C# o!rece mecanismos con los @ue crear cdigos gen,ricos @ue a la ve/ sean seguros y
!le*i"les para reali/ar otras operaciones aparte de las @ue v$lidas para cual@uier object& %stos
mecanismos consisten en de!inir restricciones en el a"anico de argumentos tipo v$lidos para cada
par$metro tipoB de modo @ue as se puedan reali/ar con ,l las operaciones v$lidas para cual@uier o"jeto
de dic(o su"conjunto de tipos&
#as restricciones se especi!ican con cl$usulas %here jpar$metro;en,rico6:jrestricciones6 tras la
lista de par$metros de los m,todos y delegados gen,ricosB o tras el identi!icador de las clasesB
estructuras e inter!aces gen,ricasJ donde jrestricciones6 pueden serA
Cestricciones de clase baseA Indican @ue los tipos asignados al par$metro gen,rico de"en
derivarB ya sea directa o indirectamenteB del indicado en jrestricciones6& -sB en el cdigo
gen,rico se podr$n reali/ar con seguridad todas las operaciones v$lidas para los o"jetos dic(o
tipo padreB incluidas cosas como lan/arlos con sentencias thro% o capturarlos en "lo@ues catch
si ese padre deriva de E)ce"tion& Por ejemploA
using System;
class A
{
public int Valor;
}
class B:A
{
public static int IncrementarValor<T>(T objeto) where T:A
{
return ++objeto.Valor;
}
static void Main()
{
Console.WriteLine(B.IncrementarValor(new B())); // Imprime 1
Console.WriteLine(B.IncrementarValor(new A())); // Imprime 1
// Console.WriteLine(B.IncrementarValor(new C())); // Error
}
}
class C {}
%sta restriccin adem$s "ermite asegurar Sue el argumento ti"o siem"re ser$ un ti"o referenciaB
por lo @ue con podr$ utili/ar en los conte*tos en @ue slo sean v$lidos tipos re!erenciaB como por
ejemplo con el operador as& -s mismoB tam"i,n permite reali/ar conversiones directas del par$metro
tipo a su tipo "ase sin tenerse @ue pasar antes por la conversin a object antes vista&
Cestricciones de interfazA Son similares a las anterioresB slo @ue en este caso lo @ue indican
es @ue los tipos @ue se asignen al par$metro tipo de"en implementar las inter!aces @ueB
separadas mediante comasB se especi!i@uen en jrestricciones6 -s se podr$n usar en todos
a@uellos conte*tos en los @ue se esperen o"jetos @ue las implementenB como por ejemplo en
sentencias using si implementan IEis"osable.
Cestricciones de constructorA Indican @ue los tipos por los @ue se sustituya el par$metro
gen,rico de"er$n disponer de un constructor pC"lico sin par$metros& Se declaran especi!icando
ne%;< en jrestricciones6B y sin ellas no se permite instanciar o"jetos del par$metro tipo dentro
de la de!inicin gen,rico& %s decirA
// Correcto, pues se indica que el tipo por el que se concretice T
// deber de tener un constructor sin parmetros
class A<T> where T:new()
{
public T CrearObjeto()
{
return new T();
}
}
/* Incorrecto, ya que ante el new T() no se sabe si el tipo por el
que se concretice T tendr un constructor sin parmetros
class B<T>
{
public T CrearObjeto()
{
return new T();
}
}
*/
Cada gen,rico puede tener slo una cl$usula %here por par$metro gen,ricoB aun@ue en ella se pueden
me/clar restricciones de los tres tipos separadas por comas& Si se (aceB ,stas (an de aparecer en el
orden en @ue se (an citadoA la de clase "ase primero y la de constructor la Cltima& Por ejemploB el tipo
por el @ue se sustituya el par$metro gen,rico del siguiente m,todo de"er$ derivar de la clase -B
implementar las inter!aces IF e I9 y tener constructor pC"lico sin par$metrosA
void MiMtodo<T> (T objeto) where T: A, ',, '*, new()
{...}
:as restricciones no se heredanB por lo @ue si de una clase gen,rica con restricciones se deriva otra
clase gen,rica cuyos par$metros tipo se usen como par$metros de la clase padreB tam"i,n (a"r$n de
incluirse en ella dic(as restricciones para asegurase de @ue cual@uier argumento tipo @ue se le pase sea
v$lido& IgualmenteB en las rede!iniciones (a"r$ @ue mantener las restricciones espec!icas de cada
m,todo& O seaA
class A {}
class B<T> where T:A
{}
/* No vlido, T debe ser de tipo A para poder ser pasado como argumento
tipo de B, y dicha restriccin no la hereda automticamente el T de C.

class C<T>:B<T>
{}
*/
class C<T>:B<T> where T:A // Vlido
{}
8tese @ue todas estas restricciones se "asan en asegurar @ue los argumentos tipo tengan
determinadas caractersticas =un constructor sin par$metros o ciertos miem"ros (eredados o
implementados?B pero no en las propias caractersticas de esos tipos& Por lo tantoB a travKs de
"ar$metros ti"o no "odr$ llamarse a miembros est$ticos ya @ue no (ay !orma de restringir los
miem"ros est$ticos @ue podr$n tener los argumentos tipo&
inalmenteB ca"e se7alar @ue en realidad tam"i,n e*iste una cuarta forma de restringir el a"anico de
argumentos tipos de un tipo gen,ricoB @ue adem$s es muc(o m$s !le*i"le @ue las anteriores y permite
aplicar cual@uier lgica para la compro"acin de los tipos& Consiste en incluir en el constructor
est$tico del tipo gen,rico cdigo @ue lance alguna e*cepcin cuando los argumentos tipo especi!icados
no sean v$lidosB a"ort$ndose as la e*pansin& Por ejemploB un tipo gen,rico Cj.6 @ue slo admita
como argumentos tipos o"jetos de las clases - o 0 podra crearse como sigueA
class C<T>
{
static C()
{
if ( !(typeof(T) == typeof(A)) && !(typeof(T) == typeof(B)))
throw new ArgumentException("El argumento tipo para T debe ser A o B");
}
}
O si se @uisiese @ue tam"i,n los admitiese de cual@uier clase derivada de ,stasB podra aprovec(arse
como sigue el m,todo bool IsFssignableDorm;T("e ti"o< de los o"jetos T("eB @ue indica si el o"jeto
al @ue se aplica representa a un tipo al @ue se le pueden asignar o"jetos del tipo cuyo o"jeto
S(stem.T("e se le indica como par$metroA
class C<T>
{
static C()
{
if ( !(typeof(B).IsAssignableFrom(typeof(T))) &&
!(typeof(A).IsAssignableFrom(typeof(T))))
throw new ArgumentException("El argumento tipo para T debe ser A o B");
}
}

%l Cnico pro"lema de esta !orma de restringir el a"anico de tipos es @ue desde el cdigo del tipo
gen,rico no se podr$ acceder directamente a los miem"ros espec!icos del tipo argumentoB sino @ue
antes (a"r$ @ue convertirlos e*plcitamente a su tipo& Por ejemploA
using System;
public class A
{
public void Mtodo()
{
Console.WriteLine("Ejecutado Mtodo() de objeto A");
}
}
public class B
{
public void Mtodo()
{
Console.WriteLine("Ejecutado Mtodo() de objeto B");
}
}
class C<T>
{
static C()
{
if ( !(typeof(T) == typeof(A)) && !(typeof(T) == typeof(B)))
throw new ArgumentException("El argumento tipo para T debe
ser A o B");
}
public void LlamarAMtodo(T objeto)
{
if (objeto is A)
(objeto as A).Mtodo(); // Hay que hacer conversin explcita
else
(objeto as B).Mtodo(); // Hay que hacer conversin explcita
}
}
class Principal
{
static void Main()
{
C<A> objetoCA = new C<A>();
objetoCA.LlamarAMtodo(new A());
C<B> objetoCB = new C<B>();
objetoCB.LlamarAMtodo(new B());
}
}

Valores por de"ecto
Cuando se tra"aja con tipos gen,ricos puede interesar asignarles el valor por de!ecto de su tipoB
peros kcu$l ser$ ,ste> %s decirB si el par$metro gen,rico se sustituye por un tipo re!erenciaB el valor
por de!ecto de sus o"jetos sera null y valdran cdigos comoA
void F<T>()
{
T objeto = null ;
}
Sin em"argoB si se sustituyese por un tipo valor no sera v$lidoB por lo @ue este tipo de asignaciones
nunca se admitir$n salvo @ue (aya esta"lecido una restriccin de clase "ase @ue asegure @ue el
argumento tipo sea siempre un tipo re!erencia&
8o o"stanteB C# 9&: permite representar el valor por de!ecto de cual@uier par$metro tipo con la
sinta*is default;jpar$metro.ipo6<B lo @ue dejara al ejemplo anterior como sigueA
void F<T>()
{
T objeto = default(T);
}
%n cada e*pansinB el C#+ sustituir$ la e*presin de!ault=.? por el valor por de!ecto del tipo @ue se
concrete para . =`B nullB falseB&&&?B dando lugar a m,todos comoA
%*pansin para int %*pansin para string %*pansin para "ool
void F<int>()
{
int objeto =0;
}
void F<string>()
{
int objeto = null;
}
void F<bool>()
{
int objeto = false;
}
8tese pues @ue para compro"ar si un cierto argumento tipo es un tipo valor o un tipo re!erencia
"astar$ con compro"ar si su default devuelve null& -s por ejemploB para crear un tipo gen,rico @ue
slo admita tipos re!erencia se podra (acerA
class GenricoSloReferencias<T>
{
static GenricoSloReferencias()
{
if (default(T)!=null)
throw new ArgumentException("T debe ser un tipo referencia");
}
}
Por su parteB y a di!erencia de lo @ue ocurre con el operador de asignacinB el operador de igualdad
=&&? s @ue puede aplicarse entre instancias de par$metros tipo y nullB aCn cuando estos almacenen
tipos valor y dic(a comparacin no sea v$lida& %n dic(os casos la comparacin simplemente retornara
false& IgualmenteB tam"i,n se les podr$ aplicar el operador de desigualdad =,&?B @ue siempre devolver$
true para los tipo valor&
Ambi$8edades
%l @ue los delimitadores de los argumentos tipo sean los mismos @ue los operadores de comparacin
gmayor @ueg y gmenor @ueg y utilicen como el mismo car$cter separador @ue se usa para separar los
argumentos de las llamadas a m,todos =la coma U? puede dar lugar a am"ig<edades& Por ejemploB una
llamada como la siguienteA
F(G<A,B>(7));
Podra interpretarse de dos !ormasA Como una llamada a un m,todo =? con el resultado de evaluar
;j- como primer argumento y el resultado de 06=Y? como segundoB o como una llamada a =? con el
resultado de una llamada ;j-B06=Y? a un m,todo gen,rico ;=?
#o @ue (ace el compilador es interpretar como llamadas a m,todos gen,ricos cual@uier aparicin del
car$cter I donde a este le sigan alguno de estos caracteresA ;B <B .B IB TB :B BRB . U& %n el resto de casos
ser$n tratados como operadores de comparacin& Por tantoB en el ejemplo anterior la e*presin ser$
interpretada como una llamada a un m,todo gen,ricoB y para @ue se interpretase de la otra !orma (a"ra
rescri"irse como =;j-B06Y?J
(ipos parciales
C# 9&: da la posi"ilidad de distri"uir las de!iniciones de los tipos en mCltiples !ic(eros tales @ue si al
compilar se pasan todos juntos al compiladorB ,ste autom$ticamente los !usionar$ en memoria y
generar$ el MSI# correspondiente a su unin& - estos tipos se les conoce como ti"os "arciales y
pueden ser de!iniciones tanto de clases como de estructuras e interfacesB pero no de enumeraciones o
delegados ya @ue estas suelen ser de!iniciones tan sencillas @ue dividirlas resultara muy poco o nada
Ctil&
#os tipos parciales !acilitan separar los cdigos o"tenidos autom$ticamente mediante generadores
de c!digo =como VS&8%. 9::V? de las modi!icaciones se les realicen a mano tras su generacinB pues
permiten regenerarlos en cual@uier momento sin @ue con ello se pierdan dic(os cam"ios& -dem$sB
tam"i,n son Ctiles para agilizar el desarrollo ( mantenimiento de las tipos de datosB pues permiten
@ue varias personas puedan estar tra"ajando simult$neamente en di!erentes secciones de un mismo tipo
de dato&
Para de!inir un tipo parcial simplemente con "asta declararlo varias veces en el mismo o en
di!erentes !ic(erosB a7adi,ndoles un nuevo modi!icador "artial y manteniendo siempre el mismo
nom"re completoB par$metros tipoB modi!icadores de visi"ilidad y clase "ase& #as restricciones de los
par$metros tipos no tienen por@u, aparecer en todas las partesB pero si lo (ace de"en ser siempre las
mismas& Por ejemploB en un !ic(ero clientes&cs se podra tenerA
interface I1
{
void F();
}
[Mi.tributo,] [Mi.tributo*("Test1")]
public partial class Clientes
{
public int X;
}
W en otro !ic(ero llamado clientes5ampliacin&csA
public partial class Clientes: I1
{}
interface I2
{
void G();
}
[Mi.tributo*("Test2")]
public partial class Clientes: I2
{
void I1.F()
{}
public void G()
{}
}
Si al compilar se especi!ican am"as am"os !ic(eros simult$neamenteB como enA
csc ItAli"rary clientes&cs clientes5ampliacin&cs
%l compilador considerar$ @ue la de!inicin de la clase Clientes es la siguienteA
[Mi.tributo,, Mi.tributo*("Test1"), Mi.tributo*("Test2")]
public class Clientes: I1, I2
{
public int X;
void I1.F()
{}
public void G()
{}
}
8tese @ue en una parte de una de!inicin parcial se podr$n re!erenciar identi!icadores =miem"rosB
inter!aces implementadas e*plcitamenteB etc&? no declarados en ella sino en otras partes de la
de!inicinB puesto @ue mientras al compilar se le pasen al compilador las partes donde est$n de!inidosB
la !usin producir$ una clase v$lida& 8o o"stanteB (ay @ue se7alar @ue esto tiene pe@ue7as algunas
limitaciones y no es aplica"le aA
Modificador unsafeA Por seguridadB aplicarlo a la de!inicin de una parte de un tipo no
implicar$ @ue se considere aplicado al resto y puedan utili/arse en ellas punterosB sino @ue
de"er$ de aplicarse por separado a cada parte en la @ue se vaya a (acer uso de caractersticas
inseguras&
Eirectiva usingA %n cada parte de una de!inicin parcial se puede utili/ar di!erentes directivas
using @ue importen di!erentes espacios de nom"res y de!inan di!erentes alias& -l anali/ar cada
parteB el compilador tan slo interpretar$ las directivas using especi!icadas en ellaB
admiti,ndose incluso @ue en varias partes se de!inan alias con el mismo nom"re para clases o
espacios de nom"res di!erentes&
%l uso de tipos parciales no o"stante introduce el pro"lema de @ue el mantenimiento de cdigo
particionados puede ser m$s complicado al estar distri"uida su implementacin a lo largo de mCltiples
!ic(eros& Sin em"argoB (erramientas como la /ista de Clases de VS&8%. 9::V solucionan esto
proporcionando una vista uni!icada de la estructura de estos tipos con el resultado de la !usin de todas
sus partes&
Iteradores
-provec(ando las ventajas proporcionadas por los gen,ricosB en la 0C# del &8%. 9&: se (a
optimi/ado la implementacin de las colecciones introduciendo en un nuevo espacio de nom"res
S(stem.Collections.#eneric dos nuevas inter!aces llamadas IEnumerableHTI e IEnumeratorHTI
@ue las colecciones podr$n implementar para conseguir @ue el acceso a las colecciones sea muc(o m$s
eficiente @ue con las viejas IEnumerable e IEnumerator al evitarse el "o*ingIun"o*ing o
do'ncastingIupcasting @ue el tipo de retorno object de la propiedad Current de IEnumerator
implica"a& -dem$sB en ellas se (a optimi/ado el dise7o eliminando el tan poco utili/ado m,todo
Ceset;< y (aci,ndoles implementar en su lugar la estandari/ada inter!a/ IEis"osable& %n resumenB
est$n de!inidas como sigueA
public interface IEnumerable<T>
{
IEnumerator<T> GetEnumerator();
}

public interface IEnumerator<T>: '2isposable
{
T Current { get; }
bool MoveNext();
}

8tese @ue en realidad C# F&: ya proporciona"a a trav,s del "atr!n de colecci!n un mecanismo
con @ue implementar colecciones !uertemente tipadas& Sin em"argoB era algo espec!ico de este
lenguajeB oculto y desconocido para muc(os programadores y no completamente soportado por otros
lenguajes &8%. =por ejemploB Visual 0asic&8%. y su sentencia Dor Each? Por el contrarioB estas
nuevas inter!aces gen,ricas proporcionan una soluci!n m$s com"atible ( mejor formulada&
C# 9&: proporciona adem$s un nuevo mecanismo con el @ue es resultar$ muc(o sencillo crear
colecciones @ue implementando directamente estas inter!acesA los iteradores& Son m,todos @ue para
generar o"jetos @ue implementen todas estas inter!aces se apoyan en una nueva sentencia (ield& Han de
tener como tipo de retorno IEnumerableB IEnumeratorB IEnumerableHTI e IEnumeratorHTIB y su
cuerpo indicar$n los valores a recorrer con sentencias (ield return jvalor6T en las @ue si se el tipo de
retorno del iterador es gen,ricoB jvalor6 de"er$ ser de tipo .& -simismoB tam"i,n se marcar el !in de la
enumeracin y !or/ar a @ue MoveNe)t;< siempre devuelva false mediante sentencias (ield brea'T&
- partir de la de!inicin de un iteradorB el compilador anidar$ dentro de la clase en @ue ,ste se
de!ini una clase privada @ue implementar$ la inter!a/ de su tipo de retorno& %l cdigo del iterador no
se ejecutar$ al llamarleB sino en cada llamada reali/ada al m,todo MoveNe)t;< del o"jeto @ue
devuelveB y slo (asta llegarse a algCn (ield return& #uego la ejecucin se suspender$ (asta la
siguiente llamada a MoveNe)t;<B @ue la reanudar$ por donde se @ued& Por tantoB sucesivas llamadas a
MoveNe)t;< ir$n devolviendo los valores indicados por los (ield return en el mismo orden en @ue se
,stos se ejecuten& -sB enA
using System;
using System.Collections;

class PruebaIteradores
{
public IEnumerator GetEnumerator()
{
yield return 1;
yield return "Hola";
}

public IEnumerable AlRevs
{
get
{
yield return "Hola";
yield return 1;
}
}

static void Main()
{
PruebaIteradores objeto = new PruebaIteradores();
foreach(object valor in objeto)
Console.WriteLine(valor);

foreach(object x in objeto.AlRevs)
Console.WriteLine(x);
}
}
#a clase Prue"aIteradores tendr$n un m,todo ;et%numerator=? @ue devolver$ un o"jeto
IEnumerator generado en "ase a las instrucciones (ield @ue retornar$ como primer elemento un F y
como segundo la cadena gHolagB por lo @ue podr$ ser recorrida a trav,s de la instruccin foreach& )el
mismo modoB su propiedad FlCevKs devolver$ un o"jeto @ue tam"i,n dispone de dic(o m,todo y por
tanto tam"i,n podr$ recorrese a trav,s de dic(a sentenciaB aun@ue en este caso (ace el recorrido al
rev,s& Por tantoB su salida ser$A
F
Hola
Hola
F
8tese @ue aun@ue los iteradores se puedan usar para de!inir m,todos @ue devuelvan tanto o"jetos
IEnumerable como IEnumeratorB ello no signi!ica @ue dic(os tipos sean intercam"ia"les& %s decirB si
en el ejemplo anterior (u"i,semos de!inido la propiedad -l+ev,s como de tipo IEnumeratorB el
cdigo no compilara en tanto @ue lo @ue foreach espera es un o"jeto @ue implemente IEnumerableB y
no un IEnumerator&
%n realidadB si el tipo de retorno del iterador es IEnumerator o IEnumeratorHTIB la clase interna
@ue se generar$ implementar$ tanto la versin gen,rica de esta inter!a/ como la @ue no lo es& #o mismo
ocurre para el caso de IEnumerable e IEnumerableHTIB en el @ue adem$sB el compilador
opcionalmente =el de C# de Microso!t s lo (ace? tam"i,n podr$ implementar las inter!aces
IEnumerator e IEnumeratorHTI& Sin em"argoB implementar las inter!aces IEnumerator no implica
@ue se implementen las IEnumerableB y de a( el pro"lema descrito en el p$rra!o anterior&
Por otro ladoB (ay @ue se7alar @ue en el cdigo @ue se puede incluir dentro de los iteradores e*isten
algunas limitaciones destinadas a evitar rupturas descontroladas de la iteracinA no se permiten
sentencias returnB ni c!digo inseguro ni "ar$metros "or referenciaB y las sentencias (ield no se
puede usar dentro de "lo@ues tr(B catch o finall(&
InternamenteB a partir de la de!inicin del iterador el compilador generar$ una clase interna @ue
implementar$ la inter!a/ del tipo de retorno de ,ste y sustituir$ el cdigo del miem"ro de la coleccin
donde se de!ine el iterador por una instanciacin de dic(a clase a la @ue le pasar$ como par$metro el
propio o"jeto coleccin a recorrer =this? %n ellaB el cdigo del iterador se trans!ormar$ en una
implementacin del MoveNe)t;< de IEnumerator "asada en un algoritmo de m$@uina de estadoB y la
posi"le limpie/a de los recursos consumido por la misma se (ar$ en el Eis"ose;< O seaB se generar$
algo comoA
public class <coleccin>:<interfaz>
{
public virtual <interfaz> GetEnumerator()
{
return GetEnumerator$<nmeroAleatorionico>__IEnumeratorImpl impl =
new GetEnumerator$<nmeroAleatorionico>__IEnumeratorImpl(this);
}

class GetEnumerator$<nmeroAleatorionico>__IEnumeratorImpl:<interfaz>
{
public <coleccin> @this;
<tipoElementosColeccin> $_current;
string <interfaz>.Current { get { return $_current; } }

bool <interfaz>.MoveNext()
{
// Implementacin de la mquina de estados
}

void IDisposable.Dispose()
{
// Posible limpieza de la mquina de estados
}
}
}
8tese @ue para cada foreach se generar$ un nuevo o"jeto de la clase internaB por lo @ue el estado de
estos iteradores autom$ticamente generados no se comparte entre foreachs y por tanto el antiguo
m,todo Ceset;< de IEnumerator se vuelve innecesario& %s m$sB si la inter!a/ de retorno del iterador
!uese IEnumeratorB la implementacin reali/ada por el compilador en la clase interna para el o"soleto
m,todo de la misma Ceset;< lan/ar$ una NotSu""ortedE)ce"tion ante cual@uier llamada @ue
e*plcitamente se le realice& 8o o"stanteB (ay @ue tener cuidado con esto pues puede implicar la
creacin de numerosos o"jetos en implementaciones recursivas como la siguienteB en la @ue se
aprovec(an los iteradores para simpli!icar la implementacin de los recorridos so"re un $r"ol "inarioA
using System.Collections.Generic;

public class Nodo<T>
{
public Nodo<T> Izquierdo, Derecho;
public T Valor;
}

public class rbolBinario<T>
{
Nodo<T> raz;
public IEnumerable<T> Inorden{get{return
recorrerEnInorden(this.raz); } }
IEnumerable<T> recorrerEnInorden(Nodo<T> nodo)
{
Nodo<T> nodoIzquierdo = nodo.Izquierdo;
if (nodoIzquierdo!=null)
foreach(T valor in recorrerEnInorden(nodoIzquierdo))
yield return valor;

yield return raz.Valor;
Nodo<T> nodoDerecho= nodo.Derecho;
if (nodoDerecho!=null)
foreach(T valor in recorrerEnInorden(nodoDerecho))
yield return valor;
}

// Implementacin de recorridos en Preorden y PostOrden y dems miembros
}
&ejoras en la manipulaci%n de dele!ados
'n"erencia de dele$ados
Mientras @ue en C# F&P siempre era necesario indicar e*plcitamente el delegado del o"jeto o evento al
@ue a7adir cada m,todo utili/ando el operador ne%B como enA

miObjeto.miEvento += new MiDelegado(miCdigoRespuesta);
%n C# 9&: el compilador es capa/ de in!erirlo autom$ticamente de la de!inicin del delegado en @ue
se desea almacenar& -sB para el ejemplo anterior "astara con escri"irA
miObjeto.miEvento += miCdigoRespuesta;
Sin em"argoB asignaciones como la siguiente en la @ue el m,todo no es asociado a un delegado no
permiten la deduccin autom$tica del mismo y !allar$n al compilarA
object o = miCdigoRespuesta;
-un@ue e*plicitando la conversin a reali/ar tal y como sigue s @ue compilar$A
object o = (MiDelegado) miCdigoRespuesta;
%n generalB la in!erencia de delegados !unciona en cual@uier conte*to en @ue se espere un o"jeto
delegado& %sto puede o"servarse en el siguiente ejemploA
using System;
class A
{
delegate void MiDelegado(string cadena);

public static void Main()
{
// En C# 1.X: MiDelegado delegado = new MiDelegado(miMtodo);
MiDelegado delegado = miMtodo;
// En C# 1.X: delegado.EndInvoke(delegado.BeginInvoke("Hola",
// new AsyncCallback(mtodoFin), null));
delegado.EndInvoke(delegado.BeginInvoke("Hola", mtodoFin, null));
}

static void miMtodo(string cadena)
{
Console.WriteLine("MiMtodo(string {0})", cadena);
}
static void mtodoFin('.sync4esult datos)
{
//.
}
}
M&todos annimos
C# 9&: permite asociar cdigo a los o"jetos delegados directamenteB sin @ue para ello el programador
tenga @ue crear m,todos Cnicamente destinados a acoger su cuerpo y no aB como sera lo apropiadoB
reutili/ar o clari!icar !uncionalidades& Se les llama mKtodos an!nimosB pues al especi!icarlos no se les
da un nom"re sino @ue se sigue la sinta*isA
delegate(<parmetros>) 0<instrucciones>1$
W ser$ el compilador @uien internamente se encargue de declarar m,todos con dic(os jpar$metros6
e jinstrucciones6 y crear un o"jeto delgado @ue los re!erencie& %stas jinstrucciones6 podr$n ser
cuales@uiera e*cepto (ieldB y para evitar colisiones con los nom"res de m,todos creados por el
programador el compilador dar$ a los m,todos en @ue internamente las encapsular$ nom"res @ue
contendr$n la su"cadena reservada XX& 8tese @ue con esta sinta*is no se "ueden aVadir atributos a
los mKtodos an!nimos&
Con m,todos annimosB las asignaciones de m,todos a delegados podra compactarse aCn m$s
elimin$ndoles la declaracin e*plcita del m,todo de respuesta& Por ejemploA
miObjeto.miEvento += delegate(object parmetro1, int parmetro2)
{ Console.WriteLine ("Evento producido en miObjeto"); };
Incluso siB como es el casoB en el cdigo de un m,todo annimo no se van a utili/ar los par$metros
del delegado al @ue se asignaB puede omitirse especi!icarlos =al llamar a los m,todos @ue almacena a
trav,s suya (a"r$ @ue pasarles valores cuales@uiera? -sB la asignacin del ejemplo anterior podra
compactarse aCn m$s y dejarla enA
miObjeto.miEvento += delegate {
Console.WriteLine ("Evento producido en miObjeto"); };
%n am"os casosB a partir de estas instrucciones el compilador de!inir$ dentro de la clase en @ue (ayan
sido incluidas un m,todo privado similar al siguienteA
public void __AnonymousMethod$00000000(object parmetro1, int parmetro2)
{
Console.WriteLine ("Evento producido en miObjeto");
}
W tratar$ la asignacin del m,todo annimo al evento como si !ueseA
miObjeto.miEvento += new MiDelegado(this,__AnonymousMethod$00000000);
8o o"stanteB la sinta*is a"reviada no se puede usar con delegados con par$metros outB puesto @ue al
no poderlos re!erenciar dentro de su cuerpo ser$ imposi"le asignarles en el mismo un valor tal y como
la sem$ntica de dic(o modi!icador re@uiere&
jese @ue aun@ue a trav,s de *& es posi"le almacenar m,todos annimos en un o"jeto delegadoB al
no tener nom"re no ser$ posi"le @uit$rselos con +& a no ser @ue antes se (ayan almacenado en otro
o"jeto delegadoB como en por ejemploA
MiDelegado delegado = delegate(object prametro1, int parmetro2)
{ Console.WriteLine ("Evento producido en miObjeto"); };
miObjeto.miEvento += delegado;
miObjeto.miEvento -= delegado;
#os m,todos annimos (an de de!inirse en asignaciones a o"jetos delegados o eventos para @ue el
compilador pueda determinar el delegado donde encapsularlo& Por tantoB no ser$ v$lido almacenarlos
en objects mediante instrucciones del tipoA
object annimo = delegate(object prametro1, int parmetro2)
{ Console.WriteLine ("Evento producido en miObjeto"); }; // Error
-un@ue s si se especi!icarse el delegado mediante conversiones e*plcitasB como enA
object annimo = (MiDelegado) delegate(object parametro1, int parmetro2)
{ Console.WriteLine ("Evento producido en miObjeto"); };
#os m,todos annimos tam"i,n pueden ser pasados como par$metros de los m,todos @ue esperen
delegadosB como en por ejemploA
class A
{
delegate void MiDelegado();
public void MiMtodo()
{
LlamarADelegado(delegate() { Console.Write("Hola"); });
}
void LlamarADelegado(MiDelegado delegado)
{
delegado();
}
}
8tese @ue si el m,todo aceptase como par$metros o"jetos del tipo gen,rico EelegateB antes de
pasarle el m,todo annimo (a"ra @ue convertirlo a algCn tipo concreto para @ue el compilador pudiese
deducir la signatura del m,todo a generarB y el delegado no podra tomar ningCn par$metro ni tener
valor de retorno& %s decirA
class A
{
public void MiMtodo()
{
LlamarADelegado((MiDelegado) delegate { Console.Write("Hola"); });
}
void LlamarADelegado(delegate delegado)
{
MiDelegado objeto = (MiDelegado) delegado;
objeto("LlamarADelegado");
}
}

Ca"tura de variables e)ternas
%n los m,todos annimos puede accederse a cual@uier elemento visi"le desde el punto de su
declaracinB tanto a las varia"les locales de los m,todos donde se declaren como a los miem"ros de sus
clases& - dic(as varia"les se les denomina variables e)ternasB y se dice @ue los m,todos annimos las
ca"turan ya @ue almacenar$n una re!erencia a su valor @ue mantendr$n entre llamadas& %sto puede
o"servarse en el siguiente ejemploA
using System;
delegate int D(ref VariablesExternas parmetro);
class VariablesExternas
{
public int Valor = 100;
static D F()
{
VariablesExternas o = new VariablesExternas();
int x = 0;
D delegado = delegate(ref VariablesExternas parmetro)
{
if (parmetro==null)
parmetro = o;
else
parmetro.Valor++;
return ++x;
};
x += 2;
o.Valor+=2;
return delegado;
}
static void Main()
{
D d = F();
VariablesExternas objeto = null;
int valor = d(ref objeto);
Console.WriteLine("valor={0}, objeto.Valor={1}", valor, objeto.Valor);
valor = d(ref objeto);
Console.WriteLine("valor={0}, objeto.Valor={1}", valor, objeto.Valor);
}
}
Cuya salida esA
valor=3, objeto.Valor=102
valor=4, objeto.Valor=103
jese @ue aun@ue las varia"les * y o son locales al m,todo =?B se mantienen entra las llamadas @ue
se le reali/an a trav,s del o"jeto delegado d ya @ue (an sido capturadas por el m,todo annimo @ue ,ste
almacena&
- las varia"les capturadas no se les considera !ijas en memoriaB por lo @ue para poderlas manipular
con seguridad en cdigo inseguro (a"r$ @ue encerrarlas en la sentencia fi)ed&
)e"e se7alarse @ue la captura de varia"les e*ternas no !unciona con los cam"os de las estructurasB
ya @ue dentro de un m,todo annimo no se puede re!erenciar al this de las mismas& Sin em"argoB la
estructura siempre puede copiarse desde !uera del m,todo annimo en una varia"le local para luego
re!erenciarla en el mismo a trav,s de dic(a copia& %so sB de"e se7alarse @ue en un campo de la
estructura no se podr$ reali/ar esta copiar ya @ue ello causara ciclos en la de!inicin de ,sta&
Co#arian0a . contra#arian0a de dele$ados
#os delegados tam"i,n son m$s !le*i"les en C# 9&: por@ue sus o"jetos admiten tanto m,todos @ue
cumplan e*actamente con sus de!inicionesB con valores de retorno y par$metros de e*actamente los
mismos tipos indicados en ,stasB como m,todos @ue los tomen de tipos padres de ,stos& - esto se le
conoce como covarianza para el caso de los valores de retorno y contravarianza para el de los
par$metros& Por ejemploA
using System;
public delegate Persona DelegadoCumpleaos(Persona persona, int
nuevaEdad);
public class Persona
{
public string Nombre;
private int edad;

public int Edad
{
get { return this.edad; }
}
public event DelegadoCumpleaos Cumpleaos;
public )ersona(&tring nombre, int edad)
{
this.Nombre = nombre;
this.edad = edad;
}
public void CumplirAos()
{
Cumpleaos(this, this.edad+1);
this.edad++;
}
}
public class Empleado:Persona
{
public uint Sueldo;

public (mpleado(string nombre, int edad, uint sueldo):base(nombre, edad)
{
this.Sueldo = sueldo;
}
}
public class Covarianza
{
static void Main()
{
Empleado josan = new Empleado("Josan", 25, 500000);
josan.Cumpleaos += mostrarAos;
josan.CumplirAos();
}
static Persona mostrarAos(Persona josan, int nuevaEdad)
{
Console.WriteLine("{0} cumpli {1} aos", josan.Nombre, nuevaEdad);
return josan;
}
}
8tese @ue aun@ue en el ejemplo el delegado se (a de!inido para operar con o"jetos del tipo PersonaB
se le (an pasado o"jetos de su su"tipo %mpleado y devuelve un o"jeto tam"i,n de dic(o tipo derivado&
%sto es per!ectamente seguro ya @ue en realidad los o"jetos del tipo %mpleado siempre tendr$n los
miem"ros @ue los o"jetos del Persona y por lo tanto cual@uier manipulacin @ue se (aga de los mismos
en el cdigo ser$ sint$cticamente v$lida& Si lo ejecutamosB la salida @ue mostrar$ el cdigo es la
siguienteA
Josan cumpli 26 aos

(ipos anulables
Concepto
%n C# 9&: las varia"les de tipos valor tam"i,n pueden almacenar el valor especial nullB como
las de tipos re!erencia& Por elloB a estas varia"les se les denomina ti"os anulables&
%sto les permite se7alar cuando almacenan un valor desconocido o inaplica"leB lo @ue puede
resultar muy Ctil a la (ora de tra"ajar con "ases de datos ya @ue en ,stas los campos de tipo enteroB
"ooleanosB etc& suelen permitir almacenar valores nulos& -s mismoB tam"i,n evita tener @ue
de!inir ciertos valores especiales para los par$metros o el valor de retorno de los m,todos con los
@ue e*presar dic(a sem$ntica =peB devolver 5F en un m,todo @ue devuelva la posicin donde se
(aya un cierto elemento en una ta"la para indicar @ue no se (a encontrado en la misma?B cosa @ue
adem$s puede implicar desaprovec(ar parte del rango de representacin del tipo valor o incluso no
ser posi"le de aplicar si todos los valores del par$metro o valor de retorno son signi!icativos&
Sinta*is
#a versin anula"le de un tipo valor se representa igual @ue la normal pero con el su!ijo RB y se
le podr$n asignar tanto valores de su ti"o sub(acente =el tipo normalB sin el R? como null& )e
(ec(oB su valor "or defecto ser$ null& Por ejemploA
int? x = 1;
x = null;
%n realidad el uso de R no es m$s @ue una sinta*is a"reviada con la @ue instanciar un o"jeto del
nuevo tipo gen,rico NullableHTI incluido en el espacio de nom"res S(stem de la 0C# con su
par$metro gen,rico concreti/ado al tipo su"yacente& %ste tipo tiene un constructor @ue admite un
par$metro del tipo gen,rico TB por lo @ue en realidad el cdigo del ejemplo anterior es e@uivalente
aA
+ullable<int> x = new +ullable<int>(1);// Tambin valdra
// Nullable<int>x = new int?(1);
x = null;
%l tipo Nullable proporciona dos propiedades a todos los tipos anula"lesA bool ?as/alue para
indicar si almacena nullB y T /alueB para o"tener su valor& Si una varia"le anula"le valiese nullB
leer su propiedad /alue (ara saltar una Invalid"erationE)ce"tion& - continuacin se muestra
un ejemplo del uso de las mismasA
using System;
class Anulables
{
static void Main()
{
int? x = null;
int? y = 123;
MostrarSiNulo(x, "x");
&odificadores de visibilidad de blo2ues !et y set
C# 9&: permite de!inir di!erentes modi!icadores de visi"ilidad para los "lo@ues get y set de las
propiedades e indi/adoresB de manera @ue podr$n tener propiedades en las @ue el "lo@ue get sea
pC"lico pero el set protegido& Por ejemploA
class A
{
string miPropiedad;
public string MiPropiedad
{
get { return miPropiedad; }
protected set { miPropiedad = value; }
}
}
#gicamenteB la visi"ilidad de los "lo@ues get y set nunca podr$ ser superior a los de la propia
propiedad o indi/ador al @ue pertene/can& Por ejemploB una propiedad protegida nunca podr$ tener uno
de estos "lo@ues pC"lico&
-dem$sB aun@ue de este modo se puede con!igurar la visi"ilidad del "lo@ue get o del "lo@ue set de
una cierta propiedad o indi/adorB no se puede cam"iar la de am"os& Si interesaseB kpara @u, se dio a la
propiedad o indi/ador ese modi!icador de visi"ilidad>
Clases estticas
Para !acilitar la creacin de clases @ue no est,n destinadas a ser instanciadas o derivadas =abstract
sealed? sino tan slo a proporcionar ciertos m,todos est$ticos =clases f$bricaB utili/adas para crear
ciertos tipos de o"jetosB clases utilidad @ue o!re/can acceso a ciertos servicios de manera cmodaB sin
tener @ue instanciar o"jetosB etc&?B C# 9&: permite con!igurar dic(a sem$ntica en la propia declaracin
de las mismas incluyendo en ellas el modi!icador static& -s se !or/ar$ a @ue el compilador asegure el
seguimiento de dic(a sem$ntica& Por ejemploB el cdigo @ue a continuacin se muestra ser$ v$lidoA
static public class ClaseEsttica
{
static public object CrearObjetoTipoA()
{ . }
static public object CrearObjetoTipoB()
{ . }
}
Por el contrarioB el siguiente cdigo no compilara ya @ue la clase Clase%st$ticaCon%rror se (a
de!inido como est$tica pero tiene un m,todo no est$tico llamado M,todoInstanciaB se la est$ intentando
instanciarB y se est$ intentando derivar de ella una clase HijaA
static public class ClaseEstticaConError
{
static public object CrearObjetoTipoA()
{ . }
static public object CrearObjetoTipoB()
{ . }

public void MtodoInstancia(string texto) // Error: mtodo no esttico.
{
Console.WriteLine("MtodoInstancia({0})", texto);
}
static void Main()
{
// Error: Se est instanciado la clase esttica
ClaseEstticaConError objeto = new ClaseEstticaConError();
objeto.MtodoInstancia("Test");
}
}
class Hija: ClaseEstticaConError {}
// Error: Se est derivando de clase esttica

-eferencias a espacios de nombres
Alias $lobal . cali"icador 99
%n C# F&F puede producirse con!lictos a la (ora de resolver las re!erencias a ciertas clases cuando en
anidaciones de espacios de nom"res e*istan varias clases yIo espacios de nom"res (omnimos& Por
ejemploB en el siguiente cdigoA
using System;
namespace Josan
{
class A
{
static void Main(string[] args)
{
Mtodo();
}
static void Mtodo()
{
Console.WriteLine("Josan.System.A.Mtodo()");
A.Mtodo();
}
}
}
class A
{
static void Mtodo()
{
Console.WriteLine("A.Mtodo()");
}
}
+esulta imposi"le llamar desde el m,todo M,todo=? de la clase Eosan&- a su (omnimo en la clase
- del espacio de nom"res glo"alB por lo @ue la llamada -&M,todo=? producir$ un "ucle recursivo
in!inito y la salida del programa ser$ del tipoA
Eosan&System&-&M,todo=?
Eosan&System&-&M,todo=?
Eosan&System&-&M,todo=?
Para solucionar estoB C# 9&: introduce la posi"ilidad de (acer re!erencia al espacio de nom"res
glo"al a trav,s de un alias prede!inido denominado global y un cali!icador :: @ue se usa de la !orma
jinicio6::jre!erencia6 y permite indicar el punto de jinicio6 en la jerar@ua de espacios de nom"res a
partir del @ue se (a de resolver la jre!erencia6 al tipo o espacio de nom"res indicada& %stas re!erencias
se podr$n usar en cual@uier parte en la @ue se espere un nom"re de tipo o espacio de nom"resB tal como
una sentencia usingB la creacin de un o"jeto con ne%B&&& -sB el ejemplo anterior podra resolverse
como sigueA
using System;
namespace Josan
{
class A
{
static void Main(string[] args)
{
Mtodo();
}
static void Mtodo()
{
Console.WriteLine("Josan.System.A.Mtodo()");
global::A.Mtodo();
}
}
}
class A
{
public static void Mtodo()
{
Console.WriteLine("A.Mtodo()");
}
}
W a(ora ya s @ue se o"tendra la salida "uscadaA
Eosan&System&-&M,todo=?
-&M,todo=?
Alias e*ternos
C# 9&: va un paso m$s all$ en lo re!erente a resolver con!lictos de am"ig<edades en los nom"res de
los identi!icadores respecto a C# F&P& -(ora no solo se pueden usar clases con el mismo nom"re
siempre y cuando se (allen en espacios de nom"res di!erentes sino @ue tam"i,n se permite usar clases
con el mismo nom"re y espacio de nom"res @ue se (allen en di!erentes ensam"lados& Para ello se usan
los denominados alias e)ternos&
-ntes de las importaciones de espacios de nom"res =using? se puede incluir lneas con la siguiente
sinta*isA
extern alias <nombreAlias>$

Con esto se estar$ diciendo al compilador @ue durante las compro"aciones de sinta*is admita a la
i/@uierda del cali!icador :: las re!erencias al alias de espacio de nom"res cuyo nom"re se le indica&&
Cada una de estas re!erencias se corresponder$n con uno o varios ensam"lados e*ternos dentro de
cuyos espacios de nom"res se intentar$n resolver la re!erencia indicada a la derec(a del ::& #a
correspondencia entre estos ensam"lados y sus alias se indicar$n al compilador de C# mediante
par$metros @ue se podr$n pasar en la lnea de comandos al (acerles re!erencia mediante la opcin Ar
siguiendo la sinta*is jnom"re-lias6&jruta%nsam"lado6 para los valores de la mismaJ o en el caso de
VS&8%. 9::VB desde la ventana de propiedades de la re!erencia al ensam"lado en la solucin&
Por ejemploB se puede tener un !ic(ero miclaseF&cs con el siguiente contenidoA
using System;
public class MiClase
{
public void F()
{
Console.WriteLine("F() de mi miclase1.cs");
}
}
W otro miclase9&cs con una clase (omnima a MiClaseA
using System;
public class MiClase
{
public void F()
{
Console.WriteLine("F() de mi miclase2.cs");
}
}
Para usar am"as clases a la ve/ en un !ic(ero e*tern&cs "astara escri"irlo como sigueA
extern alias X;
extern alias Y;
class Extern
{
static void Main()
{
X::MiClase objeto = new X::MiClase();
objeto.F();
Y::MiClase objeto2 = new Y::MiClase();
objeto2.F();
}
}
W compilar todo el conjunto conA
csc e*tern&cs IrAPMmiclaseF&dll IrAWMmiclase9&dll
csc e*tern&cs IrAPMmiclaseF&dll IrAWMmiclase9&dll
-l ejecutarlo podr$ compro"arse @ue la salida demuestra @ue cada llamada se (a (ec(o a uno de los
di!erentes tipos MiClaseA
=? de mi miclaseF&cs
=? de mi miclase9&cs
8tese @ue es per!ectamente v$lido asociar un mismo alias a varios ensamblados y varios alias a un
mismo ensamblado& #o @ue no se puede es incluir varias de!iniciones de alias en una misma opcin ArB
sino @ue para ello (a"ra @ue utili/ar opciones Ar di!erentes tal como se (a (ec(o en el ejemplo& %s
decirB la siguiente llamada al compilador no sera correctaA
csc e*tern&cs IrAPMmiclaseF&dllBWMmiclase9&dll

#upresi%n temporal de avisos
-l conjunto de directivas del preprocesador de C# se (a a7adido una nueva en C# 9&: @ue permite
desactivar la emisin de determinados avisos durante la compilacin de determinadas secciones del
cdigo !uente as como volverlo a activar& Su sinta*is esA
@pragma warning <estado> <cdigoAviso>
)onde jcdigo-viso6 es el cdigo del aviso a desactivar o reactivarB y jestado6 valdr$ disable o
restore segCn si lo @ue se desea es desactivarlo o re(a"ilitarlo& Por ejemploB al compilar el siguiente
cdigo el compilador slo in!ormar$ de @ue no se usa la varia"le "B pero no se dir$ nada de la varia"le
de"ido a @ue se le (a suprimido dic(o mensaje de aviso =su cdigo es el ZXd? a trav,s de la directiva
#"ragma %arningA
class ClaseConAvisos
{
@ pragma warning disable 649
public int a;
@ pragma warning restore 649
public int b;
}
%n cual@uier casoB (ay @ue se7alar @ue como normal general no se recomienda hacer uso de esta
directivaB ya @ue el cdigo !inal de"era siempre escri"irse de manera @ue no genere avisos& Sin
em"argoB puede venir "ien durante la depuracin de aplicaciones o la creacin de prototipos o
estructuras iniciales de cdigo para !acilitar el aislamiento de pro"lemas y evitar mensajes de aviso ya
conocidos @ue aparecer$n temporalmente&
,tributos condicionales
%l atri"uto Conditional @ue en C# F&P permita especi!icar si compilar ciertas llamadas a m,todos
en !uncin de valores de constantes de preprocesador (a sido a(ora ampliado para tam"i,n poderse
aplicar a la utili/acin de atri"utos& %n este casoB si la utili/acin del atri"uto para un determinado
!ic(ero no se compila por no estar de!inida la constante de la @ue dependeB ninguna clase del mismo a
la se apli@ue lo almacenar$ entre sus metadatos& -sB si tenemos un !ic(ero test&cs con la siguiente
de!inicin de atri"utoA
using System;

using System.Diagnostics;

[5onditional(32(/9A3)]
public class TestAttribute : Attribute {}
W con ,l compilamos un !ic(ero miclase&cs con el contenidoA
@define DEBUG
[:est]
class MiClase {}
%n el ensam"lado resultante la clase MiClase incluir$ el atri"uto .est entre sus metadatos por estar
de!inida la constante )%01; dentro del !ic(ero en @ue se usa el atri"uto& Pero por el contrarioB si
adem$s compil$semos otro !ic(ero miclase9&cs como el siguienteA
@undef DEBUG
[:est]
class MiClase2 {}
%ntonces la MiClase9 del ensam"lado resultante no almacenara el atri"uto .est entre sus metadatos
por no estar de!inida la constante )%01; en el !ic(ero donde se declar&
Incrustaci%n de tablas en estructuras
-l interoperar con cdigo nativo puede ser necesario pasar a ,ste estructuras de un tama7o !ijo ya
@ue el cdigo nativo puede (a"er sido programado para esperar un cierto tama7o concreto de las
mismas& Hacer esto con estructuras @ue tengan ta"las como campos no era !$cil en C# F&P ya @ue al ser
,stas o"jetos de tipo re!erenciaB en realidad sus campos almacena"an re!erencias a los datos de la ta"la
y no los propios datos&
C# 9&: soluciona este pro"lema dando la posi"ilidad de de!inir en las estructuras campos de tipo
ta"la @ue se almacenar$ ocupando posiciones de memoria contiguas& Para elloB "asta preceder del
modi!icador fi)ed la de!inicin del campo& Por ejemploA
public struct Persona
{
public unsafe fixed char Nombre[100];
public int Edad;
}
)e este modoB los o"jetos de la estructura Persona siempre ocupar$n F:X "ytes =F:: por la ta"la
correspondiente al nom"re da persona y X por los "ytes del tipo int de la edad?
8o o"stanteB (ay @ue se7alar @ue este uso del modi!icador fi)ed slo !unciona en las de!iniciones de
campos @ue sean tablas unidimensionales "lanas =vectores? de estructuras en conte)tos insegurosB
y no en campos de clasesB ni en conte*tos segurosB ni con ta"las multidimensionales o dentadas&
&odificaciones en el compilador
Control de la #ersin del len$ua,e
- partir de la versin 9&: del &8%. rame'or2B el compilador de C# proporciona una nueva opcin
Alangversion @ue permite restringirle las caractersticas del lenguaje @ue se permitir$n usar durante la
compilacin para solo permitir las de una cierta versin o est$ndar del lenguaje& Por a(oraB los valores
@ue esta opcin admite son los siguientesA
/alor Eescri"ci!n
default 1tili/ar las caractersticas de la versin m$s actual del lenguaje para la @ue el
compilador se (aya preparado& %s lo @ue se toma "or defecto
IS+2 1sar las caractersticas de la versin F&P del lenguaje estandari/ada por ISO& Por
lo tantoB no se permitir$ el uso de gen,ricosB m,todos annimosB etc&RFYS
.a"la 9FA Identi!icadores de versiones del lenguaje
Por ejemploB dado el siguiente !ic(ero version9&cs @ue usa tipos parcialesA
partial class Version2
{
static void Main()
{
}
}
Si lo intentamos compilar como sigueA
csc version9&cs IlangversionAiso5F
O"tendremos un mensaje de error indic$ndonos @ue el uso de tipos parciales no est$ permitido en la
versin F&P est$ndar de C#A
Version9&cs=FBF?A error CSFZXXA eature fpartial typesf cannot "e used "ecause it is not part o!
t(e standardi/ed ISO C# language speci!ication
Control de la plata!orma de destino
)ado @ue a partir de la versin 9&: de Microso!t&8%. se so"ortan las arSuitecturas de 76 bits de
Intel ( FMEB el compilador de C# admite una nueva opcin A"latform por medio de la @ue se le puede
indicar el tipo de plata!orma (acia la @ue se desea dirigir el cdigo @ue se compila& #os valores @ue
admite son los siguientesA
/alor Significado
Fn(c"u Compilar para cual@uier plata!orma& %s lo @ue "or defecto se toma
Y_7 Compilar para los procesadores de O9 "its compati"les con Intel
Y76 Compilar para los procesadores de ZX "its compati"les con -M)
Itanium Compilar para los procesadores de ZX "its Intel Itanium
.a"la 99A Identi!icadores de plata!orma de destino
;racias a esta opcinB si el cdigo se dirige (acia una plata!orma de ZX "its y se intenta ejecutar "ajo
una plata!orma de O9 "its saltar$ un mensaje de error como el siguienteA
R -mpliar ImagenS
Por el contrarioB si se dirige a plata!ormas de O9 "its y se intenta ejecutar en una de ZX "itsB
autom$ticamente Nindo's simular$ la ejecucin del mismo en un entorno de O9 "its a trav,s de su
!uncionalidad NON =Nindo's On Nindo's?
-un@ue en principio lo ideal es realizar el c!digo lo m$s inde"endiente "osible de la "lataformaB
se da esta opcin por@ue cuando se opera con cdigo inseguro se pueden tener @ue reali/ar
suposiciones so"re las caractersticas concretas de la plata!orma (acia la @ue se dirige el cdigoB
!undamentalmente en lo @ue respecta al tama7o ocupado en memoria por ciertos tipos de datos @ue se
manipulen mediante aritm,tica de punteros&
En#o automtico de errores a Microso"t
- partir de &8%. 9&:B el compilador de C# da la opcin de enviar autom$ticamente a Microso!t los
errores internos del mismo @ue durante su uso pudiesen surgir para as !acilitar su deteccin y
correccin a Microso!t =errores de csc.e)e y no del cdigo @ue se pretenda compilar? Por ejemploB si se
intenta compilar el siguiente cdigo con el compilador de C# 9&: de la 0eta F del Microso!t&8%.
rame'or2 S)] 9&:A

using System;

using System.Collections;

class Error
{
'(numerator GetEnumerator()
{
try {}
catch { yield break; }
finally {}
}

static void Main()
{}
}
%l compilador su!rir$ un error interno @ue impedir$ !inali/ar el proceso de compilacinA
error CS:VGOA Internal Compiler %rror =:*c::::::V at address VZ)F%%CX?A li2ely culprit is
f.+-8SO+Mf&
-n internal error (as occurred in t(e compiler& .o 'or2 around t(is pro"lemB try simpli!ying
or c(anging t(e program near t(e locations listed "elo'& #ocations at t(e top o! t(e list are
closer to t(e point at '(ic( t(e internal error occurred&
error&cs=ZBFX?A error CS:VGXA Internal Compiler %rrorA stage f.+-8SO+Mf sym"ol
f%rror&;et%numerator=?f
error&cs=ZBFX?A error CS:VGXA Internal Compiler %rrorA stage f0I8)f sym"ol
f%rror&;et%numerator=?f
error&cs=ZBFX?A error CS:VGXA Internal Compiler %rrorA stage fCOMPI#%f sym"ol
f%rror&;et%numerator=?f
error&cs=ZBFX?A error CS:VGXA Internal Compiler %rrorA stage fCOMPI#%f sym"ol
f%rror&;et%numerator=?f
error&cs=ZBFX?A error CS:VGXA Internal Compiler %rrorA stage fCOMPI#%f sym"ol
f%rror&;et%numerator=?f
error&cs=XBY?A error CS:VGXA Internal Compiler %rrorA stage fCOMPI#%f sym"ol f%rrorf
error&cs=FFX9dYdO:BF?A error CS:VGXA Internal Compiler %rrorA stage fCOMPI#%f sym"ol
fjglo"al namespace6f
error&csA error CS:VGZA Internal Compiler %rrorA stage fCOMPI#%f
error CS:VGYA Internal Compiler %rrorA stage fCOMPI#%f
error CS:VGYA Internal Compiler %rrorA stage f0%;I8f
Para reali/ar el envo del error a Microso!t se puede usar la opcin Aerrorre"ort del compiladorB la
cual admite los siguientes valoresA
/alor Eescri"ci!n
None 8o enviar el error a Microso!t& %s lo @ue se (ace "or defecto&
1rom"t
Preguntar si enviar el error& %sto (ar$ @ue durante la compilacin se muestre al
usuario una ventana como la siguiente en la @ue se le pide permiso para la
reali/acin del envo y se le de la opcin de inspeccionar la in!ormacin @ue se
enviar$ a Microso!t por si desea asegurarse de @ue no se vayan a enviar datos
sensi"les so"re el e@uipo o el cdigo !uente compilado =puede @ue se les enve
parte del mismo para !acilitarles la deteccin del error?A
R -mpliar ImagenS
Send %nviar autom$ticamente la noti!icacin a Microso!tB sin necesidad de tener @ue
con!irmarlo a trav,s de la ventana @ue la opcin anterior muestra&
.a"la 9OA Opciones para el envo de errores a Microso!t
#o ideal es combinar esta o"ci!n con la o"ci!n Abugre"ort ya conocidaB para @ue as el in!orme
del error sea m$s rico y la deteccin de sus causas sea m$s sencilla& Como en este caso la in!ormacin
@ue se enviar$ a Microso!t es mayor y por consiguiente puede @ue se tarde muc(o m$s envi$rsela a
trav,s de Internet =so"re todo si se usa un mdem convencional para acceder a la +ed?B se in!ormar$
antes al usuario de esta circunstancia y se le preguntar$ si est$ seguro de reali/ar el envo& Si con!irmaB
aparecer$ una ventana como la siguiente con in!ormacin so"re el progreso del envo del in!orme de
errorA
R -mpliar ImagenS

Concreti0acin de a#isos a tratar como errores
#a opcin A%arnaserror permite a(ora @ue se le concreten los avisos @ue se desea @ue se traten
como errores& Por ejemploB para decirle @ue slo considere como errores los avisos con cdigo
CS::9GA
csc test&cs I'arnaserrorA9G
-s mismoB a VS&8%. se le (a a7adido la posi"ilidad de con!igurar los avisos a tratar como errores y
los avisos a !iltrar a trav,s de la (oja de propiedades del proyecto& %n concretoB desde sus controles
Configuration 1ro"erties @ =uild @ Treat 9arnings as Errors y Configuration 1ro"erties @ =uild
@ Su""ress s"ecific %arnings&
Visibilidad de los recursos
#as opciones Alin'res y Ares permiten a(ora especi!icar la visi"ilidad de los recursos @ue se
enla/ar$n o incrustar$n en el ensam"lado generadoB de modo @ue se pueda con!igurar no permitir
acceder a los mismos desde otros ensam"lados& Para elloB tras el identi!icador del recurso se puede
incluir una de estas partculas separada por una comaA
/alor Eescri"ci!n
"ublic Podr$ accederse a los recursos del ensam"lado li"remente desde cual@uier otro
ensam"lado& %s lo @ue se toma "or defecto
"rivate Slo podr$ accederse a los recursos desde el propio ensam"lado
.a"la 9XA Indicadores de visi"ilidad de recursos
Por ejemploA
csc test&cs Ilin2resAmisrecursos&resourcesBrecursos&csBprivate
irma de ensam"lados
%l compilador de C# 9&: incorpora opciones relacionadas con la !irma de ensam"lados @ue (asta
a(ora venan siendo proporcionada de manera e*terna al mismoB pues como al !in y al ca"o compilar
un ensam"lado con !irma o sin ella no es m$s @ue una opcin de compilacinB la !orma m$s lgica de
indicarlo es a trav,s de opciones del compilador&
Para poder instalar un ensam"lado en el ;-C es necesario @ue tenga un nom"re seguroJ es decirB @ue
est, !irmado& %ste proceso de !irma consiste en utili/ar una clave privada para ci!rar con ella el
resultado de aplicar un algoritmo de (as(ing al contenido del ensam"ladoB e incluir en su mani!iesto la
clave pC"lica con la @ue luego poder desci!rar la !irma y compro"ar @ue el ensam"lado no se (a
alterado y procede de @uien se espera&
Para generar la pareja de claves pC"lica5privada se puede utili/ar la (erramienta sn.e)e =singing tool?
del S)]B @ue se puede usar como sigue para generar aleatoriamente un par de claves y guardarlas en
un !ic(ero =por convenio se le suele dar e*tensin .sn'?A
sn H2 misClaves&sn2
#uegoB la !irma del ensam"lado se reali/ar$ especi!icando durante la compilacin la ruta del !ic(ero
en el @ue se almacenan las claves a utili/ar para reali/ar la !irma a trav,s de la nueva opcin A'e(file
incluida en el compilador de C# 9&: para estos menesteresA
csc test&cs I2ey!ileAmisClaves&sn2
%n lugar de especi!icar las claves como !ic(eroB tam"i,n es posi"le instalarlas en un contenedor
"Wblico y re!erenciar al mismo durante la compilacin& Para instalarlas en el contenedor se usa de
nuevo la (erramienta sn.e)eB indic$ndole a(ora la opcin Mi seguida de la ruta del !ic(ero y el nom"re
del contenedor donde instalarla& Por ejemploA
sn Hi misClaves&sn2 contenedorEosan
W al compilar se re!erenciara al contenedor con la opcin A'e(container de cscA
csc test&cs I2eynameAcontenedorEosan
%l uso de las opciones A'e(file y A'e(container son a(ora la pr$ctica recomendada por Microso!t
para la !irma de los ensam"ladosB en detrimento de los antiguos atri"utos de ensam"lado
Fssembl(Be(Dile y Fssembl(Be(Name @ue antes se usa"an para estas la"ores& )e (ec(oB si se insiste
en seguir utili/$ndolos el compilador emitir$ mensajes de aviso in!ormando de la inconveniencia de
(acerlo& #gicamenteB en los ensam"lados generados utili/ando estas opciones ya no estar$n presentes
dic(os atri"utos&
#as opciones I'e(file y A'e(container se pueden com"inar con Adela(sign para conseguir @ue el
proceso de !irma no se (aga al completoB sino @ue en ve/ de calcularse y guardarse la !irma del
ensam"lado entre sus metadatos slo se reserve en los mismos el espacio necesario para posteriormente
inclursela y se les a7ada la clave pC"lica con la @ue se podr$n instalar en el ;-C para reali/arles
prue"as& - esto se le conoce como firma "arcialB y para posteriormente reali/ar la !irma completa al
ensam"lado se puede utili/ar la utilidad sn.e)e para re!irmarloB ya sea en "ase a un !ic(ero de claves o
a un contenedor pC"lico tal y como a continuacin se muestra con los siguientes ejemplosA
sn&e*e H+ test&dll misClaves&sn2
sn&e*e H+c test&dll contenedorEosan
8uevamenteB en &8%. F&P la !irma retrasada de los ensam"lados se reali/a"a a trav,s de un atri"uto
de ensam"lado =Fssembl(Eela(Sign?B cosa @ue a(ora no se recomienda y @ue provocar$ la aparicin
de mensajes de aviso durante la compilacin si se utili/a&
uenteA (ttpAII'''&devjo2er&comIaspIindiceacontenido&asp*>coagrupoM.1CS

También podría gustarte