programacion con ado.net c#.pdf

Upload: carlos-cuarezma

Post on 12-Oct-2015

104 views

Category:

Documents


7 download

TRANSCRIPT

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    1/31

    Programacin con ADO.NET en C#

    ##

    PRIMERA PARTE - RESUMEN DE EJERCICIOS

    A0

    Aplicaciones Windows FormsA1Creacin de tablas y columnasA2Clases derivadas de conjuntos de datosA3

    Definicin de conjuntos de datos con XSDA4

    Enlace de datos simpleA5

    Relaciones entre tablasA6

    Columnas basadas en expresionesA7PersistenciaA8Filtros y bsquedasA9Vistas de datos

    A10Enlace complejo a datos

    A11Actualizacin y versiones

    A12Eventos de actualizacin

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    2/31

    Programacin con ADO.NET en C# v

    When one door closes, another opens;

    but we often look so long and so regretfully upon the closed door

    that we do not see the one which has opened for us.

    Alexander Graham Bell

    ABA UNA VEZ UN MUNDO DENTROde los ordenadores en el que la mano derecha no saba loqu haca la mano izquierda. Dos aplicaciones, incluso si se ejecutaban dentro de una misma

    mquina, slo podan comunicarse entre s a travs de complicados protocolos asncronos. Estossistemas de seales eran tan primitivos, que para cada conversacin era necesario inventar todo unlenguaje. La aplicacin A conversaba en hotentote con el programa B, pero para interpelar al servi-cio C, deba usar el kickapoo, dialecto continental. Era la Torre de Babel, pero sin torre, porque enun entorno tan hostil se haca imposible edificar ms all de cierta altura.

    Sabios y chamanes comprendan cun desalentadora era la falta de comunicacin, aunque encontra-ban dificultades a la hora de explicar el problema a sus respectivas tribus. Poco a poco fueronideando sistemas de comunicacin ms potentes y a la vez ms fciles de usar. Surgieron nuevosprotocolos con extraos nombres, como OLE, CORBA, COM, MTS y Java Remoting, y un pro-

    ceso parecido a la seleccin natural comenz a moldear a los ms aptos, mientras que los menosafortunados eran devorados y digeridos por los supervivientes.

    Una vista panormica

    Aparte de lo que sugieren las siglas mencionadas en el idealizado cuento de hadas que he empezadoa relatar, puede usted reconocer a la plataforma .NET como protagonista de dicha historia? Quizssea una simplificacin sostener que los orgenes de .NET tienen que ver en exclusiva con la necesi-dad de disponer de un modelo de componentes potente y fcil de usar, pero hay un ncleo de ver-dad en ello. En todo caso, la mayora de los programadores nos hemos despertado un buen da enmedio del ajetreo de una ciudad en construccin. Mi primer contacto serio con la plataforma, porponer el ejemplo ms cercano, tuvo lugar a mediados de 2002, cuando Microsoft liber la primeraversin oficial de la misma. Es cierto que por entonces, utilizaba Delphi como herramienta princi-

    pal de programacin, pero en una situacin muy parecida se encuentran muchas personas fami-liarizadas con Visual Studio 6. Y es porque entre esa versin y la siguiente se produjo una verdaderarevolucin en la programacin para Windows.

    El objetivo de este curso es describir un sector pequeo pero esencial de la flamante megpolisredmontiana: las tcnicas de acceso a datos en la plataforma. Esto no slo incluye las clases de ac-ceso directo a SQL y las tcnicas de cach y edicin, sino tambin los conocimientos necesariospara el acceso remoto, la particin en capas fsicas de sistemas grandes y el uso de servicioscorporativos para garantizar la escalabilidad de nuestras aplicaciones.

    Organizacin del contenido

    El curso completo se ha dividido en tres partes. La primera parte est formada por tres series deejercicios, mientras que hay una sola serie para cada una de las otras dos partes. Este es el contenidoasignado a cada serie:

    Serie AConjuntos de datos y enlace a datos.

    Serie BAcceso directo a servidores SQL: la capa conectada.

    Serie CAdaptadores de datos.

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    3/31

    Introduccin

    Programacin con ADO.NET en C#vivi

    Serie DProgramacin en dos capas: un ejercicio prctico.

    Serie EProgramacin en tres capas: .NET Remoting y XML Web Services.

    Las tres primeras series se han organizando siguiendo el siguiente hilo argumental:

    ADO.NET ofrece la clase DataSet, que funciona como una pequea base de datos en memoria. Paralelamente, existe una interfaz muy sencilla para el acceso directo a servidores SQL.

    Es posible combinar las dos interfaces anteriores, con la ayuda de adaptadores de datos, para traerregistros desde el servidor SQL a la memoria de las estaciones clientes. Esta informacin puedeeditarse localmente para luego reenviarla al servidor SQL con la ayuda de los mismos adaptado-res de datos.

    Las otras dos series tienen una estructura muy diferente. Toda la serie D consiste en el desarrollo deuna misma aplicacin: un programa de facturacin muy simple, pero que muestra unas cuantastcnicas prcticas, como el uso de gestores de ventanas, de mens, el uso de reflexin para el descu-brimiento de tipos y el sistema bsico de impresin en .NET. Adems de este ejercicio, se incluye elcdigo fuente completo de una aplicacin paralela, esta vez desarrollada con los componentes deDeveloper Express para Windows Forms. Por supuesto, los distintos sistemas de gestin desarrolla-dos a lo largo de los ejercicios se adaptan para funcionar con estos componentes.

    La serie E, en cambio, combina ejercicios de presentacin de la teora con la aplicacin de lo apren-dido al proyecto desarrollado en la serie anterior.

    Requisitos para el seguimiento

    Los ejercicios de este curso han sido desarrollados con Visual C#Standard 2003, con el objetivo deque los requisitos para el seguimiento fuesen los mnimos. Necesitar instalar la versin 1.1 de.NET, y Visual C#Standard 2003, o Visual Studio 2003, en cualquiera de sus variantes, siempre quese asegure de instalar el soporte para C#.

    Como base de datos, he usado elMicrosoft Data Engine2000 (MSDE): una versin reducida del mo-

    tor de bases de datos utilizado por SQL Server 2000. Esto se debe a que Visual C#

    Standard slopuede acceder a bases de datos ubicadas en una instancia local del MSDE. El mayor problema delMSDE 2000 es que carece de herramientas grficas de administracin. Si debe usar Visual C #, envez de Visual Studio, una solucin aceptable consiste en instalar primero el MSDE en la mquina dedesarrollo, y luego instalar las herramientas clientes de la versin completa de SQL Server. Existeuna edicin de SQL Server 2000, la llamada SQL Server Developer, que se puede conseguir por unprecio muy ajustado, en torno a los 50 euros. Si va a usar Visual Studio, puede usar la versin com-pleta de SQL Server, sin importar si la instancia es local o remota.

    Las tres primeras series del curso utilizan la base de datos de ejemplos Northwind, que viene conSQL Server. Las dos series restantes utilizan una base de datos propia incluida con los ejercicios.

    He intentado incluir toda la teora necesaria para resolver cada ejercicio. No obstante, es aconsejabletener a mano algn libro sobre ADO.NET y s, claro, le recomiendo que ste sea La Cara

    Oculta de C#

    .

    Convenios

    A pesar de que cada ao nuestros ordenadores son ms rpidos y baratos, la impresin de librossigue siendo cara: es raro ver un libro tcnico impreso en colores. Nos hemos acostumbrado a leeren blanco, negro y gris y puede que ahora le extrae el que haya usado colores sin complejo al-guno a lo ancho y largo de este manual. Me siento justificado: no lo he hecho por el dudoso efectoesttico, sino para mejorar la legibilidad dentro de lo posible.

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    4/31

    Introduccin

    Programacin con ADO.NET en C# viivii

    Este pequeo fragmento de cdigo muestra algunas de las convenciones que he utilizado:

    public classTr i angul ar : Chi p, I Osci l ador , I Conf i gurabl e{

    public double Vol t aj e( double t i empo){

    // Implementacin de la onda triangular

    }

    }

    Al igual que ocurre en el nuevo editor de cdigo de Visual Studio 2005, he resaltado en cian losidentificadores que corresponden a nombres de tipos, sin importar si se trata de una clase, unaestructura, una interfaz, un tipo enumerativo o delegado. Es un indicio til para lector porque nopuede deducirse siempre de la sintaxis. Por el contrario, he seguido marcando las palabras reserva-das mediante negritas, en vez de usar texto de color azul como en Visual Studio. En mi opinin, alresaltar de esta manera las palabras claves se facilita la identificacin de la estructura sintctica deltexto. Por ltimo, he usado itlicas en color verde para los comentarios. Podra haber usado el grispara comentarios, pero en las pruebas con impresoras monocromas he comprobado que el verde setraduce mejor, adems de ser tambin el color usado por Visual Studio 2005.

    Ver tambin, de cuando en cuando, nmeros en color gris situados fuera de los mrgenes, como elnmero que acompaa a este prrafo. Se trata de referencias a La Cara Oculta de C#, y represen-tan la pgina donde podr encontrar ms informacin sobre el tema que se est explicando.

    Agradecimientos

    Quiero agradecer, sobre todo, la fe y la paciencia de todas las personas que adquirieron la serie D deeste curso por adelantado. Aprovecho tambin para ofrecer mis ms sinceras disculpas por los re-trasos: todava tengo mucho que aprender y hay mucho tambin por escribir. De este cuento dehadas tecnolgico slo hemos visto una parte insignificante, aunque ya se puede predecir quedisfrutaremos de un final feliz.

    Ian Marteenswww.marteens.com

    Madrid, agosto de 2005

    999

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    5/31

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    6/31

    Programacin con ADO.NET en C# 1

    NTES DE PASAR A LOSejercicios, resumiremos algunas de las caractersticas de la plataforma.NET que nos sern necesarias ms adelante. No pretendo agotar el tema, como es lgico, y

    ms que profundizar en detalles, me interesa presentar informacin prctica.

    Qu es la plataforma .NET?

    Una parbola budista cuenta la historia de tres ciegos que queran saber qu era un elefante. Acudie-ron al palacio real y suplicaron al monarca que les permitiese palpar su elefante blanco. El rey, bu-dista devoto y compasivo, accedi, y un criado llev a los ciegos al estanque donde se baaba elpaquidermo. A una voz del sirviente, los ciegos se abalanzaron sobre el animal, agarrndolo pordistintos puntos de su inmensa anatoma:

    Por la gloria de mi madre! exclam el primero Un elefante es como una columna, pequeapero muy ancha! dijo, pues se haba aferrado a una de las patas.

    Mientes, bellaco! se enfad el segundo Es una serpiente peluda y se retuerce como undemonio! explic mientras intentaba que el elefante no se lo sacudiese de la trompa.

    Hmffff! se oy la voz apagada del tercero que alguien me saque de esta caverna malo-liente!

    Estoy convencido de haber contado esta historia en algn otro sitio, aunque creo que el final eradiferente. De todos modos, es una historia apropiada, porque la plataforma .NET puede presentartantas apariencias como el elefante del cuento, incluyendo la caverna maloliente.

    Por ejemplo, para un forofo de la programacin de sistemas, .NET es la versin 3.0 de COM. Y nole falta razn, al menos desde el punto de vista histrico. Al parecer, las primeras ideas sobre .NETsurgieron como parte del diseo de un sucesor para COM+. Qu es COM+? Una serie deprotocolos que permiten la colaboracin entre objetos desarrollados con diferentes lenguajes yherramientas, y que pueden residir en diferentes procesos o incluso mquinas. Qu es .NET, si loobservamos a travs de esta estrecha rendija? Ha adivinado: es lo mismo, pero mejor. Es por esouna irona que incluso la versin 2.0 de la plataforma no haya logrado sustituir completamente la

    funcionalidad de COM+, y que deba colaborar con COM+ para poder aprovechar los llamadosservicios corporativos, que estudiaremos en la ltima serie de este curso.

    Pero yo no soy forofo de la programacin de sistemas; al menos, no de la tribu de esta especie quepretende pasar a la fama copiando el funcionamiento de subsistemas del viejo UNIX. Me interesa.NET ms por su faceta de herramienta de desarrollo que por cualquier otra cosa.

    1

    Hay toda una familia de lenguajes que pueden utilizarse para desarrollar aplicaciones o compo-nentes. En realidad, tras esa familia concreta de lenguajes, hay un conjunto muy bien definidode reglas del juego que deben ser satisfechas por cualquier aspirante a ingresar en tal selectoclub.

    2

    Hay un sistema de soporte para la ejecucin suficientemente complejo para que lo dividamosen subsistemas. Tenemos, para empezar, un sistema que carga las aplicaciones y las prepara parasu ejecucin. Tradicionalmente, esta ha sido una responsabilidad del sistema operativo y,efectivamente, Windows ha necesitado algunos retoques para satisfacer las exigencias de cargade las aplicaciones .NET.

    3 Las aplicaciones .NET no slo necesitan una tutela especial durante la carga, sino incluso du-rante la ejecucin. Estas aplicaciones utilizan, por ejemplo, un recolector de basura para la ges-tin de memoria, y en el caso tpico, es necesario traducir el cdigo intermedio que generan loscompiladores a cdigo nativo ejecutable, a medida que la ejecucin vaya activando una u otraruta dentro de la aplicacin. Hay tipos de datos cuya implementacin se sintetiza en tiempo deejecucin: los tipos delegados, que se utilizan en la implementacin de eventos y de funcionesde respuesta, y los tipos genricos en la versin 2.0 de la plataforma.

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    7/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C#22

    4 Por ltimo, estn las numerosas bibliotecas de clases necesarias para ejecutar hasta la ms sim-

    ple tarea.

    Ahora busque un libro sobre sistemas y vea cmo el autor define qu es un sistema operativo. Separece mucho a la lista anterior, verdad? Esto ha llevado a que algunos sostengan lo siguiente:

    .NET es el nuevo sistema operativo de Microsoft

    Se trata de una exageracin, por descontado. Por mencionar slo un argumento: hay muchas reasde las versiones actuales de Windows que no se adecuan naturalmente al estado actual de la plata-forma. Muchos pensarn inmediatamente en los controladores de dispositivos, pero puede agregarel subsistema COM+ a esta lista. No obstante, esta idea de .NET como sistema operativo virtual noes desatinada, y Microsoft ya ha dado pasos importantes hacia esta meta, de momento lejana.

    Por qu .NET y no Java?

    Ha llegado el momento de romper corazones y herir almas sensibles. Si conoce algo sobre Java,aunque sea de odas, habr notado las similitudes entre Java y .NET. Hay un lenguaje intermedio,hay un traductor a cdigo nativo, hay un intento de portabilidad Por qu un individuo como yo,que reniega de Java como aficin personal, se muestra tan entusiasmado con algo que parece unaimitacin? Puedo resumir mis razones:

    .NET es Java, pero bien diseado y mejor implementado

    .NET ha tenido la posibilidad de aprender de los errores en el diseo de Java, y doy fe de que se haaprovechado esta oportunidad. Para demostrarlo, habra que efectuar una comparacin rea porrea y muy bien detallada, pero puedo adelantarle algunos puntos:

    Entorno de ejecucin: el Common Language Runtimede .NET ha sido, desde sus primeras versio-nes, ms eficiente y funcionalmente completo que la Java Virtual Machine. Est fresca an laenconada discusin sobre las bondades de aadir un mecanismo de tipos delegados a este tipode mquinas virtuales. En la JVM no hay soporte para tcnicas tan tiles como los tiposenumerados o el traspaso de parmetros por referencia. Esto se paga en velocidad de ejecuciny en menor productividad, al tener el programador que tratar con un lenguaje menos expresivo.

    Otra manifestacin de lo mismo: para no desvirtuar la universalidad de los metadatos entiempo de ejecucin, el equipo de Microsoft que introdujo los tipos genricos, liderado porDon Syme y Andrew Kennedy, ide una implementacin que respeta toda la informacin sobretipos genricos, parmetros e instancias en tiempo de ejecucin. La alternativa propuesta paraJava est basada en trucos de compilacin. Resultado? Tanto la JVM de Java como el CLR de.NET deben ofrecer aplicaciones verificables. Los tipos genricos de .NET son verificables yeficientes. Para que las instancias de tipos genricos en Java sigan siendo verificables, elcompilador debe aadir verificaciones de tipo en tiempo de ejecucin que tienen un alto costeasociado.

    El propio concepto de cdigo intermedio es muy diferente. El bytecode de Java muchas vecestermina por ser interpretado. El cdigo IL de .NET nunca se interpreta, sino que siempre setransforma en eficiente cdigo nativo. Java presenta una paradoja: su popularidad inicial se de-bi precisamente a la presunta portabilidad de su bytecodey las posibilidades que se abran res-

    pecto a la creacin de appletspara Internet. Sin embargo, los problemas con las interfaces grfi-cas terminaron por arrinconar el uso universal de applets, y Java ha encontrado su nicho ecol-gico en la programacin para servidores justo donde es ms crtica la velocidad de ejecuciny respuesta.

    Interfaces grficas: quin no se ha visto involucrado alguna vez en las tragedias javanesasrelacionadas con AWT, Swing y el resto de los engendros visuales? Es cierto que WindowsForms en .NET v1.1 no es gran cosa, pero ha bastado una versin ms para que la mejora seams que notable. Adems, podamos criticar el primer Windows Forms por su fealdad o por la

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    8/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C# 33

    falta de alguna funcionalidad pero jams por su ineficiencia o por estar repleta de bugs detodo tipo.

    Interfaz de acceso a datos: las interfaces oficiales de acceso a datos en Java son de muy bajonivel, en comparacin con .NET. Entre los programadores que usan Java es comn una extraaadoracin por las implementaciones manuales de sistemas de persistencia, especialmente aque-llos que se desarrollan en solitario y partiendo siempre de cero absoluto. DataSet se traduce

    como abominacin y la sola idea del data bindingprovoca espasmos epilpticos incluso a losjvicos ms curtidos e insensibles.

    La lista podra alargarse indefinidamente, pero voy a mencionar slo otro punto de comparacin:los llamados servicios corporativos. Estos sern tratados en la serie E de este curso, y sirven como so-porte para aplicaciones divididas en capas que tienen que atender un nmero suficientementegrande de peticiones concurrentes. Cualquier versin de Windows, a partir de Windows 2000, vienede serie con soporte integrado para estos servicios, como parte de la funcionalidad de COM+. Elequivalente en Java se conoce como J2EE y es uno de los motivos por los que un servidor Linuxpuede terminar costando ms que un servidor Windows, porque las implementaciones de estosservicios para Java suelen pertenecer a grandes empresas de software y costar un ojo de la cara.

    Por ltimo, es innegable que .NET cuenta con una ventaja abrumadora sobre Java:

    En .NET, el sistema operativo y el entorno de ejecucin colaboran estrechamenteEs injusto? Me parece que no pero en cualquier caso, la Informtica es mi profesin, no miaficin para el tiempo libre, y mi inters es poder llevar a cabo mi trabajo con la mayor calidad en elmenor tiempo posible. Me importa un pimiento quin me suministre esas herramientas. Puedoequivocarme o puedo acertar, pero si me equivoco, las consecuencias las voy a tener que pagar demi bolsillo. Por lo tanto, quiero ser yo, y no un maldito comisario poltico de la Unin Europea o unburcrata vitalicio federal, quien decida qu herramientas estoy obligado a usar. Reconozco que heescrito este prrafo con mucha rabia y mala sangre, pero es que detesto el intervencionismo estataly por experiencia s que nunca lleva a nada bueno. Le pido disculpas por el tono amargo, pero nohe podido evitarlo.

    Common Language Runtime

    Y ahora, al grano: veamos el mnimo de conceptos necesarios para empezar a trabajar con la plata-forma. Ya sabemos, y si no, se lo cuento ahora, que los compiladores .NET traducen el cdigofuente a un cdigo intermedio llamado bueno, cdigo intermedio, o IL. No hay una pasadaposterior de enlace, como veremos en la siguiente versin, sino que el resultado de esta compilacinya constituye directamente una aplicacin ejecutable o una biblioteca de clases, o parte de alguna deestas dos variantes.

    He dicho, sin embargo, que este cdigo intermedio jams se interpreta. Quin es, por consiguiente,el responsable de la traduccin a cdigo nativo, y cundo entra en escena? Hay dos alternativas:

    Compilacin sobre la marcha

    Sobre la marcha? Bueno, just in timeno significa eso exactamente, pero me da pereza levan-tarme e ir a por un diccionario. Cuando usted lea esto habrn pasado ya varios meses desde que

    lo escrib, pero si observa bien, todava sigue diciendo lo mismo, con lo cual puede hacer unaidea de cunta pereza me da

    Espero, de todos modos que la idea quede clara: Como parte del proceso de carga de la aplica-cin traducida a IL, uno de los componentes del sistema de carga realiza esta traduccin sobrela marcha, segn vaya siendo necesario. Inicialmente se traduce un pequeo fragmento; diga-mos, por concretar, que se traduce el mtodo Mainpor donde comienza la ejecucin del pro-grama. Si este mtodo contiene una llamada a otro mtodo MeDaLoMismo, la instruccin queejecuta ese mtodo se truca para que salte en realidad a una rutina artificial. Cul es el cdigode esa rutina artificial? Muy sencillo: se traduce el cdigo intermedio de esa rutina y se arreglan

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    9/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C#44

    las cosas para que una posible segunda llamada aMeDaLoMismosalte de cabeza al cdigo nativoreal y definitivo.

    Compilacin por adelantado

    Alternativamente, se puede compilar la aplicacin durante su instalacin. Antes de la instalacinno es recomendable hacerlo, porque el resultado de esta operacin depende en gran medida dela versin exacta del sistema operativo, del tipo de CPU, e incluso puede que de la memoria

    disponible. Este proceso se activa desde una aplicacin de lnea de comandos incluida en laplataforma y llamada ngen. Los detalles, tanto sintcticos como varan ligeramente con la versinde la plataforma. En la versin 2.0, por ejemplo, se puede diferir la traduccin para que seaejecutada en algn momento apropiado desde un servicio del ordenador.

    Adems de estos dos algoritmos bsicos de traduccin, hay que tener en cuenta las particularidadesdel equipo donde se ejecutar la aplicacin. Por ejemplo, el traductor para Windows CE tiene encuenta la poca memoria dinmica que es caracterstica de los dispositivos donde debe ejecutarse. Enestas circunstancias, el sistema operativo puede eliminar de la memoria dinmica la traduccin dedeterminadas rutinas (siempre las menos usadas) y es posible que haya que traducir a cdigo nativouna misma rutina ms de una vez.

    Imagino que, al llegar aqu, aquellos que todava no sientan mucho afecto por .NET, sonreirn pen-sando que han encontrado la panacea. Una dosis de ngena todo lo que compilen, y todas las pesadi-

    llas asociadas al cdigo intermedio se desvanecern. Cuidado! Puede que pasar todo a cdigo na-tivo no sea siempre una buena idea:

    Si la aplicacin funciona como servidor, ms temprano que tarde todo el cdigo intermediahabr sido traducido a cdigo nativo, y el factor traduccin deja de importar. Es una paradojaque sea preferible ejecutar ngensobre una aplicacin GUI, para las que se supone que la veloci-dad de procesamiento no es tan crtica, que ejecutarlo sobre un servidor, que suele ser el cuellode botella en muchos casos. Pero hay un candidato incluso mejor: las aplicaciones de lnea decomando, como el compilador que estoy desarrollando para el lenguaje Freya1. Es comprensi-ble: cada vez que se ejecuta el compilador, inmediatamente despus se descarga de la memoria,y en la prxima ejecucin es necesario rehacer todo el trabajo de traduccin. Por este motivo, elcompilador de Freya se traduce a cdigo nativo al ser instalado.

    Sorprendentemente, el compilador JIT en tiempo de ejecucin puede realizar mejor trabajo queel compilador ngen. Hay varios motivos para ello, y no todos son evidentes. En tiempo de ejecu-cin, por ejemplo, el traductor se puede hacer una idea mejor de las condiciones en las que seejecuta la aplicacin. Incluso puede jugar con la relocalizacin de bloques de cdigo paraminimizar la paginacin. Un factor menos evidente es que en tiempo de ejecucin ya se sabecules ensamblados necesita realmente la aplicacin. Esto permite realizar operaciones msagresivas de inlining, o expansin de cdigo en lnea.

    Ensamblados y mdulos

    .NET no ofrece nada similar al enlace esttico de cdigo de otras plataformas de desarrollo, inclu-yendo Windows en modo nativo. Tomemos como ejemplo una clase: digamos que se trata deComplex, para el manejo de nmeros complejos. En lenguaje tradicional, como C++, el programa-

    dor que crea esta clase la compila para obtener una biblioteca de clases. En Windows nativo, estabiblioteca sera un fichero con extensin lib. Si a continuacin, usted escribe dos programas quehace uso de esta clase, el cdigo nativo correspondiente a la misma se copia dentro de sus dosaplicaciones. Aunque esto no es malo, los verdaderos problemas comienzan cuando usted disea ycompila dos bibliotecas dinmicas, como las DLL de Windows nativo, que hacen uso de Complex.Cada biblioteca cargara con su propia copia de la clase, y si una aplicacin necesita usar ambasbibliotecas dinmicas, en el espacio del proceso ejecutable tendramos tambin dos copias indepen-

    1freyalang.blogspot.com

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    10/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C# 55

    dientes de la clase de nmeros complejos. Por supuesto, la solucin evidente consiste en alojar laclase Complex, desde el primer momento, en una tercera biblioteca dinmica.

    Los diseadores de la plataforma .NET cortaron por lo sano: cada proyecto que usted compilegenerar, o un fichero ejecutable, o una DLL. Quiere compartir cdigo entre proyectos? Cree unabiblioteca de clases, que siempre ser de tipo dinmico. Con esta decisin no perdemos nadasignificativo. Es cierto que el sistema operativo tendr un poco ms de trabajo durante la carga de

    las aplicaciones, pero las ventajas que obtenemos como compensacin son ms que suficientes.Existe, sin embargo, una mxima en Informtica que, medio en broma, medio en serio, suele sercierta:

    Todo avance en Informtica consiste en aadir otra capa de indireccin.

    En este caso, la capa de indireccin consiste en que el programador no trabaja directamente con losficheros fsicos, sino que utiliza identificadores simblicos para referirse a las bibliotecas de clases.Esto permite que varios ficheros fsicos puedan combinarse de forma lgica en una misma biblio-teca. A estos ficheros fsicos se les conoce como mdulos, y la unin de uno o ms de estos mdulosse llama ensamblado:

    Un mdulo slo puede pertenecer a un ensamblado. Debo tambin precisar que los ficherosejecutables tambin se consideran como un tipo especial de ensamblado. En realidad, esta es unaexplicacin muy simplificada. Estoy dejando deliberadamente fuera el sistema de versiones, la firmade ensamblados para su autentificacin, etc. Lo que ahora nos importa es aadir y gestionar referen-cias en un proyecto de Visual Studio.

    Adems de permitir la fragmentacin de un ensamblado grande en trozos fsicamente manejables,la principal utilidad de los mdulos, al menos de los mdulos compilados por usted y yo, es permitir

    que un ensamblado se cree a partir de proyectos desarrollados en lenguajes diferentes. Sin embargo,no es fcil trabajar con mdulos, si nos atenemos a las plantillas predefinidas por Visual Studio. Paracrear un mdulo hay que pasar un parmetro especial al compilado de lnea de comandos: comoVisual Studio no trae plantillas para mdulos, habra que indicar ese parmetro directamente en laconfiguracin del proyecto. Para unir varios mdulos en un ensamblado puede usarse tambin elcorrespondiente compilador de lnea de comandos.

    NOTA He mencionado la existencia de mdulos para explicar por qu hay ensamblados del sistema frag-

    mentados entre varios ficheros fsicos, y para no dejar espacios en blanco en la explicacin de losensamblados. No obstante, no volveremos a tratar con mdulos en este curso, al menos de formadirecta.

    Clases y espacios de nombres

    Qu contiene cada ensamblado en su interior? Lo principal: una lista de tipos de datos y sus imple-mentaciones, cuando procede. Hay tambin referencias a otros ensamblados que necesita para sufuncionamiento, y metadatos de todo tipo y nivel.

    Cada tipo de datos tiene un nombre que consiste por lo general en una lista de identificadoresseparados por puntos. El punto, en realidad, es un carcter ms dentro del nombre del tipo. De estamanera, tenemos tipos con nombres como:

    System.String

    System.Data.SqlClient.SqlDataAdapter

    Ensamblado Ensamblado

    Mdulo Mdulo Mdulo

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    11/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C#66

    Microsoft.CSharp.CSharpCodeProvider

    IntSight.Proteus.Stargate.Entity

    Ahora bien, la mayora de los lenguajes que soportan la plataforma interpretan este formato denombres segn un convenio recomendado por la plataforma; en realidad, no conozco lenguajealguno que no siga el convenio mencionado. Este consiste en identificar el ltimo identificador de lacadena como el nombre abreviado del tipo de datos. Los identificadores restantes se tratan como si

    fuesen nombres de espacios de nombres, o namespaces. Un espacio de nombre es simplemente uncontenedor lgico que puede albergar otros espacios de nombre anidados, o tipos de datos. Porejemplo, observe el siguiente nombre de clase:

    System.Data.SqlClient.SqlDataAdapter

    El nombre abreviado del tipo es SqlDataAdapter. El tipo se encuentra definido dentro de un espaciode nombres llamado SqlClient, definido dentro de Data, que finalmente se define dentro del espaciode nombres de primer nivel llamado System.

    El problema con este convenio es que no existe una entidad fsica que represente al espacio denombres. Esto, por regla general, es bueno: podemos definir clases dentro del espacio de nom-bres Systemen cualquier ensamblado. Eso mismo es, a la vez, un inconveniente. La nica forma desaber qu espacios de nombres se utilizan dentro de un ensamblado es buscar todas las clases

    definidas dentro del ensamblado, eliminar los nombres abreviados de tipos y eliminar luego losduplicados. Este mismo problema es el que encontramos al definir las referencias de un proyecto:es fcil confundir un nombre de ensamblado con un espacio de nombres. En definitiva, ambos sonlistas de identificadores separados por puntos.

    Cmo podemos saber qu contiene un ensamblado dado? Oficialmente, la plataforma ofrece unautilidad llamada ildasm, una aplicacin de interfaz grfica. Mi consejo, sin embargo, es que utiliceotra herramienta para estos propsitos: el excelente y sin par Reflector, de Lutz Roeder, una aplica-cin gratuita que puede descargarse desde la siguiente pgina:

    www. ai st o. com/ r oeder/ dot net

    En el momento en que escribo estas lneas, la versin ms reciente de Reflectores la 4.1.64.0, y fun-ciona tanto con la versin 2.0 de la plataforma como con las versiones anteriores. Aqu tiene unaimagen de esta aplicacin:

    El nodo superior del rbol corresponde al ensamblado System. Inmediatamente debajo aparece elmdulo correspondiente al fichero system.dll. El mdulo hace referencia a otros ensamblados, queno se muestran en la imagen, pero define una serie de clases que la aplicacin reparte entre loscorrespondientes espacios de nombres. Por ejemplo, vemos un espacio Microsoft.CSharp que con-tiene varios tipos privados, en color gris, y el tipo CSharpCodeProvider, que al parecer es pblico ypodemos usarlo en nuestras aplicaciones.

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    12/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C# 77

    El sistema de tipos comunes

    Para que todos los lenguajes soportados por .NET puedan comunicarse entre s, deben compartirun mismo sistema de tipos y un mismo modelo de objetos. El siguiente diagrama muestra los distin-tos tipos de objetos definidos por el Common Type System (CTS), que es el nombre del sistema detipos de .NET:

    Este es un sistema de tipos ms rico y expresivos que el soportado por Java. Este ltimo lenguajeslo incluira, de los tipos anteriores, esta lista reducida:

    1 Clases2 Tipos de interfaz3

    Tipos bsicos o atmicos

    Java intenta utilizar el concepto de clase para modelar absolutamente todo, lo cual es correcto desdeel punto de vista conceptual y un verdadero incordio desde el punto de vista prctico. En .NETtambin se considera que la clase es el concepto fundamental, pero se toleran ciertas mutaciones delconcepto para facilitar algunas tcnicas de programacin de uso frecuente.

    Tipos bsicos

    Antes de complicarnos demasiado la vida, veamos qu es un tipo bsico y cules de ellos nosofrece la plataforma. No es una definicin sencilla, entre otras cosas porque todos los lenguajesintentan disimular al mximo las posibles caractersticas especiales de estos tipos. Tomemos comoejemplo los enteros. Resulta que C#nos permite escribir expresiones como la siguiente:

    999. ToSt r i ng( )

    Claro, es una tontera escribir una expresin como la anterior aunque no tanto, si la funcin To-Stringincluye una cadena de formato:

    999. ToSt r i ng( "C" )

    Est seguro de que se trata de una expresin constante? En Espaa imprime una cantidad en eu-ros, claro Lo que importa es que, a medida que los lenguajes orientados a objetos progresan, escada vez ms difcil distinguir entre tipos bsicos y objetos. Esto es bueno para el programador,porque as debe recordar menos excepciones a las reglas, pero en el fondo se trata de un disfraz.Los objetos, ya sean instancias de clases o de estructuras, son tipos compuestos que, obviando larecursividad, deben definirse con la ayuda de tipos ms simples.

    A pesar de todo lo dicho, hay una forma inequvoca para diagnosticar si un tipo determinado sepuede considerar bsico: basta con mirar la documentacin del Common Language Runtime, y averi-

    Common TypeSystem

    Tiposabstractos

    Tiposconcretos

    interfaceinterfaceinterfaceinterface Tipos dereferencia

    Tipos de valor

    Tipos atmicos Tiposcompuestos

    enumenumenumenum Tipos bsicos structstructstructstruct

    classclassclassclass delegatedelegatedelegatedelegate

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    13/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C#88

    guar si el tipo dado es reconocido como tal por la mquina virtual de ejecucin. Por ejemplo, lamquina reconoce sin ms los tipos enteros de 32 bits. Aunque no se puede trabajar directamentecon enteros de 16 bits en la pila, existen operaciones para la conversin en las direcciones con losenteros de 32 bits. Hay otro indicio necesario, aunque no suficiente: todos los tipos bsicos son tiposde valor, como veremos ms adelante.

    C#asigna una palabra clave para cada uno de los tipos bsicos. Adems, estos tipos tienen un nom-

    bre completo, como cualquier tipo de datos normal del Common Type System. Estos son los tiposbsicos y sus nombres, tanto desde el punto de vista de C #como del CTS:

    C# CLR Significadobool System.Boolean Verdadero y falso, no es as?char System.Char Caracteres Unicode (16 bits cada uno!)sbyte System.SByte Enteros de 8 bits con signo.byte System.Byte Enteros de 8 bits sin signo.short System.Int16 Enteros de 16 bits con signo.ushort System.UInt16 Enteros de 16 bits sin signo.int System.Int32 Enteros de 32 bits con signo.uint System.UInt32 Enteros de 32 bits sin signo.long System.Int64 Enteros de 64 bits con signo.ulong System.UInt64 Enteros de 64 bits sin signo.float System.Single Valores reales representados en 4 bytes.

    double System.Double Valores reales representados en 8 bytes.

    Hay autores, y entre ellos hay alguno famoso, que aconsejan no usar los nombre de tipos abreviadosde C#. Aducen que as se facilita la conversin de cdigo entre lenguajes soportados por la plata-forma. De modo que, de hacer caso al consejo, para declarar una variable local de tipo enterotendramos que escribir lo siguiente:

    / / Syst em. I nt 32 i = 0;

    / /

    Se imagina un bucle for?

    / / for ( Syst em. I nt 32 i = 0; i < 10; i ++) {

    / /

    }/ /

    Me parece horrible. En primer lugar, porque no tengo ni la ms mnima intencin de programarcon Visual Basic.NET al menos, mientras pueda evitarlo. Es cierto que, en teora, C#y este len-guaje son funcionalmente equivalentes; en la prctica, C#va siempre por delante. Pero nadie mepaga para demostrar que soy un polglota de la programacin. En segundo lugar, el que yo escribainten mi cdigo fuente no afecta al modo en que un hipottico programador en Visual Basic veralas declaraciones de mi ensamblado, ya que Visual Studio siempre se ocupara de estos detalles su-cios.

    Hemos visto los tipos bsicos, pero no hay un tipo de datos para las cadenas de caracteres? Haylo,pero no es un tipo bsico, sino una clase especial. Y lo mismo sucede con el tipo que se sueleusar para representar dinero, pasta, parn, plata, guita2 o como quiera llamarlo. Lo notable res-

    pecto a estos dos seores es que tienen nombres especiales en C #:C# CLR Significadoobject System.Object La fuente de la vida! Al menos, tericamente.string System.String Cadenas de caracteresdecimal System.Decimal Valores decimales de alta precisin, con 128 bits de capacidad.

    2Slo las cosas muyimportantes tienen tantos nombres.

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    14/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C# 99

    He aadido el tipo objecta la tabla, porque se trata tambin de un tipo de clase con una palabrareservada a su disposicin. La existencia de esta palabra clave se debe al mayor protagonismo deeste tipo en las primeras versiones de la plataforma, en las que las operaciones de boxingy unboxingeran mucho ms importantes que ahora, en la versin 2.0, donde los tipos genricos las haceninnecesarias en la mayora de los casos.

    Finalmente, conviene presentar varios tipos relacionados con el acceso a datos:

    CLR SignificadoSystem.DateTime Fecha y hora.System.Guid Corresponde al tipo uniqueidentifierde SQL Server.System.DBNull Usado para representar valores nulos provenientes de una base de datos.

    Estos tipos no tienen nombre propio en C#, y slo los menciono porque los veremos con frecuen-cia en el curso. Sobre todo me interesa presentar la clase DBNull: cuando recuperamos el valor deuna columna que contiene un valor nulo, recibimos un valor de tipo DBNull. Para ser exactos,recibimos el nico valor que puede existir para esta clase. En su momento, veremos cmo averiguarsi un valor ledo con la ayuda de ADO.NET es nulo o no.

    Qu hay dentro de una clase

    En nuestro diagrama, las clases se clasifican como tipos concretos. Traduccin: podemos crearinstancias, es decir, objetos, a partir de una clase. Aclaremos que hay tambin clases marcadas apropsito como clases abstractas, pero en principio, estamos hablando de la capacidad de crearinstancias, y no de si se aprovecha o no en un caso dado. Los tipos abstractos, de los que solo tene-mos los tipos de interfaz en nuestro rbol, nuncapueden usarse para crear instancias.

    Adems, una clase es un tipo de referencia. Esto significa, en primer lugar, que una variable o campoperteneciente al tipo, almacena un puntero a una instancia del tipo, nunca directamente una de estasinstancias. Consecuencias? Unas cuantas, y entre ellas, stas:

    Hace falta una instruccin especial para crear instancias de estos tipos de referencia. Estaoperacin tiene un coste asociado. Por s mismo, es un coste pequeo, pero hay que aadirle elcoste de la posterior devolucin de la memoria, cuando el objeto ya no es necesario. Veremosluego cmo los tipos de estructuras pueden ayudar a evitar estos costes, en muchos casos.

    Dos variables diferentes pueden compartir un mismo objeto. Se puede modificar el estado deun mismo objetos por medio de variables, o campos, sin relacin aparente.

    Una clase es un tipo compuesto: sirve como contenedor y organizador para otras entidades defini-das en su interior. Las clases en .NET pueden contener estos tipos de declaraciones:

    Campos: variables declaradas dentro de la clase. Es costumbre prohibir el acceso directo a losmismos desde fuera del objeto.

    Mtodos: todo el cdigo ejecutable en un lenguaje orientado a objetos debe estar encerradodentro de mtodos, es decir, funciones definidas dentro de una clase. Normalmente, estos mto-dos actan sobre un objeto de la clase dentro de la cul han sido declarados. Para llamar uno deestos mtodos se debe indicar la instancia sobre la cul queremos aplicardicho mtodo; si noespecificamos tal instancia, se asume el uso de la instancia implcita del mtodo donde se realiza

    la llamada. Esto implica, por supuesto, que tanto el mtodo llamado como el mtodo que con-tiene la llamada pertenecen a la misma clase en un sentido relajado, porque hay que tener encuenta la herencia de clases. Lo siento, pero es as de complicado. Para terminar de liarle la vida,veremos dentro de nada que existen tambin mtodos y campos estticos, que obedecen a unconjunto de reglas ligeramente distintas.

    Constructores: parecen mtodos, porque contienen cdigo ejecutable, pero slo pueden usarsedentro de una expresin new, o usando una sintaxis especial, antes de que empiece a ejecutarseel cdigo de otro constructor. No es necesario advertir que los constructores construyeninstan-cias de objetos a partir de clases y bueno, de estructuras. Ah, y si tiene alguna experiencia conotros lenguajes orientados a objetos, sepa que C#soporta algo que se parece mucho a un des-

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    15/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C#1010

    tructor (incluso se llaman destructores!) pero que no se parecen en nada a un destructortradicional.

    Propiedades: campos con superpoderes. Simulan la lectura del valor de un campo por medio deuna funcin, y la escritura mediante otra. Esto permite aadir efectos secundarios a las lecturasy escrituras de miembros de la clase que aparentan ser campos, y es uno de los pilares de la pro-gramacin mediante componentes.

    Eventos: es el mecanismo preferido para el envo de notificaciones entre componentes. Unevento utiliza casi siempre un campo oculto para mantener una cadena de punteros a mtodos.Cuando la clase que define el evento lo considera apropiado, activa esa cadena de funcionesmediante el disparo del evento. Microsoft prefiere que se hable de la elevacin (raising) delevento pero da igual.

    Cuando declaramos un campo, lo normal es que se reserve memoria para ste en cada una de lasinstancias de la clase. Si le parece anormal la palabra normal para hablar de estos campos, le per-mito que tambin los llame campos de instancia. Podemos tambin usar el modificador staticen ladeclaracin de campos, propiedades, eventos, mtodos e incluso constructores. Por ejemplo:

    // Un campo de instancia

    public string nombre;

    // Un campo "esttico"

    public static string pr ef i j o;

    La particularidad de los campos estticos es que slo se reserve memoria para cada declaracin unavez por clase. Siguiendo las declaraciones anteriores, tendremos a nuestra disposicin un camponombre por cada instancia que creemos de la clase donde ha sido declarado. Sin embargo, slotendremos un campoprefijo, sin importar el nmero de instancias creadas. De hecho, tendremos uncampoprefijoincluso antes de que creemos instancia alguna!

    Un mtodo normal, quiero decir, de instancia, acta sobre el estado de los campos y propiedadesde una instancia que debemos suministrarle, ya sea de forma explcita o implcita. Cuando declara-mos un mtodo esttico, ste no tiene acceso a los campos de instancia, como era de esperar, sinosolamente a los campos estticos declarados dentro de la clase. Y tampoco necesitamos pasarle unainstancia al mtodo: nos basta con indicar, implcita o explcitamente, el nombre de la clase dondeha sido declarado el mtodo.

    Esto hace que podamos decir que, al declarar una clase con miembros estticos, es como siestuvisemos declarando dos clases normales, sin miembros estticos:

    Una de estas clases imaginarias slo contendra las declaraciones de instancias. La otra claseimaginaria implcita contendra todas las declaraciones que utilizan el modificar static, con lapeculiaridad de que de esta segunda clase imaginaria slo tendramos una instancia a nuestradisposicin, que siempre estara creada ms o menos. No es una metfora para ser tomada muyen serio, pero si el CLR no ofreciese soporte explcito para miembros estticos, un compilador deun lenguaje como C#podra simularlos mediante este truco de las dos clases, de forma oculta parael programador.

    Clase

    estado de instancias estado esttico

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    16/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C# 1111

    Herencia e interfaces

    Puede que el truco ms popular de la chistera de la Programacin Orientada a Objetos sea la heren-cia de clases. Cuando declaramos una clase e indicamos que desciende de otra, hacemos que nuestraclase herede todas las declaraciones de la clase ancestro, con la posibilidad de aadir nuevosmiembros y modificar algunos de los heredados. Se dice en estos casos que heredamos tanto laestructura como el comportamiento.

    En un momento dado, los tericos de la programacin pensaron que era deseable que una clasepudiese heredar de ms de una clase base. Pero en la prctica, los lenguajes que soportaban herenciamltiple, como el popular C++, demostraron que:

    Muchas de las tcnicas necesarias para evitar conflictos de nombres eran, o demasiado comple-jas, o demasiado limitantes.

    Como consecuencia, muchos programadores ni siquiera se aventuraban a usarla. Una buena parte de los osados cometa errores de difcil diagnstico. Era un verdadero dolor en las vrtebras implementar un compilador con soporte para herencia

    mltiple. Da la casualidad que el principal caso prctico en el que merece la pena utilizar herencia mlti-

    ple se puede resolver con otra tcnica que enseguida veremos.

    El misterioso caso tiene que ver con las llamadas clases abstractas. Una clase puede declarar que uno oms de sus mtodos es abstracto, para que sea implementado en alguna clase derivada. Esta situa-cin es relativamente frecuente cuando se disean jerarquas de herencia. Por ejemplo, para progra-mar un sintetizador de sonidos por software (estn de moda, por cierto), se puede partir de unaclase base llamada Oscilador, de la que derivaremos luego varias clases que proporcionen elcomportamiento de distintas formas de onda. En un diagrama, representaramos tal situacin deesta manera:

    El tringulo de la imagen no es cuestin esttica: se utiliza en UML para representar las relacionesde herencia. En cdigo, tendramos esto, si nos ahorramos detalles innecesarios:

    public abstract class Osci l ador{

    public abstract double Vol t aj e( double t i empo) ;

    // Otros miembros, no necesariamente abstractos

    }

    public classTr i angul ar

    { public override double Vol t aj e( double t i empo){

    // Implementacin de la onda triangular

    }

    // Otros miembros

    }

    Podemos llegar al extremo y declarar alguna que otra clase solamente con mtodos, propiedades yeventos abstractos; no tiene sentido hablar de campos abstractos, y .NET no soporta constructores

    Oscilador

    Triangular Cuadrada DientesSierra

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    17/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C#1212

    abstractos. El caso especial al que antes me refera consiste en declarar una clase que herede de unasola clase concreta y de una o ms clases abstractas. Qu hay de especial en este caso?

    La estructura fsica se hereda de la nica clase concreta. Esto simplifica mucho la implementa-cin de compiladores.

    Los conflictos y ambigedades, aunque no desaparecen del todo, se reducen al mnimo posible. Desde el punto de vista del sistema de tipos, la nueva clase sigue siendo compatible para la

    asignacin respecto a todas sus clases bases.

    Para evitar la herencia mltiple y seguir soportando este til caso especial, los lenguajes como Java yC#permiten el uso de tipos de interfaz. Estos tipos son muy similares a las clases, pero slo permitendeclaraciones de mtodos, propiedades y eventos. Y muy importante: para ninguno de estos miem-bros se puede suministrar una implementacin. Por ejemplo, en vez de declarar una clase abstractapara definir las habilidades de un oscilador digital, podramos declarar una interfaz:

    public interface I Osci l ador {

    double Vol t aj e( double t i empo) ;}

    Los tipos de interfaz se interpretan como especificacin de una funcionalidad determinada. Lainterfaz IOsciladores muy sencilla: describe elementos que pueden suministrar un voltaje que varacon el tiempo. Ahora tenemos que establecer las reglas que deben cumplir C#y la mayora de loslenguajes .NET:

    1 Toda clase debe heredarexactamente de una sola clase.2

    La excepcin: la clase System.Object; en C#, objecta secas.3

    Una clase puede omitir la clase base en su declaracin, y en tal caso se asume que desciende deSystem.Object.

    4 Por el contrario, una clase puede implementarcero o ms tipos de interfaz.

    He resaltado heredare implementarporque esa es la terminologa oficial. Implementarsignifica que unaclase menciona el tipo de interfaz en su declaracin, con lo cual se obliga a implementar los mto-dos, propiedades y eventos declarados en la interfaz:

    public classTr i angul ar : Chi p, I Osci l ador , I Conf i gurabl e

    {public double Vol t aj e( double t i empo){

    // Implementacin de la onda triangular

    }

    // Otros miembros

    }

    El primer tipo de la lista de herencia debe ser una clase. En este caso, me he inventado una clase a laque he llamado Chip, para mostrar que ahora tenemos ms libertad al elegir una clase base. Acontinuacin se menciona IOscilador, y efectivamente: la clase Triangular implementa su mtodoVoltaje. Observe que he mencionado otro tipo de interfaz, IConfigurable: esto podra indicar quenuestra clase puede leer y guardar su configuracin desde algn tipo de medio persistente, como unfichero XML, el registro de Windows o incluso una base de datos.

    Encapsulamiento y control de acceso

    Cada miembro declarado dentro de una clase o estructura en C# debe ir acompaado de unmodificador que indique su nivel de acceso: desde qu zonas de un proyecto puede ser utilizado dichomiembro. El objetivo de este control de acceso es ocultar la mayor cantidad de detalles de la vista delos potenciales usuarios de la clase. No se trata de esconder ideas o secretos tcnicos, sino desimplificar la forma de usar la clase y evitar dependencias innecesarias. En realidad, para un usuariocon los permisos necesarios no hay secretos dentro de un ensamblado .NET. Si esto fuese un pro-blema, debera utilizar tcnicas adicionales como el ofuscamiento del cdigo intermedio.

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    18/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C# 1313

    El modelo de control de acceso en C# est determinado en su mayor parte por la implementacindel CLR y ofrece cinco niveles. Tres de ellos tienen mucho en comn con el modelo de acceso delenguajes orientados a objetos clsicos como C++:

    publicLos miembros declarados publicpueden ser utilizados desde cualquier parte del proyecto, yasea en el mismo ensamblado donde se est declarando la clase, como desde un ensamblado

    diferente. private

    Por el contrario, los miembrosprivateslo pueden ser utilizados por la propia clase que los de-clara.

    protectedLos miembros protectedpueden ser utilizados por la propia clase que los declara, y adems,por cualquier clase que descienda de la clase original, no importa en qu ensamblado se encuen-tre.

    Hay otros dos niveles de acceso que tienen que ver con los ensamblados:

    internalUn miembro declarado internalslo puede ser utilizado por clases ubicadas dentro del mismoensamblado que la clase original. Es una versin menos estricta deprivate.

    protectedinternalUn miembro declarado protected internal puede ser utilizado desde cualquier clase ubicadadentro del mismo ensamblado. Fuera de ste, slo tendrn acceso al miembro las clases deriva-das de la clase original.

    Tenga presente que estos cinco niveles se refieren a miembros declarados dentro de una clase oestructura, incluyendo otros tipos anidados. En cambio, para los tipos declarados directamentedentro de un espacio de nombre, es decir, para aquellos tipos que no son tipos anidados, slo haydos niveles aplicables:

    internalEl tipo slo puede ser usado dentro del ensamblado.

    publicBarra libre!

    Se asume que todos los miembros declarados dentro de un tipo de interfaz son pblicos, por lo queno se debe usar un modificador de acceso en la declaracin de estos. Debe saber tambin que algu-nos miembros especiales son considerados automticamente como privados. En esta categora seencuentran los constructores de tipos, tambin llamados constructores estticos, los mtodos usados para laimplementacin explcita de tipos de interfaz y losfinalizadores(pgina 22).

    Delegados

    Me permite una pregunta tonta? Asumo que s, de modo que ah va: por qu llamamos variablesa

    las variables? Lo malo de hacer estas preguntas es que termina por contestarlas uno mismo. Lasllamamos variables porque pueden contener un valor que vara. Si es una variable entera, puede quecontenga un cero, un seiscientos sesenta y seis o un menos uno. Si es una variable lgica, slo puedecontener verdadero o falso. Gracias a este hecho tan elemental, querido Watson, podemos desarro-llar algoritmos que acten sobre un valor entero arbitrario, o sobre un valor lgico arbitrario, etc-tera.

    Podemos tener variables de funciones? Si fuese posible, podramos desarrollar algoritmos que actuasensobre una funcin arbitraria. Imagine, por ejemplo, un algoritmo que calcule la media de los valoresde una funcin real evaluada en una lista de puntos.

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    19/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C#1414

    Para concretar, suponga que tomamos la funcin raz cuadrada, y queremos promediar el resultadode esta funcin en una lista de puntos pasada como parmetro:

    public static double Medi aRai z( double[ ] punt os){

    // Asumiremos que el vector puntosno est vaco.double t otal = 0. 0;for ( int i = 0; i < punt os. Lengt h; i ++)

    t otal += Math. Sqrt ( punt os[ i ] ) ;

    return t ot al / punt os. Lengt h;}

    Y si queremos usar la funcin exponencial? Tendamos que modificar el bucle de esta forma:

    for ( int i = 0; i < punt os. Lengt h; i ++)t otal += Mat h. Exp( punt os[ i ] ) ;

    Viendo que se trata de modificaciones mnimas, por qu no programar la funcinMediade formatal que acepte cualquierfuncin real que le suministremos? En los dos ejemplos anteriores, he resal-tado en rojo la funcin utilizada. Para lograr nuestro propsito, tendramos que sustituir la llamada auna funcin concreta por una llamada a una funcin que puede variar. He aqu que necesitamosuna variable de funcin: una variable, o parmetro, que contenga una referencia a una funcin. Estclaro que no puede ser una funcin cualquiera: las funciones que debe aceptar dicha variable debenadmitir un parmetro de tipo real y retornar un valor tambin real. Necesitamos poder programar lo

    siguiente:public static double Medi aRai z( double[ ] punt os,

    TipoEspecialAunPorDeterminar funcion){

    double t otal = 0. 0;for ( int i = 0; i < punt os. Lengt h; i ++)

    t otal += funcion( punt os[ i ] ) ;return t ot al / punt os. Lengt h;

    }

    Parece convincente pero si le cuenta esta historia a su profesor de Java, ver como frunce el ceoy, como mnimo, le llama psicpata pervertido que nunca comprender la belleza de la OOP.

    NOTA A Microsoft, modificar la JVM para permitir estas cosas le cost un pleito de apa con Sun, que ade-

    ms perdi. Ya es triste que el J++ mutante fuese ms rpido y eficiente que el trilobites antedilu-

    viano de Jaime Gansito y compaa. Ms triste an, si cabe, es ver que quienes aplauden el vere-dicto de ese juicio son luego quienes se oponen ms radicalmente a las patentes de software. Habauna vez una hermosa dama llamada Coherencia, alabada por todos pero amada por nadie

    Me atar una mano a la espalda para mostrar dos formas de bordear el problema al estilo Java, aun-que usar C#La primera consiste en encapsular el algoritmo de la media dentro de una clase:

    public abstract class Pr omedi ador {

    protected abstract double Funci on( double val or ) ;

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    20/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C# 1515

    public double Cal cul ar( double[ ] punt os){

    double t otal = 0. 0;for ( int i = 0; i < punt os. Lengt h; i ++)

    t ot al += Funci on(punt os[ i ] ) ;return t ot al / punt os. Lengt h;

    }}

    Imagino que ya estar viendo el disparate. Cada vez que quiera usar el algoritmo con una nuevafuncin, tendr que crear una clase derivada:

    public class Promedi oRai z : Pr omedi ador{

    protected override double Funci on( double val or ){

    return Mat h. Sqr t (val or ) ;}

    }

    Una clase para poder usar una funcin! Le aseguro, adems, que esto hace ms lento el algoritmo,porque para evaluar la raz en cada punto se realiza primero una llamada virtual, y luego viene lallamada a la verdadera funcin. Para poder ejecutar el algoritmo, necesitaremos crear tambin unainstancia de la nueva clase:

    double[ ] punt os = new double[ ] { 0. 0, 1. 0, 2. 0 };Pr omedi ador pr om = new Promedi oRai z( ) ;Consol e. Wr i t eLi ne(prom. Cal cul ar ( punt os) ) ;

    En realidad, casi nadie seguira este camino de perdicin: un javans tomado al azar que posea unmnimo de sensatez usara un tipo de interfaz:

    public interface I Funci on{

    double Funci on( double val or ) ;}

    Podramos programar ahora una funcin similar a la presentada al iniciar la seccin, usando el tipode interfaz en el papel del TipoEspecialAunPorDeterminar:

    public static double Medi aRai z( double[ ] punt os, I Funci on f unci on){

    double t otal = 0. 0;for ( int i = 0; i < punt os. Lengt h; i ++)

    t otal += f unci on. Funci on( puntos[ i ] ) ;return t ot al / punt os. Lengt h;

    }

    Le parece interesante? Si responde que s, es que no se ha dado cuenta todava de que estamosrepitiendo casi al pie de la letra la tontera de la clase abstracta. Para que esto funcione, seguimosnecesitando una nueva clase para cada funcin que se nos ocurra promediar. Lo nico que ha cam-biado es que, donde antes haba herencia de clases, ahora tenemos la implementacin de un tipo deinterfaz:

    public class Promedi oRai z : I Funci on

    {public double Funci on( double val or){

    return Mat h. Sqr t (val or ) ;}

    }

    La forma de ejecutar el algoritmo tampoco ha cambiado mucho:

    double[ ] punt os = new double[ ] { 0. 0, 1. 0, 2. 0 };I Funci on r ai zCuadr ada = new Promedi oRai z( ) ;Consol e. Wr i t eLi ne(Medi aRai z( punt os, r ai zCuadr ada)) ;

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    21/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C#1616

    Listo para la solucin de verdad?

    public delegate double Funci on( double val or ) ;

    public static double Medi aRai z( double[ ] punt os, I Funci on f unci on){

    double t otal = 0. 0;for ( int i = 0; i < punt os. Lengt h; i ++)

    t otal += f unci on(puntos[ i ] ) ;return t ot al / punt os. Lengt h;

    }

    La primera lnea es una declaracin de tipo: declaramos un tipo Funcion que representa aquellasfunciones o mtodos que reciben un valor de doble precisin y devuelven un valor del mismo tipo.Veamos ahora cmo usar el algoritmo:

    double[ ] punt os = new double[ ] { 0. 0, 1. 0, 2. 0 };Consol e. Wr i t eLi ne(prom. Cal cul ar ( punt os, new Funci on( Math. Sqr t ) ) ) ;

    Puede que me est llamando tramposo. Por qu he omitido la variable temporal que s he utilizadocon las soluciones tipo Java? Quizs debera haber escrito esto:

    double[ ] punt os = new double[ ] { 0. 0, 1. 0, 2. 0 };Funci on r ai zCuadr ada = new Funci on( Mat h. Sqr t ) ;

    Consol e. Wr i t eLi ne(Medi aRai z( punt os, r ai zCuadr ada)) ;

    Pero es que en C#2.0 se puede usar una sintaxis abreviada:

    double[ ] punt os = new double[ ] { 0. 0, 1. 0, 2. 0 };Consol e. Wr i t eLi ne(prom. Cal cul ar ( punt os, Mat h. Sqr t ) ) ;

    No es la brevedad lo que ms me gusta de esta solucin: repase los ejemplos anteriores, para quevea que estas dos lneas son las que mejor se comprenden, las que mejor expresan el problema plan-teado y su solucin. El tipo Funcionnos permite declarar variables, campos y parmetros para repre-sentar las variables de funcinpor las que suspirbamos al principio. Y gracias a la nueva sintaxis de C #2.0, podemos usar el nombre de una funcin concreta, comoMath.Sqrt, como si se tratase de unaconstante de funcin! Compare:

    // A una variable entera le asignamos una constante entera

    int i = 0;

    // A una variable de funcin le asignamos una constante de funcin

    Funci on f = Mat h. Sqr t ;

    Observe que, en la segunda instruccin no se est pidiendo la ejecucin de la funcin que calcula laraz cuadrada. La diferencia es pequea y merece ser destacada:

    // A una variable real le asignamos el resultado de una funcin

    Funci on f = Mat h. Sqrt (3. 0) ;

    Es la ausencia de parntesis, a continuacin del nombre de la funcin, la que indica que queremosuna referencia a la funcin, no el resultado de su evaluacin.

    Cadenas de delegados

    He simplificado un poco las cosas en la explicacin anterior, de modo que los tipos delegados de.NET se pareciesen lo ms posible a los punteros a funciones de la programacin ms tradicional.Los punteros a funciones han estado en C desde siempre, y fueron aadidos a Pascal poco despusde su creacin. Era ms complicado aadir este recurso a Pascal principalmente por culpa de losprocedimientos anidados de este lenguaje, que ya de por s aaden complejidad a la implementacinde compiladores. La solucin ms popular ha sido permitir que estos punteros slo puedan hacerreferencia a funciones y procedimientos no anidados, tal como ocurri en Turbo Pascal 4.

    De todos modos, hay una pequea diferencia entre los punteros a funciones tradicionales y losdelegados: en un lenguaje orientado a objetos puro, los mtodos no existen separados de las clases,

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    22/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C# 1717

    como entidades independientes. Cuando guardamos una referencia a un mtodo en un delegado, eldiseador del lenguaje debe tomar una decisin: debe el delegado guardar tambin la referencia aun objeto en particular, o no? C++, que no es un lenguaje puro, opta por la va negativa. Loslenguajes .NET siguen la va contraria: un delegado, en realidad, almacena una referencia opcional aun objeto, adems de la referencia al mtodo en s. La referencia al objeto es opcional para que losdelegados se puedan usar tambin con mtodos estticos, que como sabemos, no necesitan unainstancia para ser ejecutados.

    Y hay ms complicaciones: los valores delegados pueden formar cadenas de referencias a distintosmtodos. El siguiente diagrama muestra, al fin, la estructura interna de una instancia de un tipodelegado y el mecanismo usado para formar las cadenas mencionadas:

    En primer lugar, y como sugiere el diagrama, los delegados son tipos de referencia: .NET los imple-menta como un tipo muy particular de clases. Ese es el motivo por el que haba que utilizar eloperador newen C#v1.0 para obtener un delegado:

    Funci on r ai zCuadr ada = new Funci on( Mat h. Sqr t ) ;

    Esto sigue siendo cierto en la versin 2.0, pero el compilador ahora puede aadir por su cuenta lallamada al constructor:

    Funci on r ai zCuadr ada = Mat h. Sqr t ;

    Se asume que todos los tipos delegados descienden de la clase especialMulticastDelegate, que a su vezderiva de Delegate, la cual desciende directamente de Object. Al parecer, Microsoft consider en algnmomento la posibilidad de ofrecer delegados simples y combinables, pero en la versin final slosobrevivieron los delegados combinables que ahora conocemos.

    El diagrama nos muestra tambin la existencia de tres campos ocultos dentro de una instancia dedelegado. El primero de ellos, bautizado _targeten la ilustracin, almacena una referencia a un ob-jeto; en el caso de que el delegado se refiera a un mtodo esttico, se guarda un puntero nulo eneste campo. El campo _methodPtr contiene una referencia al mtodo concreto al que el delegadoapunta. Sospecho que este valor debe interpretarse como una direccin dentro del segmento decdigo de la aplicacin. Finalmente, el campo _prevapunta a otro delegado del mismo tipo, y es eltruco que se utiliza para implementar cadenas de delegados.

    Qu sentido tiene combinar delegados en una cadena? Si se trata de funciones matemticas, comola raz cuadrada o la exponencial, no tiene ningn sentido. Si activamos el delegado, se ejecutarncada una de las funciones de la cadena, pero slo podremos usar el valor de retorno de la ltimafuncin que se ejecute. Algo muy diferente ocurre cuando trabajamos con mtodos que provocanefectos secundarios. Veamos un ejemplo sencillo:

    public delegate void Mensaj e( ) ;

    Este delegado se puede conectar a mtodos sin parmetros y sin valor de retorno. Definamos dosmtodos compatibles con este tipo. Para simplificar, usaremos mtodos estticos:

    public static void BuenosDi as( ){

    Consol e. Wr i t eLi ne(" Buenos d as") ;}

    _target

    _methodPtr

    _prev

    _target

    _methodPtr

    _prev

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    23/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C#1818

    public static void Adi os( ){

    Consol e. Wri t eLi ne( "Adi s");}

    Declaremos una variable y construyamos una cadena de delegados:

    Mensaj e cadena = new Mensaj e( BuenosDi as) + new Mensaj e( Adi os);

    Como ve, podemos utilizar el operador de adicin para componer cadenas de delegados. En elfondo, el operador ejecuta el mtodo esttico Combine de la clase Delegate. Ejecutemos ahora losmtodos de la cadena:

    cadena() ;

    Hemos usado la variable como si fuese el nombre de una funcin, y le hemos pasado los parme-tros necesarios. En nuestro caso, no hay parmetros, por supuesto.

    Eventos

    Por qu Microsoft se tom tantas molestias para permitir la combinacin de delegados en cade-nas? La respuesta es que podemos usar los tipos delegados para declarar eventosdentro de una clase.Ya he presentado los eventos cuando veamos qu tipo de miembros puede contener una declara-cin de clase. Muchos programadores confunden al principio los dos conceptos, el de evento y elde tipo delegado, pero basta con recordar un par de hechos para aclarar las ideas:

    Un delegado es un tipo de datos. Un evento es un tipo de miembro que es admitido por las clases, estructuras y tipos de interfaz.

    El evento se declara utilizando un tipo delegado.

    Antes dije tambin que los eventos servan para implementar notificaciones. En efecto: una clasecomo Button puede declarar un evento llamado Click. Los usuarios de la clase pueden enganchardelegados a la cadena de delegados que puede colgar de este evento. Este acto se interpreta comouna suscripcinal evento. Cuando la clase Buttondetecta que alguien ha pulsado el control, activa losmtodos enganchados a la cadena definida por Click.

    Un evento, en una primera aproximacin, se parece mucho a una propiedad de tipo delegadopero sera incorrecto. Para ver la diferencia, usaremos el siguiente tipo delegado, definido en System:

    public delegate void Event Handl er ( object sender, EventAr gs e ) ;

    No nos interesa ahora el papel de estos parmetros, pero debe saber que, aunque potencialmentepodramos declarar eventos con tipos arbitrarios de delegados, .NET establece el convenio de queun tipo delegado asociado a un evento debe tener siempre dos parmetros. El primero de ellos debeser siempre de tipo object, y el segundo debe pertenecer a la clase EventArgs, o a una clase derivadade la misma.

    Ahora declaremos una propiedad y un evento dentro de una clase, usando el tipoEventHandler:

    public class Cl ase01{private Event Handl er campo;

    public Event Handl er Pr opi edad{

    get { return campo; }set { campo = value; }

    }

    public event Event Handl er Event o;}

    La primera diferencia es que una propiedad exige una implementacin, mientras que slo declara-mos el evento y dejamos que el compilador proporcione una implementacin. Esta no es una

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    24/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C# 1919

    diferencia fundamental, sin embargo; entre otras razones porque podemos darle una implementa-cin explcita al evento. La diferencia realmente importante se manifiesta durante el uso de lapropiedad y el evento. Para concretar, suponga que estamos dentro de una segunda clase:

    public class Cl ase02{private void Manej ador Compati bl e( object sender, EventAr gs e){

    Syst em. Consol e. Wr i t eLi ne( "yoo- hoo! ") ;}

    public void Pr ueba( Cl ase01 cl s01){

    // Usemos la propiedad

    cl s01. Propi edad = new Event Handl er ( Manej adorCompat i bl e) ;// Usemos el evento

    cl s01. Event o += new Event Handl er ( Manej adorCompat i bl e) ;// Esto produce un error de compilacin!cl s01. Event o = new Event Handl er ( Manej adorCompat i bl e) ;

    }}

    Podemos asignar un valor a una propiedad, siempre que sta permita escrituras. Pero no podemosasignar directamente un valor a un evento. No obstante, parece que podemos aadir, con el opera-dor de asignacin y suma, y le aseguro que tambin podemos quitar de un evento, con el imagina-ble operador compuesto de asignacin y resta:

    // Sera tambin correcto!

    cl s01. Event o -= new Event Handl er ( Manej adorCompat i bl e) ;

    La clave est en las cadenas de delegados. Cuando exponemos una propiedad de tipo delegado,estamos permitiendo a que un usuario de la clase que la contiene aada manejadores o quitemanejadores de la cadena de delegados a cuyo inicio apunta la propiedad. Pero tambin nosarriesgamos a que un programador despistado asigne sin ms su propio manejador a la propiedad, yse cargue de este modo una hipottica cadena ya existente. Eso es precisamente lo que se evita aldeclarar un evento: el evento no puede ser asignado desde fuera de la clase donde se define, y slopodemos usar los dos operadores mencionados para su manipulacin.

    Estructuras

    Las estructuras (structs) son otra clara ventaja de .NET frente a Java. Mientras que las instancias declases siempre utilizan memoria dinmica, las instancias de estructuras residen normalmente en elsegmento de datos estticos, como campos estticos, o aplanadas dentro de la memoria reservadapara una instancia de clase, o directamente en la memoria de pila local de un mtodo.

    Para entender por qu necesitamos estructuras, considere lo que ocurre en una tpica aplicacin deinterfaz grfica: en la capa de software que est detrs de los controles, hay un uso intensivo de lasprimitivas de dibujo soportadas por el entorno de ejecucin. La inmensa mayora de estas funcionesnecesitarn puntos para funcionar. Podramos representar estos puntos mediante una clase, pero seimagina la cantidad de puntos de usar y tirar que necesitaramos cada vez que fuese necesario dibu-jar cualquier tontera? En un sistema con recoleccin automtica de basura, el algoritmo de recogida

    se estara activando cada dos por tres. Este razonamiento puede aplicarse a casi cualquier dominiode programacin: siempre habrn tipos sencillos como los puntos, de los que necesitaremoscantidades industriales, que se convertirn en una amenaza para el eficiente funcionamiento de lasaplicaciones. Donde Java se resigna a lo aparentemente inevitable, .NET ofrece los tipos deestructuras como solucin efectiva.

    Las ventajas de los tipos de estructuras se pagan mediante algunas restricciones que padecen. Porejemplo:

    No podemos definir un constructor sin parmetros para una estructura. Estamos obligados aconvivir con el constructor sin parmetros que sintetiza el sistema.

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    25/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C#2020

    Este constructor implcito, adems, inicializa con ceros todos los campos de la estructura. Su-ponga que definimos un tipo para representar vectores tridimensionales:

    public struct Vect or {

    private double x, y, z ;

    public double X { get { return x; } set { x = value; } }public double Y { get { return y; } set { y = value; } }public double Z { get { return z; } set { z = value; } }

    }

    El constructor implcito asignara cero a las tres componentes del vector.

    Los campos de una estructura no pueden tener una expresin de inicializacin.

    Esta es una consecuencia inmediata de la restriccin anterior. Si pudisemos adjuntar unaexpresin de inicializacin a un campo de una estructura, estaramos interfiriendo en el efectodel constructor implcito.

    Si definimos un constructor con parmetros, estamos obligados a inicializar todoslos campos dela estructura antes de abandonarlo. En particular, esto tambin se exige para poder llamarmtodos de la propia estructura dentro del cdigo del constructor.

    Esta regla existe para facilitar el trabajo del verificador de .NET. La siguiente declaracin con-tiene un error que es detectado por el compilador:

    // Esta estructura contiene errores de compilacin

    public struct Contador {

    private int val or ;

    public Contador ( int v){

    Li mpi ar( ) ; // Esta llamada genera un error de compilacinval or += v;

    }

    public void Li mpi ar( ){

    val or = 0;}

    }

    El conflicto est en el cdigo del constructor: la llamada a Limpiarse ejecuta antes de que haya-mos podido inicializar el campo valor. Es cierto que Limpiar se encarga de ello pero elcompilador no lo sabe, porque para verificar si se cumple la regla mencionada, slo examina elcdigo definido dentro del propio constructor.

    No se puede heredar de una estructura.

    Dada la implementacin actual del CLR, para soportar la herencia de estructuras habra quetrabajar con punteros a estructuras en varias operaciones, y eso complicara tanto la

    implementacin en s como la verificacin del cdigo.

    NOTA Eiffel ofrece un concepto ms elegante para la declaracin de tipos con semntica de valor: los tipos

    incrustados, o embedded types. Sospecho que la CLR complicar la implementacin de este modelo,aunque no puedo jurarlo sin volver a echar un vistazo a la especificacin de Eiffel.

    Para terminar con las estructuras, aunque slo de momento, debo mencionarle la existencia de unaoperacin llamada boxing, y su inversa, unboxing; no me atrevo a traducirlas. El boxing consiste encrear una instancia en memoria dinmica para copiar en su interior un valor de una estructura, conla peculiaridad de que no se pierda la informacin del tipo de estructura original con la operacin.

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    26/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C# 2121

    El boxingocurre con frecuencia cuando asignamos una estructura a una variable o parmetro decla-rada de tipo object. Por ejemplo:

    object obj = new Poi nt (0, 0) ;

    El unboxingdeshace el hechizo sacando el conejo de la chistera. Despus de la asignacin anterior,podramos hacer esto:

    Poi nt pt = ( Poi nt )obj ;

    Como ve, esta ltima operacin es un caso particular de una vulgar conversin de tipo. Es en elboxingdonde reside toda la magia.

    Por qu demonios haba que inventar una historia tan retorcida como esto de meter estructuras encajitas para sacarlas despus? Por una parte, se trata de un requisito lgico que simplificaextraordinariamente el diseo e implementacin del lenguaje. Todos los tipos del Common Type Sys-tem, ya sean tipos de referencia o con semntica de asignacin por valor, se consideran derivadosdirectos o indirectos de la clase Object. Se dice, por ejemplo, que todos los tipos de estructuras des-ciende de la clase especial ValueType. La herencia implica la compatibilidad para la asignacin, y conel boxingtenemos la posibilidad de asignar cualquier tipo de valor a una variable de tipo object.

    Un segundo motivo: el tipo objectsustituye al tipo Variantque utilizaban lenguajes como Delphi y

    Visual Basic nativo. A primera vista, y tambin a segunda y tercera, el tipo variante parece unachapuza pero lo cierto es que simplifica mucho la programacin para bases de datos, y enparticular, la capa de acceso genrico sobre la que se pueden construir capas ms seguras desde elpunto de vista del sistema de tipos.

    Finalmente, estn los problemas planteados por las estructuras de datos, en especial, los contenedo-res: listas dinmicas, pilas, colas, etc. En la versin 2.0, los tipos genricos ofrecen la solucin mselegante, segura y eficiente, pero estos tipos no estaban disponibles en las versiones anteriores. Parapoder reutilizar una lista diseada para almacenar objetos, en general, era necesario poder conver-tir tipos con semntica de valor en referencias.

    Recogiendo la basura

    Una caracterstica comn a Java y .NET es la existencia de un recolector de basura (garbage collector),

    con el propsito de automatizar la liberacin de memoria. Los algoritmos bsicos de este tipo exis-ten desde hace muchsimo tiempo. En la dcada de los 80s se produjeron algunos avancesimportantes, como la tcnica llamadageneration scavenging, o barrido generacional, que mejoraron lostiempos de ejecucin del algoritmo y lo hicieron ms atractivo fuera de las reas especializadasdonde se utilizaba. A finales de los 80s y principios de los 90s, el lenguaje Eiffel populariz la idea.Se trataba de un lenguaje orientado a objetos muy completo y elegante que incorporaba el manejoautomtico de la memoria con un recolector de basura. Tanto Java como los lenguajes de la plata-forma .NET aprovechan las experiencias acumuladas en el diseo y uso de Eiffel.

    Para ser sinceros, siempre he sentido recelos hacia este tipo de algoritmos y sigo desconfiando.No obstante, es cierto que la recoleccin automtica de basura es una jugada obligada en el diseode .NET, y la justificacin principal es la necesidad de contar con tcnicas seguras y eficientes parael manejo de memoria en entornos distribuidos. Puede parecer extraa esta justificacin, pero es

    completamente cierta. De modo que hay que acostumbrarse a que la basura se evapore misteriosa-mente ante nuestras narices, aunque a algunos no nos entusiasme excesivamente la idea.

    Debo reconocer que la tcnica de recoleccin de basura tiene cierto regusto Zen. Puede incluso queal obispo Berkeley le hubiese agradado. La idea se resume as:

    Si nadie te ve, no existes

    O ms exactamente: si no existen referencias a cierto objeto desde un objeto vivo, el objeto encuestin est muerto, y su memoria puede ser liberada. De vez en cuando, se disparar un hilo deejecucin que se llevar todas estas almas muertas a Neverland o era al Walhalla? Como puede

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    27/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C#2222

    ver, todo se basa en definir qu es lo que est vivo y qu es lo que est muerto, y al parecer, ladefinicin es recursiva. De modo que pongmonos formales:

    1 Definamos un conjunto de objetos vivosiniciales, a los que llamaremos races.

    Todos los objetos a los que se pueda acceder a travs de un campo esttico de una clase, seconsideran races.

    En un momento dado, congelemos la pila de llamadas de la aplicacin junto con sus corres-pondientes zonas de variables locales. En ese momento, cualquier objeto apuntado desdecualquier variable local activa, se considera tambin una raz.

    2

    Tomemos todas las referencias a otros objetos desde un objeto vivo: todos esos objetosreferenciados estarn tambin vivos.

    Es eficiente la recoleccin de basura de .NET? Se nota cuando tiene lugar? No se preocupe: ya noestamos en los tiempos de los antiguos intrpretes de LISP y Prolog, y sobre todo, nuestrosordenadores no son ya los de aquella lejana poca. He estado trabajando mucho tiempo en eldesarrollo de un compilador de lnea de comandos para un lenguaje compatible con .NET. Durantela ejecucin del compilador se crean multitud de pequeos objetos estrechamente relacionadosentre s. La compilacin de un proyecto de unos pocos miles de lnea no necesita ni siquiera unsegundo, y la mayor parte de este tiempo se consume en leer informacin sobre los ensambladosque se van a usar como referencia. En una etapa posterior del proyecto intentaremos disminuir ese

    tiempo probando un par de tcnicas y optimizaciones.

    Pues bien, durante ese par de dcimas de segundos, el entorno de ejecucin puede llegar a activardos o tres veces la recoleccin de basura. Como entender, el tiempo de ejecucin de este algoritmono es notable, ni siquiera en este caso extremo.

    Finalizacin y destrucc in determinista

    No obstante, la recoleccin automtica de basura tiene un lado muy oscuro: nadie sabe cundo va atener lugar, y esto fastidia el uso de una de las tcnicas ms atractivas de la programacin orientadaa objetos. En palabras de Bjarne Stroustrup, el creador de C++:

    Object creation is resource allocation

    Traducido al romance: la creacin de objetos es equivalente a la reserva de recursos. O con mayorclaridad: podemos encapsular recursos dentro de clases, de modo que la creacin de una instanciade estas clases implique la obtencin de una instancia de estos recursos. En este contexto, re-curso significa cualquier objeto o entidad potencialmente costosa, que exija de nosotros una opera-cin explcita de peticin pareada con una operacin explcita de devolucin. Si cuesta, debemosdevolverlo, no? Dentro de esta categora entran entidades tales como las transacciones en un sis-tema de bases de datos, ficheros abiertos, semforos del sistema operativo, la aprobacin de uso deuno de estos semforos, la mayora de los objetos que se utilizan para dibujar en pantalla y la listapodra estirarse. Como curiosidad, observe que la mayora de estas entidades son en realidad instan-cias de objetos definidos en un nivel ms bajo del sistema.

    El problema nunca se presenta al pedir uno de estos recursos, sino a la hora de devolverlos. Sobretodo, porque debemos garantizar la devolucin de los mismos. Si no cerramos los ficheros que

    abrimos, podemos perder la capacidad de abrir ms ficheros. Si no terminamos correctamente lastransacciones que iniciamos, podemos perder los cambios que hayamos hecho en el contexto deestas, adems de que estaramos interfiriendo en el trabajo de los restantes usuarios de la base dedatos. Si seguimos los pasos de Stroustrup y asociamos la concesin de un recurso al estado de unainstancia, es normal que asociemos la devolucin del recurso a la destruccin de la instancia

    y es aqu donde empezamos a tirarnos de los pelos, porque en un sistema con recoleccinautomtica de basura no podemos predecir cundo tendr lugar la siguiente limpieza de la memoria:ser cuando el sistema lo estime oportuno. Puede que nunca. En cualquier caso, C# nos permiteescribir cdigo para que se ejecute cuando un objeto se convierta en basura y pase a mejor vida. Lasintaxis necesaria recuerda el uso de destructores en C++:

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    28/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C# 2323

    public class Cl aseConRecurso{

    private Recur so r ecurso;

    Cl aseConRecur so( ){

    // Este es el constructor

    }

    Cl aseConRecur so( ){

    // Parece un destructor, pero es un finalizador

    if (recurso != null)recurso.Li berar( ) ;

    }}

    No se apresure a sacar conclusiones a partir de este fragmento de cdigo; para empezar, hay quetener mucho cuidado con la clase Recurso. Si, por ejemplo, Recursofuese una clase CLR como File-Stream, sera incorrecto, e incluso peligroso, usar la finalizacin! Luego explicar por qu. De mo-mento, tenemos dos problemas con la finalizacin. Ya hemos mencionado el primero de ellos:nunca sabremos en qu momento se va a ejecutar. El segundo es casi tan grave: cuando el colectorde basura encuentra una instancia con cdigo de finalizacin, la mueve a una cola de finalizacin, y

    utiliza un hilo separado para ejecutar el cdigo de finalizacin de cada miembro de la cola. Estopuede llegar a ser muy costoso.

    A la vista de todas estas dificultades, muchos optan por no aplicar la mxima de Stroustrup, y utili-zar mtodos normales para reservar recursos y liberarlos posteriormente. Pero se trata de unacobarde rendicin: es muy fcil olvidar la llamada al mtodo que devuelve el recurso. En todo caso,hemos complicado las cosas aadiendo el sistema de recoleccin de basura para automatizar ladevolucin de uno de los recursos ms baratos: la memoria libre. Sin embargo, seguimos indefensosfrente al problema de la gestin automtica del resto de los tipos de recursos. Los demoniosaparentemente exorcizados vuelven a asomar sus feos rostros.

    No hay forma de evadirse de estos problemas. La plataforma .NET ofrece un remedio parcial: unpatrn de uso conocido como destruccin determinista. En vez de dejar que el autor de cada clasese invente un nombre diferente para el mtodo de liberacin, .NET nos propone que lo llamemos

    siempre Dispose. Ms an, nos aconseja que avisemos que nuestra clase tiene recursos que deben serliberados haciendo que la clase implemente el tipo de interfaz IDisposable:

    public interface I Di sposabl e{

    void Di spose( ) ;}

    De modo que si encontramos una clase que implementa IDisposable, sabremos con certeza total quedebemos garantizar la ejecucin de su mtodo Dispose. Ahora bien, incluso este requisito es dema-siado para algunos programadores. El patrn de uso de una clase con destruccin deterministadebera parecerse a esto:

    Cl aseConRecurso obj et o = new Cl aseConRecurso( ) ;try

    {// Aqu usamos la instancia creada

    }finally

    {I Di sposabl e d = obj et o as I Di sposabl e;if (d != null) d. Di spose( ) ;

    }

    La instruccin try/finallyvigila la generacin de excepciones; si se produce alguna mientras usa-mos la instancia, nos garantiza que se ejecute el cdigo incluido en la clusula finally. Por desgracia,hay muchos libros en los que el autor olvida esta simple regla de higiene. Estos pecados no reciben

  • 5/21/2018 Programacion con Ado.Net C#.pdf

    29/31

    Introduccin a la plataforma

    Programacin con ADO.NET en C#2424

    su merecido castigo de forma inmediata. Tan solo sucede que terminamos con una aplicacin pocorobusta entre manos, a la espera de que una pequeo fallo se amplifique hasta convertirse en unaverdadera catstrofe.

    Para ahorrarnos lneas de programa, mejorar la legibilidad y hacer evidentes nuestras intenciones,los diseadores de C#idearon la instruccin using:

    using ( Cl aseConRecurso obj et o = new Cl aseConRecurso( ) )

    {// Aqu usamos la instancia creada

    }

    Estas cuatro lneas hacen el mismo trabajo que las diez lneas originales. Para no complicarmedemasiado, he usado una instruccin new en la cabecera de la instruccin, pero es posible usarcualquier instruccin que devuelva un objeto perteneciente a una clase que soporte IDisposable:

    using ( Sql Dat aReader rd = sql Command. ExecuteReader ( ) )while (r d. Read( ) )

    Consol e. Wri t eLi ne( rd[0] ) ;

    Como puede ver en estos sencillos ejemplos, una de las ventajas adicionales de la instruccin usinges que hace coincidir el tiempo de vida del objeto asignado a la variable con el intervalo en el que laclase encapsula el recurso presuntamente vali