You are on page 1of 11

19.02.

13

Genricos - Tutorial C#

Contenidos Foros

Tutorial C# Introduccion a C# Programacion con C# Fundamentos de C# Operadores Instrucciones Estrcuturas de control. Definicin de clases Creacin de objetos Herencia y mtodos virtuales Polimorfismo Ocultacin de miembros Miembros de tipo Encapsulacin Espacios de nombres Importacin de espacios de nombres Espacio de nombres distribuidos Variables y tipos de datos Tablas unidimensionales Tablas multidimensionales La clase System.Array Cadenas de texto Constantes Orden de inicializacin de variables Mtodos Mtodos externos Constructores

Genricos
Concepto de genricos
C# 2.0 permite especificar los tipos utilizados en las definiciones de otros tipos de datos y de mtodos de forma parametrizada, de manera que en vez de indicarse exactamente cules son se coloque en su lugar un parmetro parmetro tipo- que se concretar en el momento en que se vayan a usar (al crear un objeto de la clase, llamar al mtodo,) A estas definiciones se les llama genricos, y un ejemplo de una de ellas es el siguiente:
pbi casAT ulc ls <> { Tvlr ao; pbi vi EtbeeVlrTvlr ulc od salcrao( ao) { ti.ao =vlr hsvlr ao; } }

Contenido Concepto de genricos Usos de los genricos Sintaxis Limitaciones Restricciones Valores por defecto Ambigedades

Server Error
Encuesta Si trabajas con .NET Que entorno utilizas? Visual Studio 2003 Visual Studio 2005 Visual Studio 2008

En esta clase no se han concretando ni el tipo del campo privado valor ni el del nico parmetro del mtodo EstablecerValor() En su lugar se le especificado un parmetro tipo T que se concretar al utilizar la clase. Por ejemplo, al crear un objeto suyo:

Ait oj=nwAit(; <n> b e <n>)

No trabajo con .NET [Ver] [Votar]

Esto creara un objeto de la clase genrica A con el parmetro tipo T concretizado con el argumento tipo int. La primera vez que el CLR encuentre esta concretizacin de T a int realizar un proceso de expansin o instanciacin del genrico consistente en generar una nueva clase con el resultado de sustituir en la definicin genrica toda aparicin de los parmetros tipos por los argumentos tipo. Para el ejemplo anterior esta clase sera:
pbi casAit ulc ls <n> { itvlr n ao; pbi vi EtbeeVlritvlr ulc od salcrao(n ao) { ti.ao =vlr hsvlr ao; } }

A los tipos con parmetros tipo, como A<T>, se les llama tipos genricos cerrados; a los generados al concretrseles algn parmetro tipo se le llama tipos construidos; y a los generados al concretrseles todos tipos genricos abiertos. La relacin establecida entre ellos es similar a la establecida entre las clases normales y los objetos: al igual que clases sirven de plantillas en base a las que crear objetos, los tipos genricos cerrados actan como plantillas en base a las que crear tipos genricos abiertos. Por eso, en el C++ tradicional se llamaba plantillas a las construcciones equivalentes a los genricos. La expansin la hace el CLR en tiempo de ejecucin, a diferencia de lo que sucede en otros entornos (pe, C++) en los que se realiza al compilar. Esto tiene varias ventajas: Ensamblados ms pequeos: Como slo almacenan el tipo genrico cerrado, que el CLR ya expandir en tiempo de ejecucin, su tamao es ms pequeo y se evita el problema del excesivo inflado del cdigo binario generado (code bloat) Adems, para evitar el inflado de la memoria consumida, el CLR reutiliza gran parte del MSIL generado para la primera expansin de un genrico por un tipo referencia en las siguientes expansiones del mismo por otros tipos
1/11

Destructores www.devjoker.com/html/Genricos.html

19.02.13 Destructores

Genricos - Tutorial C#

Propiedades Indizadores Redefinicin de operadores Delegados y eventos La clase MulticastDelegate Llamadas asncronas Implementacin interna de los delegados Eventos Estructuras Boxing y unboxing Constructores de estructuras Enumeraciones Interfaces Excepciones Otras instrucciones Atributos Definicin de nuevos atributos Lectura de atributos en tiempo de ejecucin Atributos de compilacin Pseudoatributos Cdigo inseguro Definicin de punteros Manipulacin de punteros Operadores relacionados con cdigo inseguro Fijacin de variables apuntadas Novedades de C# 2.0 Genricos Tipos parciales Iteradores Mejoras en la manipulacin de delegados Tipos anulables Modificadores de visibilidad de bloques get y set Clases estticas Referencias a espacios de nombres

referencia, ya que todas las referencias son al fin y al cabo punteros que en memoria se representan igual. Metadatos ricos: Al almacenarse los tipos genricos cerrados en los ensamblados, se podrn consultar mediante reflexin y ser aprovechados por herramientas como el IntelliSense de Visual Studio.NET para proporcionar ayuda sobre su estructura. Implementacin fcil: Como es el propio CLR quien realiza gran parte del trabajo necesario para dar soporte a los genricos, la inclusin de los mismos en cualquiera de los lenguajes .NET se simplifica considerablemente.

Usos de los genricos


Los genricos no son una novedad introducida por C# en el mundo de la programacin, sino que otros lenguajes como Ada, Eiffel o C++ (plantillas) ya las incluyen desde hace tiempo. Su principal utilidad es, como su propio nombre indica, facilitar la creacin de cdigo genrico que pueda trabajar con datos de cualquier tipo. Esto es especialmente til para crear tipos que acten como colecciones (pilas, colas, listas, etc.), cosa que C# 1.X slo permita crear definindolos en base a la clase base comn object. Por ejemplo, una cola que admitiese objetos de cualquier tipo haba que declararla como sigue:

pbi casCl ulc ls oa { ojc[ eeets bet] lmno; pbi itNmrEeets ulc n eolmno; pbi vi Eclrojc vlr; ulc od noa(bet ao) {} pbi ojc Dsnoa( ulc bet eeclr) {} }

El primer problema de esta solucin es lo incmoda y proclive a errores que resulta su utilizacin, pues a la hora de extraer valores de la cola habr que convertirlos a su tipo real si se quieren aprovechar sus miembros especficos. Es decir:

Cl mCl =nwCl(; oa ioa e oa) mCl.noa(Et e uapub"; ioaEclr"so s n rea) srn vlreecld =(tig mCl.eeclr) tig aoDsnoao srn) ioaDsnoa(;

Aparte de que el programador tenga que escribir (string) cada vez que quiera convertir alguna de las cadenas extradas de miCola a su tipo concreto, qu ocurrir si por error introduce un valor que no es ni string ni de un tipo convertible a string (por ejemplo, un int) y al extraerlo sigue solicitando su conversin a string? Pues que el compilador no se dar cuenta de nada y en tiempo de ejecucin saltar una InvalidCastException. Para resolver esto podra pensarse en derivar un tipo ColaString de Cola cuyos mtodos pblicos trabajasen directamente con cadenas de textos (Encolar(string valor) y string Desencolar()) Sin embargo, no es una solucin fcil de reutilizar ya que para cualquier otro tipo de elementos (pe, una cola de ints) habra que derivar una nueva clase de Cola. Otro problema de ambas soluciones es su bajo rendimiento, puesto que cada vez que se almacene un objeto de un tipo referencia en la cola habr que convertir su referencia a una referencia a object y al extraerlo habr que volverla a transformar en una referencia a string. Y para los tipos valor todava es peor!, en tanto que habr que realizar boxing y unboxing, procesos que son mucho ms lentos que las conversiones de referencias. Si por el contrario se hubiese definido la cola utilizando genricos tal y como sigue:
pbi casCl<> ulc ls oaT { T]eeets [ lmno; pbi itNmrEeets ulc n eolmno; pbi vi EclrTvlr ulc od noa( ao) {} pbi TDsnoa( ulc eeclr) {} }

Entonces la extraccin de objetos de la cola no requerira de ningn tipo de conversin y sera tan cmoda y clara como sigue:

Cl<tig mCl =nwCl<tig(; oasrn> ioa e oasrn>) mCl.noa(Et e uapub"; ioaEclr"so s n rea) srn vlreecld =mCl.eeclr) tig aoDsnoao ioaDsnoa(;

Si ahora por equivocacin el programador solicitase almacenar un objeto cuyo tipo no fuese ni string ni convertible Supresin temporal a l, obtendra un error al compilar informndole de ello y evitando que el fallo pueda llegar al entorno de ejecucin. www.devjoker.com/html/Genricos.html

2/11

19.02.13 Supresin temporal de avisos

Atributos condicionales Incrustacin de tablas en estructuras Modificaciones en el compilador Tambin puedes ver ... TransactionScope Simplificando el trabajo con transacciones. LinQ To SQL - Un ejemplo sencillo Cmo activar Intelisense (autocompletado) en el Web.config Leer un campo XML de SQL Server 2005 con C# TripleDES - Un ejemplo practico en C# Mostrar un GridView dentro de un DataList Mtodos Extensores: INNER JOIN String.Format Problemas en la instalacin de Visual Studio 2008-Visual studio web authoring component Redimiento de VS2008

Genricos - Tutorial C# a l, obtendra un error al compilar informndole de ello y evitando que el fallo pueda llegar al entorno de ejecucin. Adems, el rendimiento del cdigo es muy superior ya que no requerir conversiones de referencias a/desde object. Si realiza pruebas podr comprobar que la utilizacin de genricos ofrece mejoras en el rendimiento entorno al 20% para los tipos referencia, y al 200% para los tipos valor!

Sintaxis
El CLR de .NET 2.0 permite definir genricamente tanto clases como estructuras, interfaces, delegados y mtodos. Para ello basta con indicar tras el identificador de las mismas su lista de sus parmetros genricos entre smbolos < y > separados por comas. Con ello, dentro de su definicin (miembros de las clases, cuerpos de los mtodos, etc.) se podr usar libremente esos parmetros en cualquier sitio en que se espere un nombre de un tipo. La siguiente tabla muestra un ejemplo para cada tipo de construccin vlida: Ejemplo declaracin pbi casNd<> ulc ls ooT { pbi TDt; ulc ao pbi Nd<>Sgine ulc ooT iuet; } pbi src Prj<,> ulc tut aeaTU { pbi TVlr; ulc ao1 pbi UVlr; ulc ao2 } itraeIoprbeT nefc Cmaal<> { itCmaaCnTorVlr; n oprro( toao) } pbi it ulc n CmaaCnProaproa oprro(esn esn) {.} .. } dlgt vi Taa<>Tvlr; eeae od rtrT( ao) Taa<n>ojrtr= rtrit bTaa nwTaa<n>F; e rtrit() casA IoprbeProa ls : Cmaal<esn> { Prj<n,srn>mPrj; aeait tig iaea mPrj.ao1=1 iaeaVlr ; mPrj.ao2="oa; iaeaVlr Hl" Ejemplo uso casNd8iAazd:Nd<ye ls ooBtvnao oobt> {.} ..

pbi vi Fitx ulc od (n ) {.} .. vi itraba<>rfTvlr, od necmirT(e ao1 rfTvlr) e ao2 { ti.necmirdcml hsitraba<eia> (e d,rfd) rf 1 e 2; Ttm =vlr; ep ao1 vlr =vlr; ao1 ao2 vlr =tm; ao2 ep ti.necmirrfd,rfd) hsitraba(e 1 e 2; dcmld =0 d =1 eia 1 , 2 ;

} Tabla 19: Ejemplos de declaracin de tipos y miembros genricos Ntese que todos los ejemplos de nombres de parmetros genricos hasta ahora vistos son nica letra maysculas (T, U, etc.) Aunque obviamente no es obligatorio, sino que se les puede dar cualquier identificador vlido, es el convenio de nomenclatura utilizado en la BCL del .NET Framework 2.0 y el que por tanto se recomienda seguir. Lo que s es obligatorio es no darles nunca un nombre que coincida con el del tipo o miembro al que estn asociados o con el de alguno de los miembros de ste. www.devjoker.com/html/Genricos.html

3/11

19.02.13

con el de alguno de los miembros de ste.

Genricos - Tutorial C#

Fjese adems que la segunda llamada del ejemplo de utilizacin del mtodo genrico intercambiar() no explicita el tipo del parmetro genrico. Esto se debe a que C# puede realizar inferencia de tipos y deducir que, como para todos parmetros del tipo T se ha especificado un valor decimal, T debe concretarse como decimal.

Limitaciones
En principio, dentro de los tipos genricos se puede declarar cualquier miembro que se pueda declarar dentro de un tipo normal, aunque existe una limitacin: no se pueden declarar puntos de entrada (mtodos Main())ya que a stos los llama el CLR al iniciar la ejecucin del programa y no habra posibilidad de concretizarles los argumentos tipo. Afiliados La Web del programador MundoProgramacion Por su parte, los parmetros tipo se pueden usar en cualquier sitio en que se espere un tipo aunque tambin con ciertas limitaciones: No pueden usarse en atributos, alias, punteros o mtodos externos, ni en los nombres de las clases bases o de las interfaces implementadas. Sin embargo, excepto en el caso de los punteros, en estos sitios s que se pueden especificar tipos genricos cerrados; e incluso en los nombres de las clases o de las interfaces base, tambin se pueden usar tipos genricos abiertos. Por ejemplo:
/ casAT:T{ / Err N s peeua Tcm itra / ls <> } / ro. o e ud sr oo nefz / ocaebs / ls ae casAT { ls <> } itraeI<>{ nefc 1V } casBT:AT,I<tig { / O. ls <> <> 1srn> } / K

Debe tenerse cuidado al definir miembros con parmetros tipos ya que ello puede dar lugar a sutiles ambigedades tal y como la que se tendra en el siguiente ejemplo:
casAT ls <> { vi Fitx srn s { od (n , tig ) } vi FTx srn s { od ( , tig ) } }

Si se solicitase la expansin A<int>, el tipo construido resultante acabara teniendo dos mtodos de idntica signatura. Aunque en principio, el compilador de C# 2.0 debera de asegurar que tras cualquier expansin siempre se generen tipos genricos abiertos vlidos, produciendo errores de compilacin en caso contrario, por el momento no lo hace y deja compilar clases como la anterior. Sencillamente, si llamamos al mtodo F() de un objeto A<int>, la versin del mtodo que se ejecutar es la primera. Es decir, en las sobrecargas los parmetros tipo tienen menos prioridad que los concretos. Donde no resulta conveniente controlar que los parmetros genricos puedan dar lugar a mtodos no vlidos es en las redefiniciones de operadores de conversin, en concreto en lo referente al control de que las expansiones puedan dar lugar a redefiniciones de las conversiones predefinidas (como las de a/desde object), puesto que si se hiciese los parmetros tipo nunca se podran utilizar en las conversiones. Por ello, simplemente se ignoran las conversiones a medida que al expandirse puedan entrar en conflicto con las predefinidas. Por ejemplo, dado el siguiente cdigo:
uigSse; sn ytm pbi casCnesoGnrc<> ulc ls ovrineeiaT { pbi sai ipii oeao TCnesoGnrc<>ojt) ulc ttc mlct prtr (ovrineeiaT beo { Toj=dfutT; b eal() CnoeWieie"prdrd cnes ipia) osl.rtLn(Oeao e ovrin mlct"; rtr oj eun b; } } pbi casPicpl ulc ls rnia { pbi sai vi Mi( ulc ttc od an) { CnesoGnrc<rnia>ojt1 ovrineeiaPicpl beo= nwCnesoGnrc<rnia>) e ovrineeiaPicpl(; Picplojt2=ojt1 / Cnes n peeiia( Picpl rnia beo beo; / ovrin o rdfnd a rnia) CnoeWieie"ne d cnes n peeiia) osl.rtLn(Ats e ovrin o rdfnd"; CnesoGnrc<bet ojt3=nwCnesoGnrc<bet(; ovrineeiaojc> beo e ovrineeiaojc>) ojc ojt4=ojt3 / Cnes peeiia( ojc) bet beo beo; / ovrin rdfnd a bet } }

El resultado de su ejecucin demuestra que la versin implcita de la conversin solo se ejecuta ante la conversin no predefinida, puesto que su salida es la siguiente:

Operador de conversin implcita Antes de conversin no predefinida


www.devjoker.com/html/Genricos.html 4/11

19.02.13

Genricos - Tutorial C#

Donde nunca habr ambigedades es ante clases como la siguiente, ya que sea cual sea el tipo por el que se concretice T siempre ser uno y por tanto nunca se podr dar el caso de que la segunda versin de F() coincida en signatura con la primera:
casAT ls <> { vi Fitx srn s { od (n , tig ) } vi FTx Ts { od ( , ) } }

As mismo, tambin se admitiran dos mtodos como los siguientes, ya que se considera que los parmetros tipo forman parte de las signaturas:
casA ls { vi FT(n x srn s { od <>it , tig ) } vi Fitx srn s { od (n , tig ) } }

Y al redefinir mtodos habr que mantener el mismo nmero de parmetros tipo en la clase hija que en la clase padre para as conservar la signatura. Esto, como en el caso de los parmetros normales, no implica mantener los nombres de los parmetros tipo, sino slo su nmero. Por tanto, cdigos como el siguiente sern perfectamente vlidos:
pbi casA ulc ls { poetdvrulvi FT U( prmto,Uprmto) rtce ita od <, >T aer1 aer2 { } } pbi casBA ulc ls : { poetdoerd vi FX Y( prmto,Yprmto) rtce vrie od <, >X aer1 aer2 { } }

Restricciones
Probablemente a estas alturas ya est pensado que si en tiempo de diseo no conoce el tipo concreto de los parmetros genricos, cmo podr escribir cdigo que los use y funcione independientemente de su concretizacin? Es decir, dado un mtodo como:
TOeaT( vlr,Tvlr) pr<>T ao1 ao2 { itrslaooprc =vlr.oprT(ao2; n eutdCmaain ao1Cmaeovlr) i (eutdCmaain0 f rslaooprc>) rtr vlr-ao2; eun ao1vlr es i(eutdCmaain0 le frslaooprc<) rtr Mt.o(ao1 vlr); eun ahPwvlr, ao2 es le rtr 20; eun .d }

Si se le llamase con Opera(2.0d, 3.2d) no habra problema, pues los objetos double tanto cuentan con un mtodo CompareTo() vlido, como tienen definida la operacin de resta, se admiten como parmetros del mtodo Pow() de la clase Math y van a generar valores de retorno de su mismo tipo double. Pero, y si se le llamase con Opera("hola", "adis")? En ese caso, aunque los objetos string tambin cuentan con un mtodo CompareTo() vlido, no admiten la operacin de resta, no se puede pasar como parmetros a Pow() y el valor que devolvera return 2.0d; no coincidira con el tipo de retorno del mtodo. Esta inconsistencias son fciles de solucionar en entornos donde la expansin se realiza en tiempo de compilacin, pues el compilador informa de ellas. Sin embargo, en los que se hace en tiempo de ejecucin seran ms graves ya que durante la compilacin pasaran desapercibidas y en tiempo de ejecucin podran causar errores difciles de detectar. Por ello, C# en principio slo permite que con los objetos de tipos genricos se realicen las operaciones genricas a cualquier tipo: las de object. Por ejemplo, el cdigo que sigue sera perfectamente vlido ya que tan slo utiliza miembros de object:
pbi sai bo RpeetcoeECdnIulsTU ulc ttc ol ersnainsnaeagae<,> ( ojt1 Uojt2 T beo, beo) { rtr ojt1TSrn( = ojt2TSrn(; eun beo.otig) = beo.otig) }

Obviamente, tambin compilar un cdigo en el que los parmetros genricos con los que se realicen operaciones
www.devjoker.com/html/Genricos.html 5/11

19.02.13

Genricos - Tutorial C#

no comunes a todos los objects se conviertan antes a tipos concretos que s las admitan, aunque entonces si se le pasasen argumentos de tipos no vlidos para esa conversin saltara una InvalidCastException en tiempo de ejecucin. Por ejemplo, el siguiente mtodo compilar pero la ejecucin fallar en tiempo de ejecucin cuando se le pasen parmetros no convertibles a int.
pbi sai itSm<,>Tvlr,Uvlr) ulc ttc n uaTU( ao1 ao2 { rtr (it (bet vlr)+(it (bet vlr) eun (n) ojc) ao1 (n) ojc) ao2; }

Ntese que por seguridad ni siquiera se permite la conversin directa de un parmetro tipo a cualquier otro tipo que no sea object y ha sido necesario hacerla indirectamente. Lgicamente, C# ofrece mecanismos con los que crear cdigos genricos que a la vez sean seguros y flexibles para realizar otras operaciones aparte de las que vlidas para cualquier object. Estos mecanismos consisten en definir restricciones en el abanico de argumentos tipo vlidos para cada parmetro tipo, de modo que as se puedan realizar con l las operaciones vlidas para cualquier objeto de dicho subconjunto de tipos. Las restricciones se especifican con clusulas where <parmetroGenrico>:<restricciones> tras la lista de parmetros de los mtodos y delegados genricos, o tras el identificador de las clases, estructuras e interfaces genricas; donde <restricciones> pueden ser: Restricciones de clase base: Indican que los tipos asignados al parmetro genrico deben derivar, ya sea directa o indirectamente, del indicado en <restricciones>. As, en el cdigo genrico se podrn realizar con seguridad todas las operaciones vlidas para los objetos dicho tipo padre, incluidas cosas como lanzarlos con sentencias throw o capturarlos en bloques catch si ese padre deriva de Exception. Por ejemplo:
uigSse; sn ytm casA ls { pbi itVlr ulc n ao; } casBA ls : { pbi sai itIceetrao<>Tojt)weeTA ulc ttc n nrmnaVlrT( beo hr : { rtr +ojt.ao; eun +beoVlr } sai vi Mi( ttc od an) { CnoeWieieBIceetrao(e B)) / Ipie1 osl.rtLn(.nrmnaVlrnw (); / mrm CnoeWieieBIceetrao(e A)) / Ipie1 osl.rtLn(.nrmnaVlrnw (); / mrm / CnoeWieieBIceetrao(e C)) / Err / osl.rtLn(.nrmnaVlrnw (); / ro } } casC{ ls }

Esta restriccin adems permite asegurar que el argumento tipo siempre ser un tipo referencia, por lo que con podr utilizar en los contextos en que slo sean vlidos tipos referencia, como por ejemplo con el operador as. As mismo, tambin permite realizar conversiones directas del parmetro tipo a su tipo base sin tenerse que pasar antes por la conversin a object antes vista. Restricciones de interfaz: Son similares a las anteriores, slo que en este caso lo que indican es que los tipos que se asignen al parmetro tipo deben implementar las interfaces que, separadas mediante comas, se especifiquen en <restricciones> As se podrn usar en todos aquellos contextos en los que se esperen objetos que las implementen, como por ejemplo en sentencias using si implementan IDisposable. Restricciones de constructor: Indican que los tipos por los que se sustituya el parmetro genrico debern disponer de un constructor pblico sin parmetros. Se declaran especificando new() en <restricciones>, y sin ellas no se permite instanciar objetos del parmetro tipo dentro de la definicin genrico. Es decir:
/ Cret,pe s idc qee tp pre qes cnrtc T / orco us e nia u l io o l u e oceie / dbr d tnru cntutrsnprmto / ee e ee n osrco i aers casAT weeTnw) ls <> hr :e( { pbi TCerbeo) ulc raOjt( { rtr nwT) eun e (; } } / Icret,y qeat e nwT)n s sb s e tp pre * norco a u ne l e ( o e ae i l io o l qes cnrtc Ttnr u cntutrsnprmto u e oceie ed n osrco i aers casBT ls <> { pbi TCerbeo) ulc raOjt( { rtr nwT) eun e (;

www.devjoker.com/html/Genricos.html

6/11

19.02.13
} } * /

rtr nwT) eun e (;

Genricos - Tutorial C#

Cada genrico puede tener slo una clusula where por parmetro genrico, aunque en ella se pueden mezclar restricciones de los tres tipos separadas por comas. Si se hace, stas han de aparecer en el orden en que se han citado: la de clase base primero y la de constructor la ltima. Por ejemplo, el tipo por el que se sustituya el parmetro genrico del siguiente mtodo deber derivar de la clase A, implementar las interfaces I1 e I2 y tener constructor pblico sin parmetros:

vi MMtd<>( ojt)weeT A I,I,nw) od iooT T beo hr : , 1 2 e( {.} ..

Las restricciones no se heredan, por lo que si de una clase genrica con restricciones se deriva otra clase genrica cuyos parmetros tipo se usen como parmetros de la clase padre, tambin habrn de incluirse en ella dichas restricciones para asegurase de que cualquier argumento tipo que se le pase sea vlido. Igualmente, en las redefiniciones habr que mantener las restricciones especficas de cada mtodo. O sea:
casA{ ls } casBT weeTA ls <> hr : { } / N vld,Tdb srd tp Apr pdrsrpsd cm agmno * o io ee e e io aa oe e aao oo ruet tp d B ydcarsrcinn l hrd atmtcmnee Td C io e , ih etic o a eea uoiaet l e . casCT:<> ls <>BT { } * / casCT:<>weeTA/ Vld ls <>BT hr : / io { }

Ntese que todas estas restricciones se basan en asegurar que los argumentos tipo tengan determinadas caractersticas (un constructor sin parmetros o ciertos miembros heredados o implementados), pero no en las propias caractersticas de esos tipos. Por lo tanto, a travs de parmetros tipo no podr llamarse a miembros estticos ya que no hay forma de restringir los miembros estticos que podrn tener los argumentos tipo. Finalmente, cabe sealar que en realidad tambin existe una cuarta forma de restringir el abanico de argumentos tipos de un tipo genrico, que adems es mucho ms flexible que las anteriores y permite aplicar cualquier lgica para la comprobacin de los tipos. Consiste en incluir en el constructor esttico del tipo genrico cdigo que lance alguna excepcin cuando los argumentos tipo especificados no sean vlidos, abortndose as la expansin. Por ejemplo, un tipo genrico C<T> que slo admita como argumentos tipos objetos de las clases A o B podra crearse como sigue:
casCT ls <> { sai C) ttc ( { i (!tpo()= tpo() & !tpo()= tpo()) f (yefT = yefA) & (yefT = yefB) trwnwAgmnEcpin"lagmnotp pr Tdb srAoB) ho e ruetxeto(E ruet io aa ee e "; } }

O si se quisiese que tambin los admitiese de cualquier clase derivada de stas, podra aprovecharse como sigue el mtodo bool IsAssignableForm(Type tipo) de los objetos Type, que indica si el objeto al que se aplica representa a un tipo al que se le pueden asignar objetos del tipo cuyo objeto System.Type se le indica como parmetro:
casCT ls <> { sai C) ttc ( { i (!tpo()IAsgalFo(yefT) & f (yefB.ssinbermtpo()) & !tpo()IAsgalFo(yefT)) (yefA.ssinbermtpo()) trwnwAgmnEcpin"lagmnotp pr Tdb srAoB) ho e ruetxeto(E ruet io aa ee e "; } }

El nico problema de esta forma de restringir el abanico de tipos es que desde el cdigo del tipo genrico no se podr acceder directamente a los miembros especficos del tipo argumento, sino que antes habr que convertirlos explcitamente a su tipo. Por ejemplo:
uigSse; sn ytm pbi casA ulc ls {

www.devjoker.com/html/Genricos.html

7/11

19.02.13

Genricos - Tutorial C#
{ pbi vi Mtd( ulc od oo) { CnoeWieie"jctd Mtd( d ojt A) osl.rtLn(Eeuao oo) e beo "; } } pbi casB ulc ls { pbi vi Mtd( ulc od oo) { CnoeWieie"jctd Mtd( d ojt B) osl.rtLn(Eeuao oo) e beo "; } } casCT ls <> { sai C) ttc ( { i (!tpo()= tpo() & !tpo()= tpo()) f (yefT = yefA) & (yefT = yefB) trwnwAgmnEcpin"lagmnotp pr Tdb ho e ruetxeto(E ruet io aa ee srAoB) e "; } pbi vi LaaAooTojt) ulc od lmrMtd( beo { i (beoi A f ojt s ) (beoa A.oo) / Hyqehcrcnes epia ojt s )Mtd(; / a u ae ovrin xlct es le (beoa B.oo) / Hyqehcrcnes epia ojt s )Mtd(; / a u ae ovrin xlct } } casPicpl ls rnia { sai vi Mi( ttc od an) { CA ojtC =nwCA(; <> beoA e <>) ojtC.lmrMtd(e A); beoALaaAoonw () CB ojtC =nwCB(; <> beoB e <>) ojtC.lmrMtd(e B); beoBLaaAoonw () } }

Valores por defecto


Cuando se trabaja con tipos genricos puede interesar asignarles el valor por defecto de su tipo, pero cul ser ste? Es decir, si el parmetro genrico se sustituye por un tipo referencia, el valor por defecto de sus objetos sera null y valdran cdigos como:
vi FT( od <>) { Tojt =nl ; beo ul }

Sin embargo, si se sustituyese por un tipo valor no sera vlido, por lo que este tipo de asignaciones nunca se admitirn salvo que haya establecido una restriccin de clase base que asegure que el argumento tipo sea siempre un tipo referencia. No obstante, C# 2.0 permite representar el valor por defecto de cualquier parmetro tipo con la sintaxis default(<parmetroTipo>), lo que dejara al ejemplo anterior como sigue:
vi FT( od <>) { Tojt =dfutT; beo eal() }

En cada expansin, el CLR sustituir la expresin default(T) por el valor por defecto del tipo que se concrete para T (0, null, false,...), dando lugar a mtodos como: Expansin para int Expansin para string Expansin para bool

vi Fit( od <n>) vi Fsrn>) od <tig( vi Fbo>) od <ol( { { { itojt =; itojt =nl; itojt =fle n beo 0 n beo ul n beo as; } } } Ntese pues que para comprobar si un cierto argumento tipo es un tipo valor o un tipo referencia bastar con comprobar si su default devuelve null. As por ejemplo, para crear un tipo genrico que slo admita tipos referencia se podra hacer:
casGnrcSlRfrnisT ls eiooeeeca<> {

www.devjoker.com/html/Genricos.html

8/11

19.02.13

{ sai GnrcSlRfrnis) ttc eiooeeeca( { i (eal()=ul f dfutT!nl) trwnwAgmnEcpin" db sru tp rfrni"; ho e ruetxeto(T ee e n io eeeca) } }

Genricos - Tutorial C#

Por su parte, y a diferencia de lo que ocurre con el operador de asignacin, el operador de igualdad (==) s que puede aplicarse entre instancias de parmetros tipo y null, an cuando estos almacenen tipos valor y dicha comparacin no sea vlida. En dichos casos la comparacin simplemente retornara false. Igualmente, tambin se les podr aplicar el operador de desigualdad (!=), que siempre devolver true para los tipo valor.

Ambigedades
El que los delimitadores de los argumentos tipo sean los mismos que los operadores de comparacin "mayor que" y "menor que" y utilicen como el mismo carcter separador que se usa para separar los argumentos de las llamadas a mtodos (la coma ,) puede dar lugar a ambigedades. Por ejemplo, una llamada como la siguiente:

FGAB(); (<,>7)

Podra interpretarse de dos formas: Como una llamada a un mtodo F() con el resultado de evaluar G<A como primer argumento y el resultado de B>(7) como segundo, o como una llamada a F() con el resultado de una llamada G<A,B>(7) a un mtodo genrico G() Lo que hace el compilador es interpretar como llamadas a mtodos genricos cualquier aparicin del carcter > donde a este le sigan alguno de estos caracteres: (, ), ], >, ;, :, ,?, . ,. En el resto de casos sern tratados como operadores de comparacin. Por tanto, en el ejemplo anterior la expresin ser interpretada como una llamada a un mtodo genrico, y para que se interpretase de la otra forma habra rescribirse como F(G<A,B>7); Versin para imprimir Foros de consulta

Inicio | Tutorial C#

Aadir comentario ... Autor: Ttulo:

Para preguntar utiliza los foros

Para preguntar utiliza los foros.

Inicio | Tutorial C# Genricos


Autor: Jos Antonio Visitas: 6774

Versin para imprimir

Gonzlez Seco

Fecha de publicacin: 11/12/2006 Jos Antonio es experto en tecnologias Microsoft. Imparte cursos y conferencias en congresos sobre C# y .NET en Universidades de toda Espaa (Sevilla, Barcelona, San Sebastin, Valencia, Oviedo, etc.) en representacin de grandes empresas como Microsoft.

Palabras En Ingles Y Espaol


www.ganandoconingles.com Te Presentamos la Nueva Forma de Aprender Ingls a tu Manera Hoy

Lo ms nuevo ...

Donde se habla ...

18/08/2008

SQL Server 2008 Visitas: 39 | Comentarios: 0 | Archivo: Articulos Categorias: Transact-SQL


9/11

www.devjoker.com/html/Genricos.html

19.02.13

Categorias: Transact-SQL 11/08/2008

Genricos - Tutorial C#

TransactionScope - Simplificando el trabajo con transacciones. Visitas: 131 | Comentarios: 0 | Archivo: Articulos Categorias: C#| ADO.NET| LinQ

07/08/2008

Una madre con mala leche ... Visitas: 161 | Comentarios: 1 | Archivo: Articulos Categorias: Humor 16/07/2008 WCF: comparticin de tipos entre referencias a servicios Visitas: 154 | Comentarios: 0 | Archivo: Articulos Categorias: WCF 15/07/2008 WCF: netTcpBinding con seguridad tipo Custom Visitas: 123 | Comentarios: 0 | Archivo: Articulos Categorias: WCF 11/07/2008 Google Trends, adis Alexa adis ... Visitas: 210 | Comentarios: 0 | Archivo: Articulos Categorias: ASP.NET 08/07/2008 Fiddler - Indispensable para el desarrollo Web Visitas: 278 | Comentarios: 5 | Archivo: Articulos Categorias: ASP.NET 01/07/2008 LinQ To SQL - Un ejemplo sencillo Visitas: 4990 | Comentarios: 4 | Archivo: Articulos Categorias: C#| Transact-SQL| LinQ 11/06/2008 Problemas con el diseador Web de Visual Studio 2008 Visitas: 602 | Comentarios: 1 | Archivo: Articulos Categorias: Visual Studio 03/06/2008 Formatear nmeros en SQL Server Visitas: 1402 | Comentarios: 1 | Archivo: Articulos Categorias: Transact-SQL

timos temas recibidos en los foros ... Y lo mismo en WEB por systemat ... [C#] Manual del minicom de Linux con fotos. por Meta ... [UNIX] PROGRAMACION por JUANMA ... [Visual Basic .NET] Conectar ASP con B.D Informix por Franco ... [ASP] Codigo salir por Jazmin ... [ASP.NET] EXPORTAR DATOS A ARCHIVOS PLANOS. por WIX ... [ORACLE] formulario por artdark ... [C#] Codigo salir por Jazmin ... [ASP.NET] cambiar de modo un gried view por ivan ... [ASP.NET] ayuda urgente porfavor por vicancer ... [ASP.NET] pollo por hajaj ... [Actualidad] DIOS TE BENDIGA por El You ... [WIN 98/NT/2000/XP] Access Actualidad ASP ASP.NET C# CGI HTML/DHTML/XHTML ISAPI Java JavaScript JSP LINUX MS DOS mySQL Opinion ORACLE PHP Power Builder SQL SQL Server 1 18/08/2008 4 17/08/2008 1 19/08/2008 9 02/05/2007 1 18/08/2008 10 06/08/2007 2 04/08/2008 0 18/08/2008 0 18/08/2008 0 18/08/2008 1 15/08/2008 1 16/08/2008 UNIX Visual Basic .NET Visual Basic 6.0 WIN 98/NT/2000/XP

Te recomendamos adems ... 19/10/2005 Configurar el IIS para ejecutar aplicaciones ASP.net 27/10/2006 Eventos forma parte de...Tutorial C# 22/10/2005 Introduccin SQL forma parte de...Tutorial SQL 31/03/2006 Tipos de datos en PL/SQL forma parte de...Tutorial PL/SQL 22/10/2005 Actualizacin de datos. UPDATE forma parte de...Tutorial SQL 22/10/2005 Componentes del lenguaje SQL forma parte de...Tutorial SQL 28/06/2006 Triggers en PL/SQL forma parte de...Tutorial PL/SQL 07/11/2006 Enumeraciones forma parte de...Tutorial C# 28/06/2006 Excepciones en PL/SQL forma parte de...Tutorial PL/SQL 22/10/2005 Insertar datos. INSERT forma parte de...Tutorial SQL

www.devjoker.com/html/Genricos.html

10/11

19.02.13

Genricos - Tutorial C#

Medida De Fuerza
www.test-gmbh.de Mquinas de ensayo y torsin pruebas de materiales /componentes

www.devjoker.com/html/Genricos.html

11/11

You might also like