Documentos de Académico
Documentos de Profesional
Documentos de Cultura
fundamentales
de desarrollo de
software
Aspectos fundamentales
del desarrollo de software,
examen 98-361
Créditos
EDITOR Bryan Gambrel
DIRECTOR DE VENTAS Mitchell Beaton
DIRECTOR EJECUTIVO DE MARKETING Chris Ruel
GERENTE DE PRODUCTOS DE MICROSOFT Merrick Van Dongen de Microsoft Learning
ASISTENTE DE PROGRAMA EDITORIAL Jennifer Lartz
DIRECTORA DE CONTENIDO Micheline Frederick
EDITORA DE PRODUCCIÓN Amy Weintraub
DIRECTOR CREATIVO Harry Nolan
DISEÑO DE PORTADA Jim O’Shea
TECNOLOGÍA Y MEDIOS Tom Kulesa/Wendy Ashenberg
Foto de portada: © Pgiam/iStockphoto
Este libro lo realizó Aptara, Inc. usando Garamond y lo imprimió y encuadernó Bind Rite Robbinsville.
La portada la imprimió Bind Rite Robbinsville.
Copyright © 2012 por John Wiley & Sons, Inc. Todos los derechos reservados.
Ninguna parte de esta publicación puede ser reproducida, almacenada en sistemas de recuperación o transmitida en
cualquier forma o por cualquier medio, ya sea electrónico, mecánico, fotocopia, grabación, escaneo o de otro modo,
excepto según lo permitido bajo las Secciones 107 o 108 de la ley de Propiedad Intelectual de Estados Unidos de
1976, sin la autorización previa por escrito de la editorial, o la autorización a través del pago por ejemplar de la tarifa
correspondiente al Copyright Clearance Center, Inc. 222 Rosewood Drive, Danvers, MA 01923, sitio web www.
copyright.com. Las solicitudes de permiso a la editorial deberán dirigirse a Permissions Department, John Wiley &
Sons, Inc., 111 River Street, Hoboken, NJ 07030-5774, (201)748-6011, fax (201)748-6008, sitio web http://www.
wiley.com/go/permissions.
Microsoft, ActiveX, Excel, InfoPath, Microsoft Press, MSDN, OneNote, Outlook, PivotChart, PivotTable, PowerPoint,
SharePoint, SQL Server, Visio, Visual Basic, Visual C#, Visual Studio, Windows, Windows 7, Windows Mobile,
Windows Server y Windows Vista son marcas comerciales o marcas registradas de Microsoft Corporation en los
Estados Unidos y/u otros países. Otros nombres de productos y compañías mencionados aquí pueden ser marcas
comerciales de sus respectivos propietarios.
Los ejemplos de compañías, organizaciones, productos, nombres de dominio, direcciones de correo electrónico,
logotipos, personas, lugares y acontecimientos mencionados son ficticios. No se pretende ni se debe inferir de ningún
modo relación con ninguna empresa, organización, producto, nombre de dominio, dirección de correo electrónico,
logotipo, persona, lugar o acontecimientos reales.
El libro expresa puntos de vista y opiniones del autor. La información contenida en este libro se proporciona sin
ninguna garantía expresa, implícita ni estatuaria. Ni los autores, John Wiley & Sons, Inc., Microsoft Corporation, ni
sus revendedores o distribuidores serán responsables de cualquier daño causado o presuntamente causado directa o
indirectamente por este libro.
Fundada en 1807, John Wiley & Sons, Inc. ha sido una valiosa fuente de conocimientos y comprensión durante más de
200 años, ayudando a personas en todo el mundo a satisfacer sus necesidades y cumplir con sus aspiraciones. Nuestra
empresa está construida sobre una base de principios que incluyen la responsabilidad con las comunidades a las
que servimos y donde vivimos y trabajamos. En 2008, pusimos en marcha una iniciativa de ciudadanía empresarial,
Corporate Citizenship, un esfuerzo global para abordar los retos ambientales, sociales, económicos y éticos a los que
nos enfrentamos en nuestro negocio. Entre las cuestiones que abordamos se encuentra el impacto medioambiental
del carbono, las especificaciones del papel y su adquisición, la conducta ética de nuestro negocio y entre nuestros
proveedores y la comunidad, así como el apoyo solidario. Para obtener más información, visite nuestro sitio web:
www.wiley.com/go/citizenship.
ISBN 978-0-470-88911-4
Impreso en los Estados Unidos de América
10 9 8 7 6 5 4 3 2 1
www.wiley.com/college/microsoft o llame al número de teléfono gratuito de MOAC: 1 + (888) 764-7001 (solo EE. UU. y Canadá).
CONTRATO DE LICENCIA DEL USUARIO FINAL DE WILEY
PARA EL EBOOK DE MOAC Y EL CONTENIDO PARA EL INSTRUCTOR
Este es el Contrato de Licencia del Usuario Final limitado de John Wiley and Sons, Inc. (“Wiley”), que rige
el uso que hace del eBook de Microsoft Official Academic Course (“eBook de MOAC”) y del contenido
relacionado (“Contenido para el Instructor”) de Wiley. Al acceder, descargar o utilizar el eBook de
MOAC O EL CONTENIDO PARA EL INSTRUCTOR, usted acepta los términos y condiciones de
este Contrato. Si no los acepta, no acceda, descargue ni utilice el eBook de MOAC NI EL
CONTENIDO PARA EL INSTRUCTOR.
Licencia:
Por medio de este documento, Wiley concede al miembro, instructor o estudiante del Programa Microsoft IT
Academy (“usted”) derechos que puede ejercer en virtud de este contrato, y usted acepta una licencia no
exclusiva y no transferible para utilizar el eBook de MOAC y el Contenido para el Instructor solo según los
siguientes términos y condiciones:
a. Usted reconoce que los eBooks de MOAC y el Contenido para el Instructor se le licencian por
un periodo breve y que el uso que haga de estos está sujeto a los términos y condiciones de
este contrato.
b. Los siguientes son dos conjuntos independientes de derechos de uso. Solo uno de estos conjuntos se
aplica a su caso.
i. Si usted es un miembro activo del Programa Microsoft IT Academy:
1. Los eBooks de MOAC son solo para el uso de los instructores y estudiantes.
2. Solo puede descargar la cantidad de copias del título del eBook de MOAC aplicable
necesarias para los instructores que imparten la clase correspondiente a dicho título
y para los estudiantes que asisten a la misma.
3. Solo puede distribuir los títulos del eBook de MOAC a los instructores que imparten
una de las clases correspondientes a dicho título y a los estudiantes que asisten a la
misma, a través de:
o correo electrónico;
o un dispositivo USB seguro conectado directamente a los dispositivos personales
de los estudiantes;
o un sitio web protegido con contraseña al que solo tengan acceso los
instructores y estudiantes.
4. Solo puede distribuir el Contenido para el Instructor a los instructores, con fines de
preparación y enseñanza de una de las clases correspondientes al título del eBook
de MOAC asociado.
5. Antes de proporcionar acceso de cualquier tipo a un eBook de MOAC, se le notificará
a cada persona que solo puede acceder o utilizar un eBook de MOAC si acepta hacer
uso de este en cumplimiento con los siguientes criterios:
o Solo se utilizará el eBook de MOAC para fines personales de entrenamiento.
o Solo se instalará el eBook de MOAC en un dispositivo que sea de propiedad
de la persona o que esté bajo el control de esta.
o No se copiará, modificará, imprimirá, transmitirá, publicará, mostrará, vinculará,
reenviará ni distribuirá el eBook de MOAC, ni total ni parcialmente.
o Solo se podrá utilizar el título del eBook de MOAC mientras dure la clase en
la que la persona está participando, es decir, mientras se enseñe el título del
eBook de MOAC o por un periodo de ciento ochenta (180) días, lo que sea
mayor. Después de esto, se deben eliminar de forma segura todas las copias
del título del eBook de MOAC que la persona posea o que estén bajo su control.
o El uso que se haga de los títulos del eBook de MOAC también cumplirá con
todos los términos, condiciones o licencias adicionales que se apliquen, que
acompañen o que se incluyan en el eBook de MOAC.
6. Antes de proporcionar acceso de cualquier tipo al Contenido para el Instructor, se le notificará a cada instructor
que solo puede acceder o utilizar el Contenido para el Instructor si acepta hacer uso de este en cumplimiento con
los siguientes criterios:
o Solo se utilizará el Contenido para el Instructor con fines de preparar y enseñar la sesión de entrenamiento.
o Solo se instalará el Contenido para el Instructor en un dispositivo que sea de propiedad del instructor o que
esté bajo el control de este.
o No se copiará, modificará, imprimirá, transmitirá, publicará, mostrará, vinculará, reenviará ni distribuirá el
Contenido para el Instructor, ni total ni parcialmente.
o Solo se podrá utilizar el Contenido para el Instructor mientras dure la clase en la que el instructor enseña
el título del eBook de MOAC relacionado o por un periodo de ciento ochenta (180) días, lo que sea
mayor. Después de esto, se deben eliminar de forma segura todas las copias del título del Contenido
para el Instructor que el instructor posea o que estén bajo su control.
o El uso que se haga del Contenido para el Instructor también cumplirá con todos los términos, condiciones o
licencias adicionales aplicables, que acompañen o que se incluyan en el Contenido para el Instructor.
e. LOS EBOOKS DE MOAC Y EL CONTENIDO PARA EL INSTRUCTOR SE LICENCIAN “TAL CUAL” Y “SEGÚN
DISPONIBILIDAD”, SIN GARANTÍAS DE NINGÚN TIPO.
f. Usted reconoce que todos los derechos (incluyendo, sin limitación, la propiedad intelectual, las patentes y los secretos empresariales)
en los eBook de MOAC y el Contenido para el Instructor son propiedad única y exclusiva de Wiley y sus licenciantes. La aceptación
de este contrato no lo convierte en propietario de los eBooks de MOAC ni del Contenido para el Instructor, sin embargo, sí le
concede una licencia limitada para utilizar el eBook de MOAC y el Contenido para el Instructor de acuerdo con las disposiciones
de este contrato. Usted acepta proteger el eBook de MOAC y el Contenido para el Instructor del uso, la carga, la descarga, la
reproducción o la distribución no autorizados. Además, acepta no traducir, descompilar, desensamblar ni realizar ingeniería inversa
de ninguno de los eBooks de MOAC ni del Contenido para el Instructor. Wiley se reserva todos los derechos que no se le concedan
expresamente en este contrato.
Prólogo del editor
La visión editorial de Wiley para la serie de cursos Microsoft Official Academic Course es
proporcionar a los alumnos e instructores las habilidades y los conocimientos necesarios para
usar la tecnología de Microsoft de forma eficaz en todos los aspectos de sus vidas personales
y profesionales. Para que los educadores y alumnos aprovechen al máximo las herramientas
de software de Microsoft y sean más productivos, se requiere una enseñanza de calidad. Por
tanto, nuestra misión es hacer que nuestros programas de enseñanza sean compañeros docentes
de confianza de por vida.
Para lograr esta misión, Wiley y Microsoft se han asociado y han desarrollado programas
educativos de la más alta calidad dirigidos a trabajadores de la información, profesionales de
TI y desarrolladores. Los materiales creados por esta asociación llevan el nombre comercial
“Microsoft Official Academic Course”, lo que asegura a instructores y alumnos por igual
que el contenido de estos libros de texto está totalmente respaldado por Microsoft y que
proporciona información e instrucción sobre los productos de Microsoft de la más alta
calidad. Los libros de texto de Microsoft Official Academic Course son, de alguna manera,
más “oficiales”: constituyen el material didáctico oficial para los miembros de Microsoft IT
Academy.
La serie de cursos Microsoft Official Academic Course se centra en el desarrollo laboral.
Estos programas están dirigidos a aquellos alumnos que buscan ingresar al mercado laboral,
cambiar de trabajo o embarcarse en nuevas carreras como trabajadores de la información,
profesionales de TI y desarrolladores. Los programas Microsoft Official Academic Course
atienden estas necesidades haciendo hincapié sobre escenarios con entornos de trabajo
auténticos con una gran cantidad de proyectos, ejercicios, casos prácticos y evaluaciones.
Los cursos de Microsoft Official Academic Course están asignados a la extensa investigación
y análisis de trabajo en tareas de Microsoft, la misma investigación y análisis que se usa para
desarrollar los exámenes de Microsoft Technology Associate (MTA) y Microsoft Certified
Information Technology Professional (MCITP). Los libros de texto se centran en competencias
reales de los puestos de trabajos reales. Mientras los alumnos trabajan en los proyectos
y ejercicios de los libros de texto, mejoran su nivel de conocimiento y su capacidad para
aplicar la última tecnología de Microsoft a las tareas diarias. Estos alumnos también obtienen
credenciales para crear un Currículum Vitae que sirva de ayuda a la hora de encontrar un
trabajo, mantener el trabajo actual o continuar con su educación.
El concepto de aprendizaje permanente es hoy una necesidad máxima. Los puestos de trabajo,
e incluso todas las categorías laborales, están cambiando con tanta rapidez que ninguno de
nosotros puede seguir siendo competitivo y productivo sin actualizar continuamente nuestras
habilidades y capacidades. Las ofertas de Microsoft Official Academic Course, y su enfoque
en la preparación de exámenes de certificación de Microsoft, proporcionan un medio para que
las personas adquieran y actualicen de forma eficaz sus habilidades y conocimientos. Wiley
apoya a los alumnos en este esfuerzo a través de la elaboración y distribución de estos cursos
como editor académico oficial de Microsoft.
Actualmente, las publicaciones educativas deben prestar atención a la hora de proporcionar
gran calidad de impresión y contenido electrónico sólido. Mediante la integración de los
productos Microsoft Official Academic Course, WileyPLUS y las certificaciones de Microsoft
estamos en mejores condiciones para poder ofrecer soluciones eficientes de aprendizaje a los
alumnos y profesores por igual.
Bonnie Lieberman
Director general y Vicepresidente Senior
www.wiley.com/college/microsoft o llame al número de teléfono gratuito de MOAC: 1 + (888) 764-7001 (solo EE. UU. y Canadá).
| v
Prefacio
www.wiley.com/college/microsoft o llame al número de teléfono gratuito de MOAC: 1 + (888) 764-7001 (solo EE. UU. y Canadá).
vi |
Recorrido por el libro ilustrado
n Características pedagógicas
El libro de texto MOAC de Aspectos fundamentales del desarrollo de software está diseñado
para cubrir todos los objetivos de aprendizaje del examen 98-361 de MTA, que se conoce
como su “lección matriz de conocimientos”. Los objetivos del examen Microsoft Technology
Associate (MTA) se destacan a lo largo del libro de texto. Muchas características pedagógicas
se han desarrollado de forma específica para el programa Microsoft Official Academic Course.
Mediante una extensa información sobre los procedimientos y conceptos técnicos integrados,
a lo largo del libro de texto se plantean desafíos para el alumno y el instructor por igual.
El recorrido por el libro ilustrado que aparece a continuación proporciona una guía de
características que contribuyen al plan pedagógico del programa Microsoft Official Academic
Course. La siguiente es una lista de las principales características de cada lección diseñada
para preparar a los alumnos para el éxito a medida que continúan con su educación en TI, con
los exámenes de certificación y en el entorno de trabajo:
• Cada lección comienza con una Matriz de conocimientos de la lección. Más que una
lista estándar de objetivos de aprendizaje, la matriz de conocimientos de la lección
relacionará cada conocimiento del software tratado en la lección con el objetivo del
examen específico.
• Los ejercicios paso a paso concisos y frecuentes enseñan a los alumnos características
nuevas y ofrecen la oportunidad de ponerlas en práctica. Los pasos numerados
proporcionan instrucciones paso a paso detalladas que sirven de ayuda para que los
alumnos adquieran conocimientos de software.
• Las ilustraciones (en particular, imágenes de la pantalla) proporcionan información
visual mientras los alumnos realizan los ejercicios. Estas imágenes refuerzan los
conceptos clave, proporcionan pistas visuales acerca de los pasos que se deben realizar y
permiten a los alumnos comprobar su progreso.
• Las listas de Términos clave que figuran al principio de cada lección presentan a los
alumnos el vocabulario técnico importante. Cuando se usan estos términos más adelante
en la lección, aparecen en fuente negrita y cursiva en el lugar donde se definen.
• Un atractivo punto de uso son las ayudas para el lector, que se encuentran a lo largo de
las lecciones e indican a los alumnos por qué un tema es importante (Conclusión) o les
proporcionan consejos útiles (Tome nota). Las ayudas para el lector también proporcionan
información adicional relevante o general que agrega valor a la lección.
• Las características Listo para certificación que aparecen por todo el texto señalan a
los alumnos dónde se cubre un objetivo específico de certificación. Proporcionan a los
estudiantes la oportunidad de comprobar el grado de comprensión sobre ese objetivo
MTA particular y, si fuera necesario, revisar la sección de la lección donde se trata.
MOAC ofrece una preparación completa para la certificación MTA.
• Preguntas al final de la lección: la sección Evaluación de conocimientos ofrece una
gran variedad de preguntas que pueden ser de varias opciones, verdadero o falso, de
relacionar o de rellenar espacios en blanco.
• Ejercicios del final de la lección: los escenarios posibles de Evaluación de competencias
y los escenarios posibles de Evaluación de aptitudes y los ejercicios de Preparación del
lugar de trabajo son proyectos que ponen a prueba la capacidad de los alumnos para
aplicar lo que han aprendido en la lección.
www.wiley.com/college/microsoft o llame al número de teléfono gratuito de MOAC: 1 + (888) 764-7001 (solo EE. UU. y Canadá).
| vii
viii | Recorrido por el libro ilustrado
■ Características de la lección
2 LECCIÓN
Introducción a
la programación
orientada a objetos
M AT R I Z D E C O N O C I M I E N T O S D E L A L E C C I Ó N Matriz de conocimientos
Conocimientos y conceptos Objetivo del examen MTA Número de objetivo del
examen MTA de la lección
Conceptos de los objetos Conceptos de los aspectos 2.1
fundamentales de las clases.
Conceptos de los valores Conceptos del almacenamiento y
y las referencias los tipos de datos de los equipos. 1.1
TÉRMINOS CLAVE
clase espacio de nombres objetos
eventos polimorfismo
Introducción a la programación | 3
clases abstractas
clases selladas
constructores
herencia
interfaces
propiedades
propiedades implementadas
automáticamente
Términos Por ejemplo, en la figura 1-1 se muestra un diagrama de flujo que toma dos números (entrada),
los compara y, a continuación, indica cuál es el mayor (salida).
clave
delegados método
modificador de acceso signatura
descriptores de acceso
números estáticos tipo de referencia
encapsulación
tipo de valor
32
Diagramas
Ayuda para el lector informativos
Referencia cruzada (XREF)
Introducción a la programación | 9
C# proporciona varios tipos de datos integrados que se pueden usar en los programas. También
X REF
se pueden definir tipos nuevos mediante una estructura de datos, como una clase o un struct.
Como puede observarse, el diagrama de flujo enumera en el orden correcto todos los pasos
Encontrará más Este capítulo se centra en algunos de los tipos de datos integrados que más se usan.
información sobre cómo
necesarios para realizar la operación. El flujo de control comienza con el símbolo de inicio y
En la tabla 1-3 se muestran varios tipos de datos integrados de uso frecuente que están termina con el símbolo de fin. Los símbolos del proceso y de entrada y salida siempre tienen
crear sus propios tipos disponibles en C#. Los tamaños indicados en la tabla se refieren a un equipo que ejecuta un
de datos en la lección 2. sistema operativo de 32 bits, como Windows 7 de 32 bits. Para un sistema operativo de 64 bits, un único punto de entrada y uno de salida. En cambio, el símbolo de decisión tiene una sola
como Windows 7 de 64 bits, estos tamaños serán diferentes. entrada pero varias salidas. Para probar un diagrama de flujo, realizamos un “simulacro”,
es decir, seguimos manualmente los pasos del diagrama de flujo con datos de prueba para
comprobar si se siguen las rutas apropiadas.
Tabla 1-3
Tipos de datos integrados Tipo de datos Tamaño Intervalo de valores
que se usan con frecuencia INTRODUCCIÓN A LAS TABLAS DE DECISIÓN
byte 1 byte de 0 a 255
en C# Cuando los algoritmos comprenden grandes cantidades de condiciones, las tablas de decisión
char 2 bytes de U+0000 a U+ffff (caracteres Unicode) presentan un formato más compacto y fácil de leer. La tabla 1-2 muestra una tabla de decisión
short 2 bytes −de 32 768 a 32 767 para calcular un descuento. Esta tabla genera un porcentaje de descuento en función de la
cantidad de producto comprado. Las líneas en negrita de la tabla de decisión la dividen en
int 4 bytes −de 2 147 483 648 a 2 147 483 647
cuatro cuadrantes. El primer cuadrante (parte superior izquierda) especifica las condiciones
long 8 bytes −de 9 223 372 036 854 775 808 a (“Cantidad < 10,” etc.). El segundo cuadrante (parte superior derecha) especifica las reglas.
9 223 372 036 854 775 807 Las reglas son las combinaciones posibles de los resultados de cada condición. El tercer
float 4 bytes de ±1,5 × 10-45 a ±3,4 × 1038 cuadrante (parte inferior izquierda) especifica la acción (“Descuento”, en este caso) y el último
double 8 bytes de ±5.0e−324 a ±1.7e308 cuadrante (parte inferior derecha) especifica los elementos de acción correspondiente a cada
regla.
TOME NOTA
* bool 2 bytes true o false
Las versiones sin signo
de short, int y long son string - Cero o más caracteres Unicode
ushort, uint y ulong,
respectivamente. Los
tipos sin signo tienen
el mismo tamaño que Todos los tipos de datos enumerados en el cuadro 1-3 son tipos de valor, excepto string, que es
sus versiones con un tipo de referencia. Las variables que se basan directamente en los tipos de valor contienen
signo, pero almacenan el valor. En el caso del tipo de referencia, la variable contiene la dirección de la ubicación de
un intervalo muy memoria donde se almacenan los datos en sí. Aprenderemos más sobre las diferencias entre los
superior de valores solo tipos de valor y los tipos de referencia en la lección 2.
positivos.
CONCEPTOS DE LAS MATRICES
Una matriz es una colección de elementos, a cada uno de los cuales se puede obtener
acceso mediante un índice único.
En C#, se suelen usar las matrices para representar colecciones de objetos de tipo similar. En
el código siguiente se muestra un ejemplo de declaración de matriz:
int[] numbers = { 1, 2, 3, 4, 5 };
Esta declaración crea una matriz identificada por los números de nombre. Puede almacenar
una colección de cinco números enteros. Esta declaración también inicializa cada uno de los
elementos de la matriz respectivamente mediante los números del 1 al 5.
A cualquier elemento de la matriz se puede obtener acceso directamente mediante un índice.
En .NET Framework, los índices de la matriz son de base cero. Esto significa que para obtener
acceso al primer elemento de una matriz se usa el índice 1; para obtener acceso al segundo
elemento, el índice 2 y así sucesivamente.
Para obtener acceso a un elemento individual de la matriz, se usa el nombre de la matriz
seguido por el índice entre corchetes. Por ejemplo, en la matriz que hemos declarado
anteriormente, numbers[0] devolverá el valor 1 y numbers[4] devolverá el valor 5. No es
válido obtener acceso a una matriz fuera de sus límites definidos. Por ejemplo, obtendremos
un error si intentamos obtener acceso al elemento numbers[5] de la matriz.
www.wiley.com/college/microsoft o llame al número de teléfono gratuito de MOAC: 1 + (888) 764-7001 (solo EE. UU. y Canadá).
Recorrido por el libro ilustrado | ix
44 | Lección 2
CONCLUSIÓN
Un tipo de valor almacena directamente un valor, mientras que un tipo de referencia solo
almacena una referencia al valor propiamente dicho. Ayuda para el lector
Un tipo de valor almacena datos directamente en su memoria. Por su parte, los tipos
de referencia, solo almacenan una referencia a una ubicación de memoria; es decir, los
Conclusión
verdaderos datos se almacenan en la ubicación de memoria a la que se hace referencia. La 4 | Lección 1
mayoría de los tipos de datos elementales integrados (tales como bool, int, char, double, etc.)
son tipos de valor. Los tipos de datos definidos por el usuario creados mediante la palabra
Tabla 1-2
clave struct son también tipos de valor. Los tipos de referencia son aquellos creados mediante
las palabras clave object, string, interface, delegate y class. Tabla de decisión para Cantidad < 10 S N N N
calcular descuentos
Conceptos de los structs Cantidad < 50 S S N N
Cantidad < 100 S S S N
La palabra clave struct se usa para crear tipos definidos por el usuario que consisten en
pequeños grupos de campos relacionados. Los structs son tipos de valor, a diferencia de Descuento 5% 10% 15% 20%
las clases, que son tipos de referencia.
Los structs se definen mediante el uso de la palabra clave struct, como se muestra a Para averiguar qué elemento de acción se debe aplicar, es preciso evaluar cada condición a
continuación: fin de encontrar la regla correspondiente y, a continuación, elegir la acción especificada en
la columna de esa regla. Por ejemplo, si el valor “Cantidad” de los datos de prueba es 75,
public struct Point entonces la primera regla se evalúa en “No”, la segunda regla se evalúa en “No” y la tercera
{ regla se evalúa en “Sí”. Por lo tanto, elegiremos el elemento de acción de la columna (N, N, S)
public double X, Y; que establece el descuento del 15 %.
}
Los structs pueden contener casi todos los elementos que pueden contener las clases, tales
como constructores, métodos, propiedades, etc. Sin embargo, como aprenderemos en la Introducción a C#
C# es un conocido lenguaje de alto nivel que permite escribir programas en un formato
legible. C# forma parte de .NET Framework y saca partido de la compatibilidad con el
tiempo de ejecución y las bibliotecas de clases que este entorno proporciona.
Como hemos explicado en la sección anterior, los equipos necesitan instrucciones precisas
y completas para llevar a cabo una tarea. Estos conjuntos de instrucciones se denominan
programas informáticos o, simplemente, programas .
AEn el nivel más básico, los equipos usan el sistema de números binario para representar
la información y el código. En este sistema, cada valor se representa mediante dos símbolos
únicamente, 0 y 1. Un programa escrito en el sistema de números binario se llama código
Conceptos generales del desarrollo de software | 77 binario.
Usar el código binario para programar un equipo resulta árido y sumamente difícil para
BubbleSort funciona mediante la comparación de dos elementos para comprobar si están cualquier tarea mínimamente compleja. Por lo tanto, para simplificar la programación, los
desordenados. En el caso de que lo estén, intercambia sus posiciones. El algoritmo repite la científicos e ingenieros informáticos han desarrollado varios niveles de abstracción entre los
equipos y sus operadores humanos. Estas abstracciones incluyen un software (por ejemplo,
operación hasta que toda la lista está en el orden deseado. BubbleSort recibe este nombre
los sistemas operativos, los compiladores y varios sistemas de tiempo de ejecución) que se
por su funcionamiento: a medida que el algoritmo progresa, los elementos de menor tamaño encargan de traducir un programa legible por el ser humano en un programa que la máquina
ascienden hacia la superficie como si fueran burbujas (bubble, en inglés). pueda interpretar.
Vamos a visualizar BubbleSort con la ayuda de un ejemplo. Supongamos que deseamos La mayoría de los programas modernos están escritos en un lenguaje de alto nivel como C#,
organizar todos los elementos de la lista siguiente en orden ascendente: (20, 30, 10, 40). Estos Visual Basic o Java. Estos lenguajes permiten escribir instrucciones precisas de forma legible
elementos deben organizarse de menor a mayor. El algoritmo BubbleSort intenta resolver el para el ser humano. Posteriormente, un compilador traduce el lenguaje de alto nivel en un
problema en una o varias pasadas; en cada una de ellas analiza la lista completa de elementos. lenguaje de nivel inferior que resulta comprensible al sistema de ejecución runtime.
Si el algoritmo encuentra elementos desordenados, los intercambia. El algoritmo finaliza
cuando analiza la lista completa sin intercambiar ningún elemento. Si no se han producido Cada lenguaje de programación ofrece su propio conjunto de terminología y gramática
intercambios, significa que ningún elemento estaba desordenado, de modo que la lista está (también denominado “sintaxis”). En este curso, aprenderemos a programar con el lenguaje de
ordenada de principio a fin. programación C# en el entorno .NET Framework. .NET Framework proporciona un entorno
de ejecución runtime para el programa C#. Asimismo, contiene las bibliotecas de clases
que proporcionan gran cantidad de funciones básicas reutilizables que se pueden incorporar
directamente a los programas escritos en C#.
Tabla 3-1
Primera pasada de
BubbleSort
Pasada Antes Después Comentarios Tablas de ✚ MÁS INFORMACIÓN
.NET Framework proporciona tres componentes principales: un entorno de ejecución runtime, un conjunto
fácil lectura
1 20, 30, 10, 40 20, 30, 10, 40 El algoritmo compara los dos primeros de bibliotecas de clases que proporcionan muchas funciones reutilizables y compiladores de lenguaje para C#,
elementos (20 y 30); dado que están Visual Basic y Managed C++. .NET Framework admite muchos lenguajes de programación y también la adición de
lenguajes adicionales al sistema. Aunque la sintaxis y la terminología de cada lenguaje varían, todos pueden usar
en el orden correcto, no es necesario
las bibliotecas de clases base proporcionadas por .NET Framework.
intercambiarlos.
2 20, 30, 10, 40 20, 10, 30, 40 El algoritmo compara los dos
elementos siguientes (30 y 10);
puesto que están desordenados, se
intercambian.
3 20, 10, 30, 40 20, 10, 30, 40 El algoritmo compara los dos
elementos siguientes (30 y 40); como
Ayuda para
están en el orden correcto, no es
necesario intercambiarlos. el lector Más
Como se muestra en la tabla 3-1, al final del primer paso, BubbleSort ha realizado un
información
intercambio y existe la posibilidad de que los elementos sigan sin estar totalmente ordenados.
Por lo tanto, BubbleSort da otra pasada a la lista, como se muestra en la tabla 3-2.
Tabla 3-2
Segunda pasada de Pasada Antes Después Comentarios
BubbleSort
1 20, 10, 30, 40 10, 20, 30, 40 El algoritmo compara los dos primeros
elementos (20 y 10); dado que están
desordenados, se intercambian.
2 10, 20, 30, 40 10, 20, 30, 40 El algoritmo compara los dos
elementos siguientes (20 y 30); como
están en el orden correcto, no es
necesario intercambiarlos.
3 10, 20, 30, 40 10, 20, 30, 40 El algoritmo compara los dos
elementos siguientes (30 y 40); como
están en el orden correcto, no es
necesario intercambiarlos.
68 | Lección 3
Durante las pruebas de software se comprueba que la aplicación coincida con los
requisitos del sistema.
Las pruebas de software se usan para garantizar la calidad del producto final. Las pruebas
pueden identificar posibles diferencias entre las expectativas respecto al sistema descritas en el
documento de requisitos y el comportamiento real del sistema.
Entre los participantes más importantes de la actividad de pruebas de software se encuentran
los evaluadores, que comprueban la aplicación de trabajo para asegurarse de que satisface
las necesidades identificadas. Cuando estos evaluadores identifican cualquier defecto en la
aplicación, se lo asignan a la persona adecuada para que lo arregle. Por ejemplo, un defecto del
código se asignaría a un desarrollador para que lo subsanase.
Las pruebas de software consisten en comprobar el software en relación con sus requisitos. Ejercicios paso a paso
CONCLUSIÓN Las pruebas se llevan a cabo después de completar la mayor parte del trabajo de desarrollo.
Como hemos mencionado anteriormente, las pruebas de software consisten en comprobar que 46 | Lección 2
una aplicación de software funciona tal y como se esperaba y satisface todos los requisitos
de negocios y técnicos. Cuando existe una diferencia entre los comportamientos esperado y
real del sistema, se registra un defecto de software (o “error”) que se asigna a una persona COPIA DE TIPOS DE VALOR Y DE REFERENCIA
responsable de corregirlo.
Las pruebas de software pueden incluir pruebas funcionales y no funcionales. Las pruebas USE el proyecto guardado en el ejercicio anterior para completar los pasos siguientes:
funcionales se refieren a los requisitos funcionales del sistema y comprueban las características
que conforman la funcionalidad básica del sistema. Por ejemplo, comprobar si los usuarios 1. Agregue el código siguiente después de la definición de la clase Rectangle para crear
pueden agregar elementos al carro de la compra constituye una parte importante de las pruebas el struct Point:
struct Point
{
public double X, Y;
Alerta Listo para }
certificación
2. Modifique el código del método Main como se muestra a continuación:
TOME NOTA
*
Es posible crear un struct static void Main(string[] args)
Encontrará más La línea 3 del código de la figura 1-3 define un espacio de nombres, Lesson01. Los espacios
información sobre las de nombres se usan para organizar las clases e identificarlas de manera exclusiva. El espacio
clases en la lección 2. de nombres y los nombres de clase se combinan entre sí para crear un nombre de clase
completo. Por ejemplo, el nombre de clase completo de la clase Program es Lesson01.
Program. C# requiere que el nombre completo de una clase sea único. Así pues, no puede
haber otra clase que se llame Program en el espacio de nombres Lesson01, pero sí una clase
denominada Program en otro espacio de nombres, como Lesson02, por ejemplo. En este
caso, la clase Program definida en el espacio de nombres Lesson02 se identificará de forma
exclusiva por su nombre de clase completo, Lesson02.Program.
.NET Framework proporciona gran cantidad de clases útiles organizadas en muchos espacios
de nombres. El espacio de nombres System contiene algunas de las clases base que más se
X REF
usan. Una de estas clases contenidas en el espacio de nombres System es Console. La clase
Encontrará más Console proporciona funcionalidad de entrada y salida para aplicaciones de consola. La línea
información sobre los 9 del código de la figura 1-3 se refiere a la clase Console y llama a su método WriteLine. Para
métodos en la lección 2. obtener acceso al método WriteLine de manera inequívoca, se debe escribir así:
System.Console.WriteLine(“¡Hola, mundo!”);
Dado que los nombres de clase aparecen en el código con frecuencia, escribir su nombre
completo todas las veces puede resultar tedioso y hacer que el programa resulte demasiado
TOME NOTA
* detallado. Para solucionar este problema, se usa la directiva using de C# (consulte el código de
Todas las instrucciones la línea 1 en la figura 1-3). La directiva using permite usar las clases de un espacio de nombres
de C# deben terminar sin tener que escribir el nombre completo de la clase.
con un punto y coma (;).
La clase Program define un método único denominado Main (líneas 7 y 10 del listado de
código que se muestra en la figura 1-3). Main es un método especial que también sirve como
punto de entrada al programa. Cuando el runtime ejecuta un programa, siempre empieza en
el método Main. Un programa puede tener muchas clases y cada clase puede tener muchos
www.wiley.com/college/microsoft o llame al número de teléfono gratuito de MOAC: 1 + (888) 764-7001 (solo EE. UU. y Canadá).
Recorrido por el libro ilustrado | xi
funcionales de un sitio web de comercio electrónico. Por su parte, las pruebas no funcionales
se refieren a comprobar los atributos de software que no forman parte de la funcionalidad
básica, sino de los requisitos no funcionales del software, tales como la usabilidad, la
escalabilidad o la seguridad.
Es importante señalar que el proceso de las pruebas de software solo puede ayudar a
encontrar defectos pero no puede garantizar la ausencia de estos. Todo software complejo
*
TOME NOTA posee un gran número de rutas de ejecución posibles y gran cantidad de parámetros que
pueden afectar a su comportamiento. No es viable ni, con frecuencia, posible, probar todas Ayuda para el lector
las situaciones diferentes que se le presentarán a ese software en un entorno de producción.
Tome nota
Conceptos de los métodos de prueba
Los métodos de las pruebas de software se suelen dividir en dos categorías: pruebas
de caja blanca y pruebas de caja negra.
Las pruebas se llevan a cabo en diferentes fases del ciclo de vida de desarrollo de las Comprensión de bases de datos | 173
aplicaciones. Los distintos niveles de pruebas especifican en qué punto del ciclo de
vida se lleva a cabo una prueba concreta y qué tipo de prueba se ha de efectuar. RESUMEN DE CONOCIMIENTOS
■ Evaluación de conocimientos
Evaluación de
64 | Lección 2
Rellene los espacios en blanco
■ Evaluación de competencias conocimientos Complete las oraciones siguientes escribiendo la palabra o palabras correctas en los
espacios en blanco proporcionados.
1. Para que una tabla se ajuste a la _______________, ninguna de las columnas de la tabla
Escenario 2-1: Creación de propiedades debe tener varios valores en la misma fila de datos.
Debe crear una clase denominada Product que representa un producto. La clase tiene una sola 2. Además, la _______________ exige que todas las columnas no clave sean
propiedad, denominada Name. Los usuarios de la clase Product deben poder obtener y también funcionalmente dependientes de la clave principal completa.
definir el valor de la propiedad Name. Sin embargo, cualquier intento de establecer el valor de
Name en una cadena vacía o un valor null debe iniciar una excepción. Además, los usuarios 3. La _______________ exige que no exista ninguna dependencia funcional entre atributos
de la clase Product no deben tener la capacidad de obtener acceso a ningún otro miembro de no clave.
datos de la clase Product. ¿Cómo se puede crear dicha clase? 4. Los bloques de creación básicos de un diagrama de relación entre entidades son la
_______________, el _______________ y la _______________.
Escenario 2-2: Creación de un struct 5. La cláusula _______________ de una instrucción SELECT evalúa cada fila para
Está desarrollando un juego que requiere representar la ubicación de un objetivo en el espacio comprobar si se cumple una condición y decide si la incluirá en el conjunto de resultados.
tridimensional. La ubicación se identifica por tres valores enteros (de tipo int) denominados x, 6. El objeto que se usa con la instrucción using debe implementar la interfaz
y y z. Debe crear miles de estas estructuras de datos en el programa, de modo que debe hallar _______________.
una manera eficiente y ligera de almacenarlos en la memoria. Además, es poco probable que
sea preciso heredar otros tipos de este tipo de ubicación. ¿Cómo debe representar la ubicación 7. La instrucción _______________ de T-SQL se puede usar para crear un procedimiento
en el programa? almacenado.
■ Evaluación de aptitudes
Escenario 2-1: Invalidación del método ToString
Supongamos que estamos escribiendo código para una clase Product. La clase Product
contiene el nombre y el precio de un producto. Debe invalidar el método ToString de la
clase base (System.Object) de modo que proporcione información sobre los objetos de la
clase Product al código de llamada. ¿Qué código debe escribir para la clase Product a fin de
satisfacer este requisito?
www.wiley.com/college/microsoft o llame al número de teléfono gratuito de MOAC: 1 + (888) 764-7001 (solo EE. UU. y Canadá).
Convenciones y características
que se usan en este libro
En este libro se usan determinadas convenciones para fuentes, símbolos y títulos que resaltan
la información importante y llaman la atención sobre determinados pasos. Para obtener más
información sobre las características de cada lección, consulte la sección Recorrido por el libro
ilustrado.
Convención Significado
Esta característica proporciona un breve resumen del
CONCLUSIÓN
material que se trata en la sección que sigue.
LISTO PARA CERTIFICACIÓN
Esta característica señala un punto en el texto donde se
cubre un objetivo específico de certificación. Proporciona
la oportunidad de comprobar el grado de comprensión de
ese objetivo MTA particular y, si fuera necesario, revisar la
sección de la lección donde se trata.
Las ayudas para el lector aparecen en recuadros
TOME NOTA*
* sombreados que se encuentran en el texto. Tome nota
proporciona consejos útiles relacionados con tareas o temas
concretos.
Estas notas proporcionan referencias a cualquier
REF X
información tratada en otra parte del libro de texto o
describen características interesantes que no se abordan
directamente en el tema o ejercicio actual.
Alt + Tab Un signo más (+) entre dos nombres de teclas indica que
se deben presionar ambas teclas al mismo tiempo. Las
teclas que se le indique que debe presionar en un ejercicio
aparecerán en el tipo de fuente que se muestra aquí.
Ejemplo Los términos clave aparecen en negrita y cursiva cuando se
definen.
www.wiley.com/college/microsoft o llame al número de teléfono gratuito de MOAC: 1 + (888) 764-7001 (solo EE. UU. y
xii | Canadá).
Programa de apoyo
para el instructor
Los programas Microsoft Official Academic Course van acompañados de una generosa
variedad de recursos que incluyen extensas imágenes del libro de texto para formar un paquete
pedagógico coherente. Estos recursos proporcionan todo el material que los instructores
necesitan usar para impartir sus cursos. Los recursos disponibles en línea para su descarga
incluyen:
• MSDN Academic Alliance está diseñado para proporcionar herramientas de desarrollo
más fáciles y económicas, productos y tecnologías disponibles para profesores y alumnos
en los laboratorios, aulas y en los equipos de los alumnos. Existe una suscripción gratuita
disponible durante tres años para usuarios MOAC cualificados.
Nota: Microsoft Windows 2008 Server, Microsoft Windows 7 y Microsoft Visual Studio
se pueden descargar de MSDN AA para uso de los alumnos en este curso.
• La Guía del instructor contiene las soluciones a todos los ejercicios del libro de texto y
programas de estudio de varios plazos. La Guía del instructor también incluye resúmenes
de capítulos y notas de la lección. La Guía del instructor está disponible desde el sitio del
libro complementario (http://www.wiley.com/college/microsoft).
• El banco de pruebas contiene cientos de preguntas en formato de varias opciones,
verdadero o falso, respuesta corta y redacción, y está disponible para la descarga desde
el sitio del libro complementario del instructor (www.wiley.com/college/microsoft). Se
proporciona una clave de respuestas completa.
• Un juego completo de presentaciones de PowerPoint e imágenes está disponible en el
sitio del libro complementario del instructor (http://www.wiley.com/college/microsoft)
para mejorar las presentaciones en el aula. Se proporcionan aproximadamente 50
diapositivas de PowerPoint para cada lección. Adaptadas a la cobertura de actualidad del
texto y a la matriz de conocimientos, estas presentaciones están diseñadas para transmitir
conceptos claves abordados en el texto. Todas las imágenes del texto son del sitio del
libro complementario del instructor (http://www.wiley.com/college/microsoft). Puede
integrarlas en las presentaciones de PowerPoint o crear sus propias transparencias y
documentos. Mediante el uso de estas imágenes en las conversaciones en el aula, puede
ayudar a centrar la atención de los alumnos sobre los elementos clave de las tecnologías
tratadas y ayudarles a entender cómo usarlas eficazmente en el entorno de trabajo.
• Cuando se trata de mejorar la satisfacción en el aula, no hay mejor fuente de ideas e
inspiración que sus colegas. La red de profesorado de Wiley, Wiley Faculty Network,
conecta a los profesores con la tecnología, facilita el intercambio de prácticas mejoradas
y contribuye a aumentar la eficiencia y la eficacia de la enseñanza. Las actividades de la
red de profesorado incluyen entrenamiento tecnológico y tutoriales, seminarios virtuales,
intercambio de conocimientos e ideas entre iguales, asesoramiento personal e intercambio
de recursos. Para obtener más detalles, visite www.WhereFacultyConnect.com.
www.wiley.com/college/microsoft o llame al número de teléfono gratuito de MOAC: 1 + (888) 764-7001 (solo EE. UU. y Canadá).
| xiii
xiv | Programa de apoyo para el instructor
www.wiley.com/college/microsoft o llame al número de teléfono gratuito de MOAC: 1 + (888) 764-7001 (solo EE. UU. y Canadá).
Programa de apoyo
para el alumno
■ Recursos adicionales
Sitio web del libro complementario (www.wiley.com/college/microsoft)
El sitio web del libro complementario para alumnos de la serie MOAC incluye recursos,
archivos de ejercicios y vínculos web que se usarán junto con este curso.
www.wiley.com/college/microsoft o llame al número de teléfono gratuito de MOAC: 1 + (888) 764-7001 (solo EE. UU. y Canadá).
| xv
xvi | Programa de apoyo para el alumno
www.wiley.com/college/microsoft o llame al número de teléfono gratuito de MOAC: 1 + (888) 764-7001 (solo EE. UU. y Canadá).
Programa de apoyo para el alumno | xvii
www.wiley.com/college/microsoft o llame al número de teléfono gratuito de MOAC: 1 + (888) 764-7001 (solo EE. UU. y Canadá).
Reconocimientos
Yuke Wang, Universidad de Texas en Dallas Sharon Moran, Centro de estudios superiores de
Palaniappan Vairavan, Universidad de Bellevue Hillsborough
Harold “Buz” Lamson, Instituto técnico ITT Keith Hoell, Universidad de Briarcliffe y Universidad
Colin Archibald, Centro de estudios superiores de de Queens, Universidad de la Ciudad de Nueva York
Valencia (CUNY)
Catherine Bradfield, Universidad en línea DeVry Mark Hufnagel, Distrito escolar de Lee County
University Online Rachelle Hall, Centro de estudios superiores de Glendale
Robert Nelson, Universidad de Blinn Scott Elliott, Christie Digital Systems, Inc.
Kalpana Viswanathan, Universidad de Bellevue Gralan Gilliam, Kaplan
Bob Becker, Universidad de Vatterott Steve Strom, Centro de estudios superiores de Butler
Carol Torkko, Universidad de Bellevue John Crowley, Centro de estudios superiores del condado
Bharat Kandel, Escuela universitaria Missouri Tech de Bucks
Linda Cohen, Centro de estudios técnicos superiores de Margaret Leary, Centro de estudios superiores del norte
Forsyth de Virginia
Candice Lambert, Centros tecnológicos Metro Sue Miner, Centro de estudios superiores de Lehigh
Carbon
Susan Mahon, Universidad de Collin
Gary Rollinson, Universidad de Cabrillo
Mark Aruda, Centro de estudios superiores de
Hillsborough Al Kelly, Universidad de tecnología avanzada
Claude Russo, Centro de estudios superiores de Brevard Katherine James, Universidad de Seneca
David Koppy, Universidad de Baker
www.wiley.com/college/microsoft o llame al número de teléfono gratuito de MOAC: 1 + (888) 764-7001 (solo EE. UU. y Canadá).
xviii |
Contenido breve
1 Introducción a la programación 1
Apéndice A 177
Índice 179
www.wiley.com/college/microsoft o llame al número de teléfono gratuito de MOAC: 1 + (888) 764-7001 (solo EE. UU. y Canadá).
| xix
Contenido
www.wiley.com/college/microsoft o llame al número de teléfono gratuito de MOAC: 1 + (888) 764-7001 (solo EE. UU. y Canadá).
| xxi
xxii | Contenido
www.wiley.com/college/microsoft o llame al número de teléfono gratuito de MOAC: 1 + (888) 764-7001 (solo EE. UU. y Canadá).
Introducción a la LECCIÓN 1
programación
M AT R I Z D E C O N O C I M I E N T O S D E L A L E C C I Ó N
TÉRMINOS CLAVE
algoritmo código binario matriz
bloque finally constante métodos
bloque switch diagrama de flujo operador
bloque try-catch-finally estructuras de decisión programas (informáticos)
bucle do-while excepción recursión
bucle for instrucción default sistema de numeración binario
bucle foreach instrucción if tabla de decisión
bucle while instrucción if-else tipos de datos
case instrucción switch variable
clase lenguaje de alto nivel
1
2 | Lección 1
El lenguaje de programación que usamos nos aporta diversas herramientas y técnicas que
facilitan nuestro trabajo. En función de la tarea que realicemos, seleccionamos los tipos
de datos y las estructuras de control más adecuadas para resolver el problema.
El término algoritmo se refiere a un método para resolver problemas. Podemos describir los
algoritmos en nuestra lengua natal. No obstante, estas descripciones se suelen malinterpretar
debido a la complejidad y ambigüedad del lenguaje natural. Por lo tanto, los algoritmos se
escriben con frecuencia en formatos simples y precisos, como diagramas de flujo, árboles de
decisión y tablas de decisión, que representan el algoritmo en un diagrama, una tabla o un
gráfico. A menudo, estas técnicas se emplean antes de escribir los programas, con objeto de
permitir que comprendamos mejor la solución.
Estas herramientas de desarrollo de algoritmos pueden ayudarnos a expresar una solución de
una manera fácil de usar, pero un equipo no los entiende directamente. Para que un equipo
entienda nuestro algoritmo, deberemos escribir un programa, que constituye una fórmula más
formal para la que se usa un lenguaje de programación, como C#. Aprenderemos cómo hacerlo
en la sección siguiente.
Pero antes, esta sección de la lección se centra en dos técnicas que se usan para presentar
algoritmos (a saber, los diagramas de flujo y las tablas de decisión). Se trata de métodos más
precisos que el lenguaje natural pero menos formales y más fáciles de usar que un lenguaje de
programación.
Por ejemplo, en la figura 1-1 se muestra un diagrama de flujo que toma dos números (entrada),
los compara y, a continuación, indica cuál es el mayor (salida).
Figura 1-1
Diagrama de flujo simple
que compara dos números
y produce como salida el
mayor de los dos
Como puede observarse, el diagrama de flujo enumera en el orden correcto todos los pasos
necesarios para realizar la operación. El flujo de control comienza con el símbolo de inicio y
termina con el símbolo de fin. Los símbolos del proceso y de entrada y salida siempre tienen
un único punto de entrada y uno de salida. En cambio, el símbolo de decisión tiene una sola
entrada pero varias salidas. Para probar un diagrama de flujo, realizamos un “simulacro”,
es decir, seguimos manualmente los pasos del diagrama de flujo con datos de prueba para
comprobar si se siguen las rutas apropiadas.
Tabla 1-2
Tabla de decisión para Cantidad < 10 S N N N
calcular descuentos
Cantidad < 50 S S N N
Cantidad < 100 S S S N
Descuento 5% 10% 15% 20%
Para averiguar qué elemento de acción se debe aplicar, es preciso evaluar cada condición a
fin de encontrar la regla correspondiente y, a continuación, elegir la acción especificada en
la columna de esa regla. Por ejemplo, si el valor “Cantidad” de los datos de prueba es 75,
entonces la primera regla se evalúa en “No”, la segunda regla se evalúa en “No” y la tercera
regla se evalúa en “Sí”. Por lo tanto, elegiremos el elemento de acción de la columna (N, N, S)
que establece el descuento del 15 %.
Introducción a C#
C# es un conocido lenguaje de alto nivel que permite escribir programas en un formato
legible. C# forma parte de .NET Framework y saca partido de la compatibilidad con el
tiempo de ejecución y las bibliotecas de clases que este entorno proporciona.
Como hemos explicado en la sección anterior, los equipos necesitan instrucciones precisas
y completas para llevar a cabo una tarea. Estos conjuntos de instrucciones se denominan
programas informáticos o, simplemente, programas .
AEn el nivel más básico, los equipos usan el sistema de números binario para representar
la información y el código. En este sistema, cada valor se representa mediante dos símbolos
únicamente, 0 y 1. Un programa escrito en el sistema de números binario se llama código
binario.
Usar el código binario para programar un equipo resulta árido y sumamente difícil para
cualquier tarea mínimamente compleja. Por lo tanto, para simplificar la programación, los
científicos e ingenieros informáticos han desarrollado varios niveles de abstracción entre los
equipos y sus operadores humanos. Estas abstracciones incluyen un software (por ejemplo,
los sistemas operativos, los compiladores y varios sistemas de tiempo de ejecución) que se
encargan de traducir un programa legible por el ser humano en un programa que la máquina
pueda interpretar.
La mayoría de los programas modernos están escritos en un lenguaje de alto nivel como C#,
Visual Basic o Java. Estos lenguajes permiten escribir instrucciones precisas de forma legible
para el ser humano. Posteriormente, un compilador traduce el lenguaje de alto nivel en un
lenguaje de nivel inferior que resulta comprensible al sistema de ejecución runtime.
Cada lenguaje de programación ofrece su propio conjunto de terminología y gramática
(también denominado “sintaxis”). En este curso, aprenderemos a programar con el lenguaje de
programación C# en el entorno .NET Framework. .NET Framework proporciona un entorno
de ejecución runtime para el programa C#. Asimismo, contiene las bibliotecas de clases
que proporcionan gran cantidad de funciones básicas reutilizables que se pueden incorporar
directamente a los programas escritos en C#.
✚ MÁS INFORMACIÓN
.NET Framework proporciona tres componentes principales: un entorno de ejecución runtime, un conjunto
de bibliotecas de clases que proporcionan muchas funciones reutilizables y compiladores de lenguaje para C#,
Visual Basic y Managed C++. .NET Framework admite muchos lenguajes de programación y también la adición de
lenguajes adicionales al sistema. Aunque la sintaxis y la terminología de cada lenguaje varían, todos pueden usar
las bibliotecas de clases base proporcionadas por .NET Framework.
Introducción a la programación | 5
En este curso, usaremos un entorno de desarrollo integrado (IDE) para desarrollar el código.
Para escribir código, es posible usar Visual Studio o la edición gratuita Visual Studio Express.
Ambas herramientas proporcionan un entorno sumamente productivo para desarrollar y probar
los programas.
ESCRITURA DE UN PROGRAMA EN C#
Figura 1-2
Salida del programa en una
ventana de comandos
Para ejecutar el programa, otra opción consiste en abrir una ventana de comandos
(cmd.exe) y, a continuación, navegar a la carpeta de salida del proyecto que, de forma
ALTERNATIVA
predeterminada, es la subcarpeta bin\debug que se encuentra en la ubicación del proyecto.
Inicie el programa. Para ello, escriba el nombre del programa en la ventana de comandos y
presione Intro.
El programa que hemos creado es trivial por lo que hace, pero sin embargo resulta útil para
entender la estructura, compilación y ejecución de un programa. En primer lugar, vamos a
hablar de la parte de compilación y ejecución. Esto es lo que sucede al seleccionar la opción
Depurar > Iniciar sin depurar en el paso 5 anterior:
1. Visual Studio invoca el compilador de C# para traducir el código C# a un lenguaje de
nivel inferior, el código de Lenguaje intermedio común (CIL). Este código de bajo nivel
se almacena en un archivo ejecutable denominado (Lesson01.exe). El nombre del archivo
de salida se puede cambiar modificando las propiedades del proyecto.
2. A continuación, Visual Studio toma la salida del proyecto y pide al sistema operativo
que lo ejecute. En este punto es cuando aparece la ventana de comandos que muestra la
salida.
3. Cuando el programa concluye, Visual Studio muestra el siguiente mensaje: “Presione
cualquier tecla para continuar. . .”. Es importante tener en cuenta que este mensaje
solamente se genera si el programa se ejecuta mediante la opción Iniciar sin depurar.
Cuando se selecciona la opción de menú Depurar > Iniciar sin depurar, Visual Studio
muestra automáticamente el mensaje “Presione cualquier tecla para continuar . . .” Después,
la ventana de comandos permanece abierta para revisar la salida. Si, sin embargo, se
selecciona la opción Depurar > Iniciar depuración, la ventana de comandos se cierra tan
*
TOME NOTA
pronto como finaliza la ejecución del programa. Es importante saber que la opción Iniciar
depuración ofrece funciones como la posibilidad de hacer una pausa en un programa en
ejecución en un momento dado y revisar el valor de diversas variables en la memoria.
Aunque no usemos un entorno de desarrollo integrado (IDE) como Visual Studio, podemos
compilar el programa manualmente mediante las herramientas de la línea de comandos. Pero,
por supuesto, con Visual Studio resulta más fácil y rápido probar los programas.
Antes de poder ejecutar código de Lenguaje intermedio común (CIL), primero debe
traducirse para la arquitectura del equipo en que se ejecutará. El sistema de ejecución
*
TOME NOTA
runtime de .NET Framework se encarga de esta traducción en segundo plano, mediante un
proceso denominado compilación Just-In-Time.
En la figura 1-3 se describe el programa creado en el ejercicio anterior con los números de
línea. Durante esta sección, usaremos estos números para referirnos a las diferentes estructuras
del programa.
Para habilitar la visualización de los números de línea en Visual Studio, seleccione el menú
Herramientas > Opciones. A continuación, expanda el nodo Editor de texto y seleccione C#.
*
TOME NOTA
Por último, en la sección Mostrar, seleccione la opción Números de línea.
Introducción a la programación | 7
Figura 1-3
Listado del programa con
números de línea
Un programa C# está compuesto de una o más clases. Una clase es un conjunto de datos y
métodos. Por ejemplo, el código de la figura 1-3 define una sola clase denominada Program en
las líneas 5 a 11. Una clase se define mediante la palabra clave “class”, seguida por el nombre
de la clase. El contenido de una clase se define entre una llave de apertura ({) y una llave de
X REF cierre (}).
Encontrará más La línea 3 del código de la figura 1-3 define un espacio de nombres, Lesson01. Los espacios
información sobre las de nombres se usan para organizar las clases e identificarlas de manera exclusiva. El espacio
clases en la lección 2. de nombres y los nombres de clase se combinan entre sí para crear un nombre de clase
completo. Por ejemplo, el nombre de clase completo de la clase Program es Lesson01.
Program. C# requiere que el nombre completo de una clase sea único. Así pues, no puede
haber otra clase que se llame Program en el espacio de nombres Lesson01, pero sí una clase
denominada Program en otro espacio de nombres, como Lesson02, por ejemplo. En este
caso, la clase Program definida en el espacio de nombres Lesson02 se identificará de forma
exclusiva por su nombre de clase completo, Lesson02.Program.
.NET Framework proporciona gran cantidad de clases útiles organizadas en muchos espacios
de nombres. El espacio de nombres System contiene algunas de las clases base que más se
X REF
usan. Una de estas clases contenidas en el espacio de nombres System es Console. La clase
Encontrará más Console proporciona funcionalidad de entrada y salida para aplicaciones de consola. La línea
información sobre los 9 del código de la figura 1-3 se refiere a la clase Console y llama a su método WriteLine. Para
métodos en la lección 2. obtener acceso al método WriteLine de manera inequívoca, se debe escribir así:
System.Console.WriteLine(“¡Hola, mundo!”);
Dado que los nombres de clase aparecen en el código con frecuencia, escribir su nombre
completo todas las veces puede resultar tedioso y hacer que el programa resulte demasiado
TOME NOTA
* detallado. Para solucionar este problema, se usa la directiva using de C# (consulte el código de
Todas las instrucciones la línea 1 en la figura 1-3). La directiva using permite usar las clases de un espacio de nombres
de C# deben terminar sin tener que escribir el nombre completo de la clase.
con un punto y coma (;).
La clase Program define un método único denominado Main (líneas 7 y 10 del listado de
código que se muestra en la figura 1-3). Main es un método especial que también sirve como
punto de entrada al programa. Cuando el runtime ejecuta un programa, siempre empieza en
el método Main. Un programa puede tener muchas clases y cada clase puede tener muchos
8 | Lección 1
métodos, pero solo un método Main. A su vez, un método puede llamar a otros métodos. En la
línea 9, el método Main llama al método WriteLine de la clase System.Console para mostrar
una cadena de caracteres en la ventana de comandos; así es como se muestra el mensaje.
El método Main debe declararse como static. Cuando un método es static, es posible
llamarlo para una clase aunque no se haya creado ninguna instancia de ella. Aprenderemos
*
TOME NOTA
más sobre ello en la lección siguiente.
En C#, las variables son marcadores de posición que se usan para almacenar valores. Una
variable tiene un nombre y un tipo de datos. El tipo de datos de una variable determina qué
valores puede contener y qué tipo de operaciones pueden realizarse con ella. Por ejemplo, la
siguiente instrucción crea una variable denominada number del tipo de datos int y le asigna el
valor 10:
int number = 10;
Cuando se declara una variable, en la memoria del equipo se crea una ubicación lo bastante
grande para contener su valor según su tipo de datos. Por ejemplo, en un equipo de 32 bits,
una variable cuyo tipo de datos es int necesita dos bytes de memoria. El valor de una variable
se puede modificar mediante una nueva asignación; por ejemplo:
number = 20;
El código anterior cambia el contenido de la ubicación de memoria identificado por el nombre
number.
Un nombre de variable debe comenzar con una letra o un guion bajo y solo puede contener
letras, números o guiones bajos. Un nombre de variable no debe exceder de 255 caracteres.
*
TOME NOTA
También debe ser exclusiva en el ámbito en el cual se define.
Las constantes son campos de datos o variables locales cuyo valor no se puede modificar.
Las constantes se declaran mediante la palabra clave const. Por ejemplo, una constante se
puede declarar como sigue:
const int i = 10;
Este código declara una constante i de datos de tipo int y almacena el valor 10. Una vez
declarada, no se puede cambiar el valor de la constante.
Los tipos de datos especifican el tipo de datos con que se trabaja en un programa. El tipo
de datos define el tamaño de la memoria necesaria para almacenar los datos y los tipos de
operaciones que se pueden realizar con los datos.
Introducción a la programación | 9
C# proporciona varios tipos de datos integrados que se pueden usar en los programas. También
X REF
se pueden definir tipos nuevos mediante una estructura de datos, como una clase o un struct.
Encontrará más Este capítulo se centra en algunos de los tipos de datos integrados que más se usan.
información sobre cómo En la tabla 1-3 se muestran varios tipos de datos integrados de uso frecuente que están
crear sus propios tipos disponibles en C#. Los tamaños indicados en la tabla se refieren a un equipo que ejecuta un
de datos en la lección 2. sistema operativo de 32 bits, como Windows 7 de 32 bits. Para un sistema operativo de 64 bits,
como Windows 7 de 64 bits, estos tamaños serán diferentes.
Tabla 1-3
Tipos de datos integrados Tipo de datos Tamaño Intervalo de valores
que se usan con frecuencia
en C# byte 1 byte de 0 a 255
char 2 bytes de U+0000 a U+ffff (caracteres Unicode)
short 2 bytes −de 32 768 a 32 767
int 4 bytes −de 2 147 483 648 a 2 147 483 647
long 8 bytes −
de 9 223 372 036 854 775 808 a
9 223 372 036 854 775 807
float 4 bytes de ±1,5 × 10-45 a ±3,4 × 1038
double 8 bytes de ±5.0e−324 a ±1.7e308
TOME NOTA
* bool 2 bytes true o false
Las versiones sin signo
de short, int y long son string - Cero o más caracteres Unicode
ushort, uint y ulong,
respectivamente. Los
tipos sin signo tienen
el mismo tamaño que Todos los tipos de datos enumerados en el cuadro 1-3 son tipos de valor, excepto string, que es
sus versiones con un tipo de referencia. Las variables que se basan directamente en los tipos de valor contienen
signo, pero almacenan el valor. En el caso del tipo de referencia, la variable contiene la dirección de la ubicación de
un intervalo muy memoria donde se almacenan los datos en sí. Aprenderemos más sobre las diferencias entre los
superior de valores solo tipos de valor y los tipos de referencia en la lección 2.
positivos.
CONCEPTOS DE LAS MATRICES
Una matriz es una colección de elementos, a cada uno de los cuales se puede obtener
acceso mediante un índice único.
En C#, se suelen usar las matrices para representar colecciones de objetos de tipo similar. En
el código siguiente se muestra un ejemplo de declaración de matriz:
int[] numbers = { 1, 2, 3, 4, 5 };
Esta declaración crea una matriz identificada por los números de nombre. Puede almacenar
una colección de cinco números enteros. Esta declaración también inicializa cada uno de los
elementos de la matriz respectivamente mediante los números del 1 al 5.
A cualquier elemento de la matriz se puede obtener acceso directamente mediante un índice.
En .NET Framework, los índices de la matriz son de base cero. Esto significa que para obtener
acceso al primer elemento de una matriz se usa el índice 1; para obtener acceso al segundo
elemento, el índice 2 y así sucesivamente.
Para obtener acceso a un elemento individual de la matriz, se usa el nombre de la matriz
seguido por el índice entre corchetes. Por ejemplo, en la matriz que hemos declarado
anteriormente, numbers[0] devolverá el valor 1 y numbers[4] devolverá el valor 5. No es
válido obtener acceso a una matriz fuera de sus límites definidos. Por ejemplo, obtendremos
un error si intentamos obtener acceso al elemento numbers[5] de la matriz.
10 | Lección 1
Ejemplos de operadores son, entre otros, +, -, *, /. Los operandos pueden ser variables,
constants, literals, etc. En función de la cantidad de operandos afectados, existen tres tipos de
operadores:
• Operadores unarios: Los operadores unarios funcionan con un solo operando.
Algunos ejemplos de estos son ++x, x++ o isEven, donde x es del tipo de datos
integer e isEven es del tipo de datos Boolean.
• Operadores binarios: Los operadores binarios toman dos operandos. Ejemplos de
ellos son x + y o x > y.
• Operadores ternarios: Los operadores ternarios toman tres operandos. En C#
solamente existe un operador ternario, ?:.
A menudo, en las expresiones se usa más de un operador. En este caso, el compilador debe
determinar cuál de ellos tiene precedencia sobre los demás. En la tabla 1-4 se muestran los
operadores de C# en orden de precedencia. Cuanto más arriba se encuentra un operador en la
tabla, mayor es su precedencia. Los operadores con mayor precedencia se evalúan antes que
los operadores con menor precedencia. Los operadores que aparecen en la misma fila tienen la
misma precedencia.
Tabla 1-4
Precedencia de los Categoría Operadores
operadores en C#
Principal x.y f(x) a[x] x++ x −− new typeof checked unchecked
Unario + - ! ~ ++x −−x (T)x
Multiplicativo */%
Aditivo +-
Desplazamiento << >>
Relacionales y de pruebas de tipo < > <= >= is as
Igualdad == !=
AND lógico &
XOR lógico ^
OR lógico |
AND condicional &&
OR condicional ||
Ternario condicional ?:
Asignación = *= /= %= += -= <<= >>= &= ^= |=
El operador unario de incremento (++) añade 1 al valor de un identificador. Del mismo modo,
el operador de decremento (−−) resta 1 al valor de un identificador. Los operadores unarios de
incremento y decremento pueden usarse como prefijos o sufijos. Por ejemplo:
Introducción a la programación | 11
int x = 10;
x++; //ahora, el valor de x es 11
++x; //ahora, el valor de x es 12
Sin embargo, el funcionamiento de los operadores unarios de incremento y decremento cuando
se usan como parte de una asignación puede afectar los resultados. En concreto, cuando los
operadores unarios de incremento y decremento se usan como prefijos, el valor actual del
identificador se devuelve antes que el incremento o decremento. Por otro lado, cuando se
usan como sufijo, el valor del identificador se devuelve después de completar el incremento
o decremento. Para entender lo que significa esto, vamos a estudiar el siguiente ejemplo de
código:
int y = x++; // el valor de y es 12
int z = ++x; // el valor de z es 14
En la primera instrucción, el valor de x se devuelve antes del incremento. En consecuencia,
después de ejecutar la instrucción, el valor de y es 12 y el valor de x es 13. En cambio, en la
segunda instrucción, el valor de x se incrementa antes de devolver su valor para asignarlo. Así
pues, después de ejecutar la instrucción, el valor de x y de z es 14.
En el listado de código anterior, conocimos el método Main. Los métodos son la parte de
los programas donde se realizan las acciones. Más en concreto, un método es un conjunto de
instrucciones que se ejecutan cuando se llama al método.
LISTO PARA CERTIFICACIÓN El método Main no devuelve un valor al código que lo llama. Esto se indica mediante la
¿Comprende los palabra clave void. Para que un método devuelva un valor, se ha de usar el tipo de datos
elementos básicos de apropiado para el valor devuelto, en lugar de void.
programación, como
variables, tipos de datos, Los miembros de una clase pueden tener modificadores, tales como static, public y private.
operadores y métodos? Estos modificadores especifican cómo y dónde se puede obtener acceso a los miembros de la
1.1 clase. Aprenderemos más sobre los modificadores en la lección 2.
En C#, las estructuras de control de la toma de decisiones son las instrucciones if, if-else y
switch. En las siguientes secciones se explica cada una de ellas con mayor detalle.
Instrucción if
La instrucción if ejecutará una secuencia de instrucciones determinada únicamente si
la expresión de tipo Boolean correspondiente se evalúa en true (verdadero).
12 | Lección 1
A veces, en los programas, interesa que una secuencia de instrucciones solamente se ejecute
si se cumple determinada condición. En C#, esto se puede hacer mediante la instrucción if. El
procedimiento siguiente permite crear un programa que usa una instrucción if.
USO DE LA INSTRUCCIÓN IF
Figura 1-4
Diagrama de flujo
equivalente a la instrucción if
de ejemplo
En el código C#, es obligatorio que la condición se escriba entre paréntesis. Sin embargo, las
llaves son opcionales cuando el bloque de código contiene una sola instrucción. Así pues, la
instrucción anterior equivale a la siguiente:
if (number2 > number1)
Console.WriteLine(“number2 es mayor que number1”);
En cambio, vamos a fijarnos en este ejemplo:
if (number2 > number1)
Console.WriteLine(“number2 es mayor que number1”);
Console.WriteLine(number2);
En este caso, solo la primera instrucción Console.WriteLine forma parte de la instrucción if.
La segunda instrucción Console.WriteLine siempre se ejecuta, independientemente del valor
de la expresión de tipo Boolean.
Para mayor claridad, siempre es conveniente incluir entre llaves las instrucciones que se deben
ejecutar condicionalmente.
Las instrucciones if también pueden anidarse en otras instrucciones if, como en el ejemplo
siguiente:
int number1 = 10;
if (number1 > 5)
{
Console.WriteLine(“number1 es mayor que 5”);
if (number1 < 20)
{
Console.WriteLine(“number1 es menor que 20”);
}
}
Dado que ambas condiciones se evalúan en true, este código generaría la siguiente salida:
number1 es mayor que 5
number1 es menor que 20
Pero ¿qué pasaría si el valor de number1 fuese 25 en lugar de 10 antes de ejecutar la
instrucción if externa? En este caso, la primera expresión de tipo Boolean se evaluaría en true,
pero la segunda se evaluaría en false. Por lo tanto, se generaría la siguiente salida:
number1 es mayor que 5
Instrucción if-else
La instrucción if-else permite que un programa realice una acción si la expresión de
tipo Boolean se evalúa en true y otra acción distinta si se evalúa en false.
Figura 1-5
Diagrama de flujo
equivalente a la instrucción
if-else de ejemplo
Instrucción switch
La instrucción switch permite bifurcaciones multidireccionales. En muchos
casos, usar instrucciones switch puede simplificar una combinación compleja de
instrucciones if-else.
TOME NOTA
* La instrucción switch consta de la palabra clave switch, seguida de una expresión entre
La expresión que sigue paréntesis, seguida a su vez de un bloque switch. El bloque switch puede incluir una o más
a la instrucción case instrucciones case o una instrucción default. Cuando se ejecuta la instrucción switch, se
debe ser una expresión transfiere el control a una instrucción case coincidente según el valor de la expresión switch.
constante del mismo Si la expresión no coincide con ninguna de las instrucciones case, el control se transfiere a la
tipo de datos que la instrucción default. La expresión switch debe ir entre paréntesis.
expresión switch.
El procedimiento siguiente permite crear un programa que usa la instrucción switch para
evaluar expresiones simples.
C# tiene cuatro estructuras de control diferentes que permiten a los programas realizar
RESULTADO FINAL tareas repetitivas: el bucle while, el bucle do-while, el bucle for y el bucle foreach.
Estas instrucciones de control de repetición pueden usarse para ejecutar las instrucciones del
cuerpo del bucle un número determinado de veces, según el criterio de terminación del bucle.
Un bucle también se puede terminar mediante una de las diversas instrucciones de
transferencia de control que transfieren el control fuera del bucle. Estas instrucciones son
break, goto, return o throw. Por último, se puede usar la instrucción continue para pasar el
control a la siguiente iteración del bucle sin salir de él.
Figura 1-6
Diagrama de flujo
equivalente al bucle while de
ejemplo
Como se observa, el bucle for combina las tres expresiones de control esenciales de una
iteración. Esto da lugar a un código más legible. El bucle resulta útil sobre todo para crear
iteraciones que deben ejecutarse un número determinado de veces.
El procedimiento siguiente permite crear un programa que usa el bucle for.
El bucle foreach podría considerarse como una versión mejorada del bucle for para recorrer en
iteración colecciones, tales como matrices y listas. La forma general de la instrucción foreach
es la siguiente:
foreach (elemento ElementType de la colección)
instrucción
22 | Lección 1
Las expresiones de control del bucle foreach deben ir entre paréntesis. Si debe ejecutarse más
de una instrucción como parte del bucle, estas instrucciones deben ir juntas entre llaves.
El procedimiento siguiente permite crear un programa que muestra una manera sencilla de
recorrer en iteración una colección mediante el bucle foreach.
Conceptos de la recursión
La recursión es una técnica de programación que hace que un método se llame a sí
mismo para calcular un resultado.
La recursión y la iteración están relacionadas. Es posible escribir un método que genere los
mismos resultados con la recursión que con la iteración. En general, la naturaleza del problema
en sí ayuda a elegir entre una solución de iteración o recursión. Por ejemplo, una solución
recursiva es más elegante cuando se puede definir la solución de un problema en términos de
una versión más reducida del mismo problema.
Para entender mejor este concepto, tomemos el ejemplo de la operación factorial de las
matemáticas. La definición general recursiva de n factorial (escrito n!) es la siguiente:
n! =
{ 1 if n = 0,
(n − 1)! × n if n > 0.
Según esta definición, si el número es 0, su factorial es uno. Si el número es mayor que
cero, su factorial es el número multiplicado por el factorial del siguiente número menor. Por
Introducción a la programación | 23
.NET Framework admite el control de excepciones estándar para generar y controlar los
errores en tiempo de ejecución. En esta sección, aprenderemos a usar las palabras clave try,
RESULTADO FINAL
catch y finally para controlar excepciones.
24 | Lección 1
Una excepción es una condición de error que ocurre durante la ejecución de un programa.
Cuando esto sucede, el motor de tiempo de ejecución crea un objeto que representa el error y
lo inicia. A no ser que se capture la excepción escribiendo el código de control de excepciones
adecuado, la ejecución del programa termina.
Por ejemplo, si se intenta dividir un entero por cero, se iniciará la excepción
DivideByZeroException. En .NET Framework, una excepción se representa mediante
un objeto de la clase System.Exception o una de sus clases derivadas. Hay clases de
excepciones predefinidas que representan muchas situaciones de error frecuentes, tales
como DivideByZeroException mencionada anteriormente. Si se va a diseñar una aplicación
que necesita iniciar excepciones específicas de esa aplicación, es preciso crear una clase
personalizada de excepciones derivada de la clase System.Exception.
Control de excepciones
Para controlar las excepciones, debe incluirse el código que las inicia en un bloque
try y el código que las captura, en un bloque catch.
El ejercicio siguiente muestra cómo usar un bloque try-catch para controlar una excepción.
El ejercicio usa el método File.OpenText para abrir un archivo de disco. Esta instrucción se
ejecutará perfectamente en situación normal, pero si falta el archivo (o el permiso para leerlo),
entonces se iniciará una excepción.
CONTROL DE EXCEPCIONES
Para controlar una excepción, las instrucciones que pueden provocarlas se incluyen en un
bloque try. A continuación, se agregan bloques catch para controlar una o más excepciones.
En este ejemplo, además de controlar la excepción FileNotFoundException más específica,
también usamos un bloque catch con excepciones más genéricas para detectar todas las demás
excepciones. El nombre de excepción de un bloque catch debe encerrarse entre paréntesis. Las
instrucciones que se deben ejecutar cuando se captura una excepción deben ir entre llaves.
TOME NOTA
* La ejecución del código se detiene cuando se produce una excepción. El motor de tiempo
Un bloque try debe de ejecución busca una instrucción catch que coincida con el tipo de excepción. Si el primer
contar al menos con bloque catch no captura la excepción iniciada, el control pasa al siguiente bloque catch y así
un bloque catch o un sucesivamente. Si la excepción no se controla en el método, el motor de tiempo de ejecución
bloque finally asociado busca la instrucción catch en el código de llamada y continúa con el resto de la pila de
a él. llamadas.
Uso de Try-Catch-Finally
El bloque finally se usa en asociación con el bloque try. El bloque finally siempre se
ejecuta, independientemente de que se inicie una excepción. El bloque finally se usa
con frecuencia para escribir código de limpieza.
Cuando se produce una excepción, a menudo significa que no se han ejecutado algunas de
las líneas de código que vienen detrás de ella. Esto puede hacer que el programa quede en un
estado inestable o sucio. Para evitar estas situaciones, se puede usar la instrucción finally para
garantizar que siempre se ejecute el código de limpieza. Esto puede requerir cerrar conexiones,
liberar recursos o establecer variables en sus valores esperados. En el siguiente ejercicio
estudiaremos un bloque finally.
USO DE TRY-CATCH-FINALLY
• Un algoritmo es un conjunto de pasos ordenados y finitos para resolver un problema dado.
Resulta útil expresar un algoritmo como un diagrama de flujo o una tabla de decisión antes de
desarrollar un programa formal.
• El lenguaje de programación C# forma parte del entorno .NET Framework y saca partido de
la compatibilidad con el tiempo de ejecución y las bibliotecas de clases que este entorno
proporciona.
• Main es un método especial porque también sirve como punto de entrada a un programa.
Cuando el runtime ejecuta un programa, siempre empieza en el método Main.
• En C#, las variables son marcadores de posición que se usan para almacenar valores. Una
variable tiene un nombre y un tipo de datos. El tipo de datos de una variable determina qué
valor puede contener y qué tipo de operaciones pueden realizarse con ella.
Introducción a la programación | 27
• Los operadores son símbolos, tales como +, -, *, y /, que especifican qué operación se realizará
con los operandos antes de devolver un resultado.
• Las instrucciones if-else permiten que un programa realice una acción si la expresión de tipo
Boolean se evalúa en true y otra acción distinta si se evalúa en false.
• La instrucción switch permite bifurcaciones multidireccionales. En muchos casos, usar
instrucciones switch puede simplificar una combinación compleja de instrucciones if-else.
• C# tiene cuatro estructuras de control diferentes que permiten a los programas realizar tareas
repetitivas: el bucle while, el bucle do-while, el bucle for y el bucle foreach.
• Los bucles while y do-while ejecutan reiteradamente un bloque de instrucciones hasta que
una expresión concreta de tipo Boolean se evalúa en false. El bucle do-while comprueba la
condición que figura al final del bucle.
• El bucle for combina en un código más fácil de leer los tres elementos de iteración, que son:
la instrucción de inicialización, la condición de terminación y la instrucción de incremento/
decremento.
• El bucle foreach resulta útil para recorrer en iteración los elementos de una colección.
• La recursión es una técnica de programación que hace que un método se llame a sí mismo para
calcular un resultado.
• .NET Framework admite el control de excepciones estándar para generar y controlar los errores
en tiempo de ejecución. Para controlar las excepciones, debe incluirse el código que las inicia
en un bloque try y el código que las captura en un bloque catch.
• El bloque finally se usa en asociación con el bloque try. El bloque finally siempre se ejecuta,
independientemente de que se inicie una excepción. El bloque finally se usa con frecuencia
para escribir código de limpieza.
■ Evaluación de conocimientos
Rellene los espacios en blanco
Varias opciones
6. Debe almacenar valores que oscilan entre 0 y 255. También debe asegurarse de que su
programa minimice el uso de memoria. ¿Qué tipo de datos debe usar para almacenar estos
valores?
a. byte
b. char
c. short
d. int
7. Si un algoritmo recursivo no contiene un caso base, se crea una recursión infinita. Una
recursión infinita causará que su programa inicie una excepción. ¿Qué excepción iniciará
su programa en este caso?
a. OutOfMemoryException
b. StackOverflowException
c. DivideByZeroException
d. InvalidOperationException
8. Está aprendiendo a desarrollar algoritmos repetitivos en C#. Escribe el siguiente método:
private static void ForTest()
{
for(int i = 1; i < 5;)
{
Console.WriteLine(“El valor de i = {0}”, i);
}
}
¿Cuántas repeticiones realizará el bucle for en este código?
a. 0
b. 4
c. 5
d. Repeticiones infinitas
9. ¿Cuál de las siguientes características de C# debe usar para organizar el código y crear
tipos únicos a nivel global?
a. Ensamblado
b. Espacio de nombres
c. Clase
d. Tipo de datos
10. Escribe el siguiente fragmento de código:
int[] numbers = {1, 2, 3, 4};
int val = numbers[1];
También crea una variable de tipo RectangleHandler como esta:
RectangleHandler handler;
¿Cuál es el valor de la variable val después de que se ejecute este fragmento de código?
a. 1
b. 2
c. 3
d. 4
30 | Lección 1
■ Evaluación de competencias
Escenario 1-1: Conversión de una tabla de decisión en un programa C#
Está desarrollando una aplicación de facturación que calcula porcentajes de descuento basados
en la cantidad que se adquiere de un producto. La lógica para calcular descuentos aparece en
la siguiente tabla de decisión. Si debe escribir un método de C# que use la misma lógica para
calcular el descuento, ¿cómo escribiría dicho programa?
Cantidad < 10 S N N N
Cantidad < 50 S S N N
Cantidad < 100 S S S N
Descuento 5% 10% 15% 20%
■ Evaluación de aptitudes
Escenario 1-3: Control de excepciones
Está escribiendo código para una biblioteca de aritmética simple. Decide crear un método
denominado Divide que toma dos argumentos, x e y, y devuelve el valor de x/y. Debe capturar
todas las excepciones aritméticas que se inicien debidas a errores aritméticos, de conversión
o de conversiones de tipo de datos. También debe capturar todas las demás excepciones que
se inicien a partir del código. Para satisfacer este requisito, debe crear un código de control de
excepciones debidamente estructurado. ¿Cómo se escribe tal programa?
TÉRMINOS CLAVE
clase espacio de nombres objetos
clases abstractas eventos polimorfismo
clases selladas herencia propiedades
constructores interfaces propiedades implementadas
método automáticamente
delegados
modificador de acceso signatura
descriptores de acceso
números estáticos tipo de referencia
encapsulación
tipo de valor
32
Introducción a la programación orientada a objetos | 33
La programación orientada a objetos es una técnica de programación que usa objetos. Los
objetos son estructuras de datos autocontenidos que consisten en propiedades, métodos
CONCLUSIÓN y eventos. Las propiedades especifican los datos que el objeto representa, los métodos
especifican el comportamiento del objeto y los eventos proporcionan comunicación entre
los objetos.
En el mundo real, los objetos necesitan una plantilla que defina cómo construirlos. Todos
los objetos creados con la misma plantilla tienen el mismo aspecto y se comportan de forma
similar. Por ejemplo, pensemos en una marca y un modelo concretos de automóvil.
En el entorno de software, una clase es la plantilla a partir de la cual se crean los objetos
individuales. Un objeto también se denomina una instancia de una clase.
En el mundo del software, un método define las acciones o las operaciones compatibles con
una clase. Para definir un método, se especifica el nivel de acceso, el tipo de valor devuelto, el
nombre del método y una lista opcional de parámetros entre paréntesis seguida por un bloque
de código entre llaves. Por ejemplo, en el ejemplo anterior, la clase Rectangle define un único
método denominado GetArea. Para GetArea, el nivel de acceso es public, el tipo de valor
devuelto es double, el nombre del método es GetArea, la lista de parámetros está vacía y el
TOME NOTA
* bloque de código es una sola instrucción return.
El nombre de un
método, su lista de Un método puede devolver un valor al código de llamada. Si un método no está destinado a
parámetros y el orden de devolver ningún valor, su tipo de valor devuelto se especifica mediante la palabra clave void.
los tipos de datos de los El método debe usar una instrucción return para devolver un valor. La instrucción return
parámetros se reconocen termina la ejecución del método y devuelve el valor especificado en el código de llamada. El
colectivamente como la tipo de datos del valor devuelto por un método debe coincidir con el tipo de valor devuelto
signatura. La signatura especificado en la línea de declaración del método.
de un método debe ser Volviendo al ejemplo anterior, el tipo de valor devuelto del método GetArea es double, lo que
única en una clase. significa que el método GetArea debe devolver un valor de tipo double. El método GetArea
cumple este requisito devolviendo la expresión length * width, que es un valor de tipo double.
El código siguiente define un método InitFields que toma dos parámetros de tipo double y
devuelve un valor de tipo void:
public void InitFields(double l, double w)
{
length = l;
width = w;
}
Introducción a la programación orientada a objetos | 35
El método InitFields toma dos parámetros y usa sus valores para asignar respectivamente la
longitud y el ancho del campo de datos. Cuando el tipo de valor devuelto de un método es
void, se puede usar una instrucción return sin valor. Si no se usa una instrucción return, como
en el método InitFields, el método interrumpirá su ejecución cuando llegue al final del bloque
de código. Se puede usar el método InitFields para inicializar correctamente el valor de los
campos de datos, pero como veremos en la siguiente sección, los constructores ya ofrecen una
forma de inicializar una clase.
CONCEPTOS DE LOS CONSTRUCTORES
Los constructores son métodos de una clase especial que se ejecutan cuando se crea una nueva
instancia de una clase. Los constructores se usan para inicializar los miembros de datos de
un objeto. Deben tener exactamente el mismo nombre que la clase y no tienen tipo de valor
devuelto. Se pueden definir varios constructores para una clase, cada uno con una signatura
única.
Un constructor que no toma ningún argumento se denomina constructor predeterminado.
Si se define una clase sin ningún constructor, se genera automáticamente un constructor
predeterminado invisible que no hace absolutamente nada.
A menudo resulta útil disponer de constructores adicionales que ofrezcan más formas de
inicializar un objeto. La clase Rectangle definida anteriormente es solo una de las formas de
crear e inicializar su objeto: llamar al constructor que acepta dos parámetros, ambos del tipo
de datos predeterminado.
CREACIÓN DE OBJETOS
Los objetos se crean a partir de las plantillas definidas por las clases.
CREACIÓN DE UN OBJETO
PREPÁRESE. Para esta actividad, use el proyecto de aplicación de consola (Lesson02) que
creó en el ejercicio anterior. A continuación, siga este procedimiento:
1. Modifique el código de la clase Program de manera que se ajuste a lo siguiente:
class Program
{
static void Main(string[] args)
{
Rectangle rect = new Rectangle(10.0, 20.0);
double area = rect.GetArea();
Console.WriteLine(“Área del rectángulo: {0}”
area);
}
}
2. Seleccione Depurar > Iniciar sin depurar. Aparecerá una ventana de consola que
mostrará el área del rectángulo.
3. GUARDE el proyecto.
PAUSA. Deje el proyecto abierto para usarlo en el siguiente ejercicio.
La clase Rectangle proporciona una sola manera de construir una instancia de la clase: llamar
a un constructor con dos argumentos del tipo de datos double. En este caso, creamos un objeto
mediante la palabra clave new seguida de la llamada al constructor de la clase apropiada.
36 | Lección 2
Cuando se ejecuta el código, se crea un objeto del tipo Rectangle en la memoria del montón.
TOME NOTA
* Se almacena una referencia a esta memoria en la variable rect. A su vez, la variable rect
Las clases y los objetos se almacena en la pila. Más adelante en este bloque de código, puede usar rect para hacer
son diferentes. Una clase referencia al objeto recién creado y manipularlo.
define la plantilla de un
objeto, pero no es un Mediante la referencia al objeto, es posible obtener acceso a los miembros de la clase. Por
objeto en sí misma. Por ejemplo, el código llama al método GetArea para el objeto y el valor devuelto por el método
otro lado, un objeto es se almacena en la variable area. Los campos de datos, length y width, del objeto rect no están
una instancia concreta de accesibles aquí, porque se han marcado como privado (private) en la definición de clase.
una clase pero no es una
clase propiamente dicha. CONCEPTOS DE LAS PROPIEDADES
Las propiedades permiten obtener acceso a los datos de la clase de una manera segura y
flexible.
TOME NOTA
* Las propiedades son miembros de una clase a los que se puede obtener acceso, de forma
Con frecuencia
nos referimos a las similar a los campos de datos, pero que contienen código, como un método. Las propiedades
propiedades con el se suelen usar para exponer los campos de datos de una clase de una manera más controlada.
término “campos Por ejemplo, un campo privado se puede exponer mediante una propiedad pública, pero no es
inteligentes” porque necesario usar las propiedades de esta forma.
pueden incluir código que Una propiedad posee dos descriptores de acceso: get y set. El descriptor de acceso get se usa
compruebe la coherencia para devolver el valor de propiedad; el descriptor de acceso set se usa para asignar un valor
o validez de los datos. nuevo a la propiedad. Una propiedad se suele definir como pública (public) y, por convención,
siempre tiene un nombre que comienza por una letra mayúscula. En cambio, la convención
para nombrar los campos de datos privados es comenzar con una letra minúscula.
CREACIÓN DE PROPIEDADES
set
{
if ( value > 0.0)
width = value;
}
}
public double GetArea()
{
return length * width;
}
}
2. Después, modifique el código de la clase Program de manera que se ajuste a lo
siguiente:
class Program
{
static void Main(string[] args)
{
Rectangle rect = new Rectangle();
rect.Length = 10.0;
rect.Width = 20.0;
double area = rect.GetArea();
Console.WriteLine(
“Área del rectángulo: {0}”, area);
}
}
3. Seleccione Depurar > Iniciar sin depurar. Aparecerá una ventana de consola que
mostrará el área del rectángulo.
4. GUARDE el proyecto.
PAUSA. Deje el proyecto abierto para usarlo en el siguiente ejercicio.
TOME NOTA
* En este ejercicio, hemos modificado la clase Rectangle para introducir dos propiedades,
Según la forma de Length y Width (que representan la longitud y el ancho, respectivamente). Las propiedades
programación habitual, se suelen definir mediante un modificador de acceso público. En el código de la propiedad
todos los campos de Length, el descriptor de acceso get se limita a devolver el valor de la longitud del campo de
datos de una clase datos. Sin embargo, el descriptor de acceso set comprueba cuál es el valor asignado (mediante
deben declararse como la palabra clave value) a la propiedad y modifica la longitud del campo de datos únicamente
privados y el acceso a si el valor es positivo. Los campos privados length y width también se denominan campos de
estos campos privados respaldo para las propiedades que los exponen, respectivamente.
se realiza mediante Por otra parte, la clase Rectangle no declara ningún constructor explícito. En este caso, los
propiedades públicas que usuarios de la clase (el método Main) deben usar el constructor predeterminado y dependen de
comprueban la validez de las propiedades para inicializar los datos de la clase.
los valores de datos.
El método Main usa las propiedades Length y Width para configurar los datos del objeto rect.
Cualquier intento de establecer Length o Width en un valor negativo se omitirá, en cuyo caso
los campos de datos seguirán teniendo su valor original, 0.
Al definir propiedades, puede excluir el descriptor de acceso get o set. Cuando no se incluye
un descriptor de acceso set, no se proporciona ningún modo para establecer el valor de la
propiedad. En consecuencia, la propiedad será de solo lectura. Por otro lado, si no se incluye
el descriptor de acceso get, no se proporciona un modo de obtener el valor de la propiedad. Así
pues, la propiedad será de solo escritura.
CONCEPTOS DE LAS PROPIEDADES DE IMPLEMENTACIÓN AUTOMÁTICA
La palabra clave this se puede usar para obtener acceso a los miembros desde el interior
de los constructores, los métodos de instancia y los descriptores de acceso de las
propiedades de instancia.
Introducción a la programación orientada a objetos | 39
La palabra clave this es una referencia a la instancia actual de la clase. Puede usar la palabra
clave this para referirse a cualquier miembro del objeto actual. Por ejemplo, previamente en
este capítulo, hemos escrito clase Rectangle como sigue:
class Rectangle
{
private double length;
private double width;
public Rectangle(double l, double w)
{
length = l;
width = w;
}
public double GetArea()
{
return length * width;
}
}
Sin embargo, podríamos escribirla así:
class Rectangle
{
private double length;
private double width;
public Rectangle(double l, double w)
{
this.length = l;
this.width = w;
}
public double GetArea()
{
return this.length * this.width;
}
}
Como puede observarse, en el segundo ejemplo hemos usado la palabra clave this dentro del
constructor y del método GetArea para referirnos a los campos de datos del objeto actual de la
clase Rectangle. Aunque no era necesario recurrir a la palabra clave this en este caso, su uso
aporta mayor flexibilidad para nombrar los parámetros del método. Por ejemplo, podríamos
definir el constructor de la siguiente manera:
TOME NOTA
*
En C#, los caracteres public Rectangle(double length, double width)
// se usan para agregar {
al código comentarios // los nombres de parámetros length y width
de una sola línea. El // prevalecen sobre los miembros de clase length y
compilador pasa por alto
// width en este ámbito
todo el texto que aparece
detrás de los caracteres //. this.length = length;
Los comentarios de varias this.width = width;
líneas comienzan con los }
caracteres /* y terminan
con los caracteres */. Dentro del ámbito de la definición del constructor Rectangle, los nombres length y width se
refieren ahora a los parámetros que se pasan. Los parámetros prevalecen sobre los nombres de
los campos de datos y solamente es posible obtener acceso a estos últimos mediante la palabra
clave this.
40 | Lección 2
Los delegados son tipos especiales que se usan para encapsular un método con una
signatura específica.
Los delegados son objetos especiales que pueden conservar una referencia a un método
con una signatura específica. Un delegado se define mediante la palabra clave delegate. Por
ejemplo, puede definir un delegado de la siguiente manera:
public delegate void RectangleHandler(Rectangle rect);
La definición del delegado especifica la signatura del método cuya referencia puede estar
contenida en un objeto delegado. Por ejemplo, en el código anterior, definimos un delegado
RectangleHandler que puede contener referencias a un método que devuelve void y acepta un
solo parámetro del tipo Rectangle.
Así pues, si tenemos un método con una signatura similar, será un candidato idóneo para
asignárselo a una instancia del delegado. Por ejemplo:
public void DisplayArea(Rectangle rect)
{
Console.WriteLine(rect.GetArea());
}
El tipo delegado puede usarse para declarar una variable que puede hacer referencia a
cualquier método que tenga la misma signatura que el delegado. Por ejemplo, podemos
escribir:
RectangleHandler handler;
A continuación, podemos asignar el método al delegado mediante la siguiente sintaxis:
handler += new RectangleHandler(DisplayArea);
Como alternativa, podemos usar la sintaxis abreviada que se muestra a continuación:
handler += DisplayArea;
Observe que la sintaxis usa la operación de adición. Esto significa que es posible asociar más
de un método (de signatura compatible), con lo que se crea una lista de invocaciones de uno o
más métodos.
Por último, puede realizarse una llamada a un delegado mediante una sintaxis de llamada al
método, así:
Rectangle rect = new Rectangle (10, 20);
handler(rect);
Cuando se llama al delegado de esta manera, invoca todos los métodos de su lista de
invocaciones. En este ejemplo concreto, el objeto handler se refiere a un solo método
DisplayArea y, por lo tanto, el método DisplayArea se invocará con el objeto rect como
parámetro.
Entre otras muchas aplicaciones, los delegados constituyen la base de las declaraciones de
eventos, como se explica en la siguiente sección.
CONCEPTOS DE LOS EVENTOS
Los eventos son un medio para que una clase notifique a otras clases u objetos que ha
sucedido algo de interés. La clase que envía la notificación se denomina publicador del
evento. La clase que recibe la notificación se denomina suscriptor del evento.
Es fácil comprender los eventos en el contexto de una interfaz gráfica de usuario (GUI).
Por ejemplo, cuando un usuario hace clic en un botón, se produce el evento Click. Varios
elementos de la interfaz de usuario pueden suscribirse a este evento y cambiar su estado visual
Introducción a la programación orientada a objetos | 41
USE el proyecto guardado en el ejercicio anterior para llevar a cabo las siguientes tareas:
1. Modifique el código de la clase Rectangle como se muestra a continuación:
class Rectangle
{
public event EventHandler Changed;
private double length;
public double Length
{
get
{
return length;
TOME NOTA
* }
El campo EventArgs.
Empty representa un set
evento sin datos de {
evento. Este campo length = value;
equivale a tener una Changed(this, EventArgs.Empty);
instancia de solo lectura }
de la clase EventArgs.
}
}
2. Modifique el código de la clase Program de manera que se ajuste a lo siguiente:
class Program
{
static void Main(string[] args)
{
Rectangle r = new Rectangle();
42 | Lección 2
Un espacio de nombres es un elemento del lenguaje que permite organizar el código y crear
nombres de clase únicos a nivel global. Supongamos que creamos una clase denominada
Widget. Es probable que exista alguna otra empresa que distribuya código que contenga
una clase denominada Widget. En ese caso, ¿cómo controlaremos la ambigüedad en los
nombres? La solución consiste en organizar el código en el seno de un espacio de nombres.
La convención común consiste en usar el nombre de la empresa en el espacio de nombres. Por
ejemplo, podríamos escribir lo siguiente:
namespace CompanyA
{
public class Widget { … }
}
Introducción a la programación orientada a objetos | 43
y
namespace CompanyB
{
public class Widget { … }
}
En este caso, podemos hacer referencia a la clase del espacio de nombres CompanyA de
manera única mediante su nombre de clase completo: CompanyA.Widget. Por su parte, la otra
clase Widget puede identificarse inequívocamente mediante CompanyB.Widget.
.NET Framework usa espacios de nombres de forma generalizada para organizar todas sus
clases. Por ejemplo, el espacio de nombres System agrupa todas las clases fundamentales. El
espacio de nombres System.Data organiza las clases para el acceso de datos. De igual forma,
el espacio de nombres System.Web se usa para las clases relacionadas con la Web.
Es evidente que con el uso de espacios de nombres podríamos terminar usando nombres de
clase completos excesivamente largos, lo que daría lugar a programas demasiado detallados y
obligaría a mecanografiar mucho texto. C# soluciona este inconveniente mediante la directiva
using. La directiva using se puede usar en la parte superior del archivo de clase, así:
using System.Text;
Una vez que hemos incluido la directiva using para un espacio de nombres, no es preciso usar
el nombre completo de las clases de ese espacio de nombres en el archivo.
Todos los miembros de la clase que hemos descrito hasta ahora en esta sección (por ejemplo,
campos de datos, métodos y propiedades) funcionan con objetos individuales. Se los denomina
miembros de instancia, porque solo se pueden usar después de haber creado una instancia
de una clase. En cambio, la clave static se usa para declarar miembros que no pertenecen a
objetos individuales, sino a una clase en sí. Los miembros de clase de este tipo se denominan
miembros estáticos. Un ejemplo común de un miembro estático es el método Main que hemos
mencionado ya y que actúa como punto de entrada al programa.
USE el proyecto guardado en el ejercicio anterior. A continuación, realice los siguientes pasos:
1. Modifique el código de la clase Rectangle como se muestra a continuación:
class Rectangle
{
public static string ShapeName
{
get { return “Rectángulo”; }
}
public double Length { get; set; }
public double Width { get; set; }
public double GetArea()
{
return this.Length * this.Width;
}
}
44 | Lección 2
Un tipo de valor almacena directamente un valor, mientras que un tipo de referencia solo
CONCLUSIÓN almacena una referencia al valor propiamente dicho.
Un tipo de valor almacena datos directamente en su memoria. Por su parte, los tipos
de referencia, solo almacenan una referencia a una ubicación de memoria; es decir, los
verdaderos datos se almacenan en la ubicación de memoria a la que se hace referencia. La
mayoría de los tipos de datos elementales integrados (tales como bool, int, char, double, etc.)
son tipos de valor. Los tipos de datos definidos por el usuario creados mediante la palabra
clave struct son también tipos de valor. Los tipos de referencia son aquellos creados mediante
las palabras clave object, string, interface, delegate y class.
Conceptos de los structs
La palabra clave struct se usa para crear tipos definidos por el usuario que consisten en
pequeños grupos de campos relacionados. Los structs son tipos de valor, a diferencia de
las clases, que son tipos de referencia.
Los structs se definen mediante el uso de la palabra clave struct, como se muestra a
continuación:
public struct Point
{
public double X, Y;
}
Los structs pueden contener casi todos los elementos que pueden contener las clases, tales
como constructores, métodos, propiedades, etc. Sin embargo, como aprenderemos en la
Introducción a la programación orientada a objetos | 45
sección siguiente, los structs son tipos de valor, mientras que las clases son tipos de referencia.
TOME NOTA
* A diferencia de una clase, un struct no puede heredar de otra clase o de otro struct.
Los structs se usan
principalmente para crear
tipos simples. Si observa Conceptos de la asignación de memoria
que está creando un
struct muy complejo, es
conveniente estudiar la Después de especificar un valor o texto en una celda, se puede modificar de diversas
posibilidad de usar una formas. En particular, se puede eliminar el contenido por completo, especificar otro valor
clase en su lugar. distinto que sustituya al que había previamente o modificar la información especificada.
Una manera excelente de entender la diferencia entre los tipos de valor y los tipos de
referencia consiste en visualizar cómo se representa cada uno de ellos en la memoria. En la
figura 2-1 se muestra cómo se crean los tipos de valor en la memoria. Al crear una variable
de tipo int, por ejemplo, se crea una ubicación de memoria con nombre que se puede usar
para almacenar un valor de tipo int. Inicialmente, si no se asigna explícitamente un valor, se
almacena el valor predeterminado del tipo de datos (para int, el valor predeterminado es 0) en
la ubicación de memoria. Luego, cuando se realiza una asignación, la dirección de memoria
identificada por el nombre de la variable se actualiza con el nuevo valor (10 en el caso de la
asignación de la figura 2-1).
Figura 2-1
Visualización de un tipo de
valor en la memoria
Ahora, vamos a fijarnos en la figura 2-2, que muestra un tipo de referencia; en concreto,
el tipo de datos string. Cuando se crea una variable de tipo string, se crea una ubicación de
memoria que se identifica con este nombre. Sin embargo, esta ubicación de memoria no estará
ocupada por el contenido de la cadena. En cambio, esta variable almacenará la dirección de
memoria (una referencia) del lugar donde realmente se almacena la cadena.
Figura 2-2
Visualización de un tipo de
referencia en la memoria
Inicialmente, mientras no se haya asignado ningún valor, la variable tendrá el valor null (una
referencia null; es decir, esta variable no hará referencia a una dirección de memoria válida).
Posteriormente, en la instrucción siguiente, cuando escribamos:
name = “Northwind”;
se creará el valor de tipo string “Northwind” en una ubicación de memoria concreta (para
simplificar, supongamos que la dirección de memoria es m100) y esta dirección de memoria
se almacenará en el nombre de la variable. Más tarde, cuando llegue el momento de recuperar
el valor del nombre de la variable, el runtime sabrá que su contenido no está almacenado en la
variable en sí, sino en la ubicación de memoria a la que esta variable señala.
46 | Lección 2
USE el proyecto guardado en el ejercicio anterior para completar los pasos siguientes:
1. Agregue el código siguiente después de la definición de la clase Rectangle para crear
el struct Point:
struct Point
{
public double X, Y;
}
2. Modifique el código del método Main como se muestra a continuación:
TOME NOTA
*
Es posible crear un struct static void Main(string[] args)
sin usar el operador {
new. Basta con escribir Point p1 = new Point();
Point p1; para crear una
p1.X = 10;
variable de tipo struct.
p1.Y = 20;
Point p2 = p1;
p2.X = 100;
Console.WriteLine(“p1.X = {0}”, p1.X);
Rectangle rect1 = new Rectangle
{ Length = 10.0, Width = 20.0 };
Rectangle rect2 = rect1;
rect2.Length = 100.0;
Console.WriteLine(“rect1.Length = {0}”,
rect1.Length);
TOME NOTA
* }
Cuando se copia una
3. Seleccione Depurar > Iniciar sin depurar. Aparecerá una ventana de consola que
variable de tipo de
mostrará los valores de p1.X y rect1.Length.
referencia en otra variable
del mismo tipo, solo se 4. GUARDE el proyecto.
copian las referencias. En
consecuencia, después de
PAUSA. Deje el proyecto abierto para usarlo en el siguiente ejercicio.
la copia, ambas variables Aquí, la primera parte del programa crea una copia del tipo de valor Point y la segunda mitad
señalarán al mismo crea una copia del tipo de referencia Rectangle.
objeto.
Comenzaremos por analizar cómo se realiza la copia de un tipo de valor. Para empezar,
cuando se ejecuta la instrucción siguiente, se crea una nueva variable p2 en la memoria, cuyo
contenido se copia de la variable p1:
Point p2 = p1;
Después de ejecutar esta instrucción, se crea la variable p2 y se copia el contenido de
la variable p1 en la variable p2. Tanto p1 como p2 tienen su propio conjunto de valores
disponibles en sus ubicaciones de memoria respectivas. Así pues, cuando se ejecuta la
instrucción siguiente:
p2.X = 100;
solo afecta al valor de X correspondiente a la ubicación de memoria de la variable p2. El valor
de X para la variable p1 permanece invariable.
Introducción a la programación orientada a objetos | 47
Ahora, analizaremos cómo funciona la copia entre tipos de referencia. En este caso, cuando se
ejecuta la instrucción siguiente, se crea una nueva variable rect2 y, al igual que antes, se copia
el contenido de rect1 en la ubicación de memoria de rect2:
Rectangle rect2 = rect1;
Sin embargo, como la clase Rectangle es un tipo de referencia, en realidad el contenido
de la variable rect1 es una referencia a la ubicación de memoria que contiene un objeto
Rectangle. Así pues, después de la inicialización anterior, tanto rect1 como rect2 señalan a la
misma ubicación de memoria y, a su vez, al mismo objeto Rectangle. Es decir, solo existe un
objeto rectangle en la memoria y tanto rect1 como rect2 hacen referencia a él. La siguiente
instrucción modifica la longitud (Length) del objeto Rectangle:
rect2.Length = 100.0;
Esta instrucción hace referencia a la ubicación de memoria a la que señala rect2 (que resulta
ser la misma ubicación de memoria a la que señala rect1) y modifica el valor de Length del
objeto Rectangle. Ahora, si intentamos hacer referencia a la misma ubicación de memoria
LISTO PARA CERTIFICACIÓN mediante el objeto rect1, obtendremos el objeto modificado y el código siguiente mostrará el
¿Comprende los tipos valor “rect1.Length = 100”:
de datos y la asignación
de memoria? Console.WriteLine(“rect1.Length = {0}”,
1.1 rect1.Length);
✚ MÁS INFORMACIÓN
A los objetos siempre se les asigna memoria del montón. El montón es la parte de la memoria
disponible para la asignación dinámica a un programa en tiempo de ejecución. En cambio, algunos
elementos de datos se pueden crear en la pila de ejecución o la pila de llamadas. Los elementos
creados en la pila son los parámetros de método y las variables locales declaradas dentro de un
método. La memoria de pila se reclama cuando la pila se desenreda (cuando se devuelve un método,
por ejemplo). El recolector de elementos no utilizados reclama automáticamente la memoria asignada
en el montón cuando los objetos dejan de estar en uso (es decir, cuando no hay otros objetos que
contengan una referencia a ellos).
■ Conceptos de la encapsulación
TOME NOTA
* Los modificadores de acceso controlan dónde se puede usar un tipo o un miembro de un
Es importante usar el tipo.
nivel de acceso más
restrictivo que resulte Todos los tipos y miembros de tipos tienen un nivel de acceso que especifica en qué lugares
lógico para un miembro del código se pueden usar esa clase o sus miembros. El nivel de acceso se puede establecer
de un tipo. mediante uno de los modificadores de acceso especificados en la tabla 2-1.
Tabla 2-1
Modificadores de acceso
Cuando se compila el código C#, el código ejecutable de salida contenido en un archivo .dll o
.exe también se denomina ensamblado. Un ensamblado es una unidad de código ejecutable que
TOME NOTA
* se puede instalar y que puede tener versiones.
■ Conceptos de la herencia
Supongamos que queremos crear un conjunto de clases que describa polígonos, como
TOME NOTA
* rectángulos o triángulos. Estas clases tendrán algunas propiedades comunes, tales como el
A diferencia de las clases, ancho y la longitud. Para este caso, puede crear una clase base Polygon con las propiedades
los structs no admiten la Width y Length; las clases derivadas Rectangle y Triangle heredarán estas propiedades a la vez
herencia. que proporcionarán su propia funcionalidad. En el siguiente ejercicio se explica este concepto
con mayor detalle.
USE el proyecto guardado en el ejercicio anterior para llevar a cabo las siguientes acciones:
1. Agregue una nueva clase denominada Polygon como se muestra a continuación:
class Polygon
{
public double Length { get; protected set; }
public double Width { get; protected set; }
}
2. Modifique la clase Rectangle como se muestra a continuación:
class Rectangle: Polygon
{
public Rectangle(double length, double width)
{
Length = length;
Width = width;
}
public double GetArea()
{
return Width * Length;
}
}
4. Seleccione Depurar > Iniciar sin depurar. Aparecerá una ventana de consola que
mostrará el ancho, la longitud y el área del rectángulo.
5. GUARDE el proyecto.
PAUSA. Deje el proyecto abierto para usarlo en el siguiente ejercicio.
Para definir una clase derivada, se escribe un signo de dos puntos después del nombre de la
clase derivada, seguido por el nombre de la clase base. En este caso, la clase Polygon es la
clase base de la clase Rectangle.
50 | Lección 2
Las propiedades Length y Width en la clase Polygon se declaran con un modificador de acceso
protegido para el descriptor de acceso set. Esto significa que el acceso al descriptor de acceso
set está disponible solamente dentro de la clase Polygon y sus clases derivadas. Podemos
obtener el valor de las propiedades Length y Width en el método Main, pero obtendremos un
error si intentamos asignar un valor a estas propiedades.
La clase Rectangle hereda todos los datos y comportamientos no privados de la clase Polygon.
Además, la clase Rectangle define una funcionalidad adicional (el método GetArea) que no
está disponible en la clase base.
Conceptos de las clases abstractas y selladas
Las clases abstractas proporcionan una definición común de una clase base que pueden
compartir varias clases derivadas. Las clases selladas, por su parte, proporcionan una
funcionalidad completa, pero no pueden usarse como clases base.
Esta versión de la clase Polygon define un método denominado GetArea. El motivo principal
para incluir este método en la clase base es que ahora esta puede proporcionar una plantilla
común de funcionalidad para las clases derivadas. Pero, como ya hemos explicado, la clase
TOME NOTA
* base Polygon no dispone de información suficiente para calcular el área de la forma. Esta
No puede crear instancias situación se puede resolver marcando el método como abstracto. Un método abstracto
de una clase abstracta. proporciona una definición pero no ofrece ninguna implementación (el cuerpo del método).
Si cualquiera de los miembros de una clase es abstracto, la clase en sí debe marcarse como
abstracta. No se pueden crear instancias de una clase abstracta.
Las clases derivadas pueden proporcionar una implementación de una clase abstracta para
crear una clase concreta (una clase no abstracta). Las clases derivadas pueden ofrecer una
implementación de un método abstracto invalidándolo en una clase derivada. Por ejemplo,
la clase Rectangle invalida el método GetArea abstracto de la clase base y proporciona una
implementación completa. En consecuencia, la clase Rectangle ya no es una clase abstracta y
se pueden crear instancias de ella directamente.
Las clases selladas, por el contrario, se definen cuando la implementación ha finalizado y no
se desea que se herede ninguna clase. Es posible crear una clase sellada mediante la palabra
clave sealed, como en el ejemplo siguiente:
sealed class Rectangle: Polygon
{
// aquí van los miembros de la clase
}
Puesto que Rectangle es una clase sellada, no se puede usar como clase base. También es
posible marcar los miembros de la clase seleccionada como sellados para evitar que se
invaliden en una clase derivada. Por ejemplo, podríamos escribir:
TOME NOTA
* sealed public override double GetArea()
C# no admite la herencia {
de más de una clase
base, lo que a menudo return Width * Length;
se denomina herencia }
múltiple.
Esta declaración asegura que el método GetArea no se pueda invalidar en una clase derivada.
La clase Object es la clase base última de todas las clases de .NET Framework.
Todas las clases de .NET Framework heredan directa o indirectamente de la clase Object. Por
ejemplo, al declarar la siguiente clase anteriormente en esta lección:
class Polygon
{
public double Length { get; protected set; }
public double Width { get; protected set; }
}
era funcionalmente equivalente a la siguiente declaración:
class Polygon: Object
{
public double Length { get; protected set; }
public double Width { get; protected set; }
}
52 | Lección 2
Sin embargo, no es obligatorio declarar la clase Polygon de esta última forma, pues la herencia
de la clase Object se da por supuesta implícitamente. Como parte de esta herencia, una clase
derivada puede invalidar los métodos de la clase Object. A continuación se muestran dos de
los métodos más comunes para hacerlo:
• Equals: Admite la comparación entre dos objetos y devuelve true si ambos tienen el
mismo valor.
• ToString: Devuelve una representación de tipo string de la clase. De forma
predeterminada, devuelve el nombre completo de la clase. A menudo, resulta útil invalidar
este método para que devuelva una representación de tipo string del estado actual del
objeto.
En el ejemplo siguiente se muestra cómo invalidar el método ToString de la clase Rectangle:
class Rectangle: Polygon
{
public Rectangle(double length, double width)
{
Length = length;
Width = width;
}
public override double GetArea()
{
return Width * Length;
}
public override string ToString()
{
return String.Format(
“Width = {0}, Length = {1}”,
Width, Length);
}
}
Las clases derivadas tienen una relación de tipo “es un(a)” con su clase base. Por ejemplo,
podemos decir que el rectángulo (Rectangle) “es un” polígono (Polygon). Por lo tanto, en
este caso un objeto de la clase Rectangle posee en realidad dos tipos de datos: el objeto es un
rectángulo y también el objeto es un polígono.
En C#, el runtime permite convertir un objeto en su clase o en cualquiera de sus clases base.
Por ejemplo, podemos escribir:
Polygon p = new Rectangle(10, 20);
Aquí, se crea un nuevo objeto Rectangle y se convierte en su tipo base, Polygon. En C# no
se requiere ninguna sintaxis especial para hacer esto, porque la conversión en el tipo base se
considera una conversión segura.
También es posible efectuar la conversión en sentido inverso. Por ejemplo, podemos escribir:
Object o = new Rectangle(10, 20);
…
Introducción a la programación orientada a objetos | 53
Rectangle r = (Rectangle) o;
Aquí, primero se asigna un objeto Rectangle a una clase Object (la clase base última) y se
realiza la conversión inversa del objeto resultante en Rectangle. Cuando se produce esta última
asignación, se requiere una conversión explícita porque estamos convirtiendo un objeto más
general en uno menos general. El runtime comprueba si el valor de la variable o es compatible
con la clase Rectangle. Si, al realizar la ejecución, el valor de o no es compatible con la clase
Rectangle, el runtime iniciará la excepción System.InvalidCastException.
Estamos desarrollando una aplicación que permite a los usuarios trabajar con diferentes
tipos de polígonos. Tenemos una colección que contiene varios tipos de polígonos, como un
rectángulo, un triángulo y un cuadrado. Cada polígono proporciona su propia implementación
del método Draw. Al trabajar con esta colección, no sabemos necesariamente con qué forma
estamos trabajando. Sin embargo, deseamos que cada vez se invoque el método Draw correcto.
Esto es precisamente lo que permite hacer el polimorfismo.
54 | Lección 2
El polimorfismo permite tratar los objetos de una clase determinada como objetos de la
clase base en tiempo de ejecución. Cuando un método se invoca en tiempo de ejecución, se
identifica su tipo exacto y se invoca el método apropiado a partir de su clase derivada.
USE el proyecto guardado en el ejercicio anterior para llevar a cabo los pasos siguientes:
1. Modifique la clase Polygon como se muestra a continuación:
class Polygon
{
public virtual void Draw()
{
Console.WriteLine(“Dibujo: Polygon”);
}
}
2. Modifique la clase Rectangle como se muestra a continuación:
class Rectangle: Polygon
{
public override void Draw()
{
Console.WriteLine(“Dibujo: Rectangle”);
}
}
3. Agregue una nueva clase denominada Triangle, como se muestra a continuación:
class Triangle: Polygon
{
public override void Draw()
{
Console.WriteLine(“Dibujo: Triangle”);
}
}
4. Modifique el método Main como sigue:
static void Main(string[] args)
{
List<Polygon> polygons = new List<Polygon>();
polygons.Add(new Polygon());
polygons.Add(new Rectangle());
polygons.Add(new Triangle());
Introducción a la programación orientada a objetos | 55
Cuando una clase base define un miembro virtual, la clase derivada tiene dos opciones para
controlarlo; en concreto, puede usar la palabra clave override o la palabra clave new. La
palabra clave override tiene prioridad sobre la definición de la clase base del miembro. En este
caso, el objeto de la clase derivada llamará al miembro invalidado en lugar de al miembro de
la clase base.
En cambio, si se usa la palabra clave new, se creará una nueva definición del miembro y se
ocultará el miembro de la clase base. Sin embargo, si la clase derivada se convierte en una
instancia de la clase base, será posible llamar a los miembros ocultos de la clase.
56 | Lección 2
Para entender mejor estos conceptos, modificaremos el método de Triangle del ejercicio
TOME NOTA
* anterior, como sigue:
Si el método de la clase
derivada no va precedido class Triangle: Polygon
por la palabra clave new {
u override, el compilador public new void Draw()
emitirá una advertencia y
el método se comportará {
como si la palabra clave Console.WriteLine(“Dibujo: Triangle”);
new estuviera presente. }
}
A continuación, modifique el código de la clase Main, así:
Triangle t = new Triangle();
t.Draw();
Polygon p = t;
p.Draw();
El programa producirá la salida siguiente:
Dibujo: Triangle
Dibujo: Polygon
LISTO PARA CERTIFICACIÓN Aquí, cuando se invoca directamente el método Draw para el objeto de la clase derivada, se
¿Comprende el usa la nueva versión del método. Sin embargo, si el método se ejecuta cuando la clase derivada
polimorfismo? se convierte en una clase base, se ejecuta la versión del método Draw de la clase base oculta.
2.3
La clase System.Object proporciona un método ToString. Por convención, se debe usar este
método para devolver la representación de una clase en el lenguaje natural. Al crear tipos, es
TOME NOTA
* aconsejable invalidar este método para devolver información legible sobre los objetos.
Las interfaces se usan para establecer contratos en virtud de los cuales los objetos pueden
CONCLUSIÓN interactuar entre sí sin conocer los detalles de implementación.
Las interfaces se definen mediante el uso de la palabra clave interface. Una definición de
TOME NOTA
* interfaz consta de un conjunto de signaturas de métodos, propiedades, delegados, eventos o
Por convención, todas indizadores. Una definición de interfaz no puede constar de campos de datos ni detalles de
las interfaces definidas implementación, como los cuerpos de los métodos.
en .NET Framework
comienzan con una letra Una interfaz común que se define en el espacio de nombres System es el espacio de nombres
I mayúscula. Aunque IComparable. Se trata de una interfaz simple, que se define como sigue:
cada desarrollador puede
interface IComparable
asignar a sus interfaces
el nombre que desee, {
es preferible respetar int CompareTo(object obj);
la convención de .NET }
Framework.
Introducción a la programación orientada a objetos | 57
La interfaz IComparable tiene un método único (CompareTo) que acepta un objeto y devuelve
un valor de tipo int. El valor devuelto por este método indica el resultado de comparar el
parámetro dado con el objeto actual. Según la documentación del método CompareTo:
• Si la instancia es igual al parámetro, CompareTo devuelve 0.
• Si el valor del parámetro es menor que la instancia o si el parámetro es null, se devuelve
un valor positivo.
• Si el valor del parámetro es mayor que el de la instancia, se devuelve un valor negativo.
• Si el parámetro no es del tipo compatible, se iniciará una excepción ArgumentException.
¿Cómo decide IComparable cómo comparar dos objetos Rectangle o dos objetos Employee?
No lo hace. Cuando se desee realizar tales comparaciones, las clases implicadas deberán
implementar la interfaz IComparable proporcionando un cuerpo de método para el método
CompareTo. Si se desea, es posible proporcionar, dentro del método CompareTo, la lógica
personalizada propia de cada clase que implementa IComparable.
USE el proyecto guardado en el ejercicio anterior para llevar a cabo los pasos siguientes:
1. Modifique la clase Rectangle como se muestra a continuación:
class Rectangle: Polygon, IComparable
{
public double Length { get; set; }
public double Width { get; set; }
public override void Draw()
{
Console.WriteLine(“Dibujo: Rectangle”);
}
public double GetArea()
{
return Length * Width;
}
public int CompareTo(object obj)
{
if (obj == null)
return 1;
if (!(obj is Rectangle))
throw new ArgumentException();
Rectangle target = (Rectangle)obj;
double diff = this.GetArea() - target.GetArea();
58 | Lección 2
if (diff == 0)
return 0;
else if (diff > 0)
return 1;
else return -1;
}
}
3. A continuación, modifique el método Main como se muestra a continuación:
static void Main(string[] args)
{
Rectangle rect1 = new Rectangle
{ Length = 10, Width = 20 };
Rectangle rect2 = new Rectangle
{ Length = 100, Width = 200 };
Console.WriteLine(rect1.CompareTo(rect2));
}
4. Seleccione Depurar > Iniciar sin depurar. Aparecerá una ventana de consola que
mostrará el valor –1 porque el área de rect1 es menor que el área de rect2.
5. GUARDE el proyecto.
En este caso, la clase Rectangle se deriva de la clase Polygon e implementa la interfaz
IComparable. Una clase que implementa una interfaz debe implementar todos los métodos
declarados en esa interfaz.
Una interfaz es semejante a una clase abstracta, aunque con algunas diferencias notables. Por
un lado, una clase abstracta proporciona una implementación incompleta, mientras que una
interfaz no proporciona ninguna implementación. Además, una clase puede implementar varias
interfaces pero está limitada a heredar de una sola clase base.
Entonces, ¿cómo se decide entre usar una interfaz o una clase abstracta? Una forma consiste
en comprobar si existe una relación de tipo “es un(a)” entre los dos conceptos. Por ejemplo,
LISTO PARA CERTIFICACIÓN si existe una relación de herencia entre SalariedEmployee (empleado asalariado) y Employee
¿Comprende la (empleado), se puede usar una clase abstracta para estandarizar la funcionalidad común
encapsulación? de las clases derivadas. En cambio, no existe ninguna relación de tipo “es un(a)” entre un
2.4 empleado y la interfaz IComparable. Por lo tanto, es preferible implementar la funcionalidad
de comparación como una interfaz.
RESUMEN DE CONOCIMIENTOS
• La palabra clave this se puede usar para obtener acceso a los miembros desde el
interior de los constructores, los métodos de instancia y los descriptores de acceso de
las propiedades de instancia.
• Los delegados son tipos especiales que se usan para encapsular un método con una
signatura específica.
• Los eventos son un medio para que una clase notifique a otras clases u objetos
que ha sucedido algo de interés. La clase que envía una notificación se denomina
publicador del evento y la que recibe la notificación, suscriptora del evento.
• Un espacio de nombres permite organizar el código y crear nombres de clase únicos.
• La palabra clave static se usa para declarar miembros que no pertenecen a objetos
individuales, sino a una clase en sí.
• Un tipo de valor almacena directamente un valor, mientras que un tipo de referencia
solo almacena una referencia al valor propiamente dicho.
• La palabra clave struct se usa para crear tipos definidos por el usuario que consisten
en pequeños grupos de campos relacionados. Los structs son tipos de valor, mientras
que las clases son tipos de referencia.
• La encapsulación es un mecanismo orientado a restringir el acceso a una clase o a
miembros de una clase para ocultar las decisiones de diseño que probablemente
estén sujetas a cambios. La encapsulación proporciona a los diseñadores de clases la
flexibilidad necesaria para cambiar una sección de código cuando es preciso sin tener
que cambiar los demás elementos de código que hacen uso de ese código.
• Un modificador de acceso especifica qué región del código tendrá acceso a un
campo. Por ejemplo, un modificador de acceso público no limita el acceso, pero un
modificador de acceso privado lo limita a aquella clase en la que está definido el
campo.
• La herencia permite crear nuevas clases que reutilizan, amplían y modifican la
funcionalidad definida en las clases existentes. La clase que hereda la funcionalidad
se denomina clase derivada y aquella cuya funcionalidad se hereda se denomina
clase base.
• El polimorfismo es la posibilidad de que las clases derivadas compartan
funcionalidades comunes con las clases base pero puedan definir su propio
comportamiento.
• La palabra clave override reemplaza un miembro de la clase base en una clase
derivada. La palabra clave new crea un nuevo miembro con el mismo nombre en la
clase derivada y oculta la implementación de la clase base.
■ Evaluación de conocimientos
Rellene los espacios en blanco
Complete las oraciones siguientes escribiendo la palabra o palabras correctas en los
espacios en blanco proporcionados.
1. Un(a) __________ es una plantilla de un objeto.
2. Una clase que no proporciona una implementación completa se debe declarar con la
palabra clave __________.
3. Las clases para las que se desean admitir las comparaciones deben implementar la
interfaz IComparable y después proporcionar un cuerpo para el método __________.
4. Se puede usar el operador __________ para comprobar si es válido convertir un tipo en
otro tipo.
60 | Lección 2
Varias opciones
Rodee con un círculo la letra correspondiente a la mejor respuesta.
1. Desea restringir el acceso a un método de la clase contenedora o a una clase que
se deriva de la clase contenedora. ¿Qué modificador de acceso debe usar para este
método?
a. public
b. private
c. protected
d. internal
2. En una clase, hemos definido un método denominado Render. Este método
proporciona funcionalidades para representar archivos de mapa de bits en la
pantalla. Desea que las clases derivadas sustituyan esta funcionalidad para admitir
la representación de otros formatos de imagen adicionales. También desea que se
ejecute el método Render de las clases derivadas, aunque una clase derivada se
convierta en la clase base. ¿Qué palabra clave debe usar con la definición del método
Render en la clase base?
a. abstract
b. virtual
c. new
d. overrides
3. Se ha definido la clase AdvMath, que define la funcionalidad matemática avanzada.
No desea que la funcionalidad de esta clase se herede en las clases derivadas. ¿Qué
palabra clave debe usar para definir la clase AdvMath?
a. sealed
b. abstract
c. private
d. internal
4. Debe proporcionar funcionalidad de consulta para varias de sus clases.
Probablemente, el algoritmo de la consulta será diferente en cada clase. Además, no
todas las clases tienen relaciones de tipo “es un(a)” entre sí. ¿Qué debe hacer para
admitir esta funcionalidad?
a. Se agrega la funcionalidad de consulta a una clase base con el modificador de
acceso public.
b. Se procura que todas las clases hereden de una clase base abstracta y se invalida
el método de la clase base para que cada una proporcione su propia funcionalidad
de consulta.
c. Se procura que todas las clases hereden de una clase base que proporcione la
funcionalidad de consulta.
d. Se crea una interfaz común que se implementa en todas las clases.
Introducción a la programación orientada a objetos | 61
5. ¿Cuál de los siguientes elementos de clase debe usar para definir el comportamiento
de una clase?
a. Método
b. Propiedad
c. Evento
d. Delegado
6. Está escribiendo código para una clase denominada Product. Debe asegurarse de
que los miembros de datos de la clase se inicialicen en los valores correctos tan
pronto como se cree un objeto de la clase Product. El código de inicialización debe
ejecutarse siempre. ¿Qué debe hacer?
a. Crear un método static en la clase Product para inicializar los miembros de datos.
b. Crear un constructor en la clase Product para inicializar los miembros de datos.
c. Crear una propiedad static en la clase Product para inicializar los miembros de
datos.
d. Crear un evento en la clase Product para inicializar los miembros de datos.
7. Está creando una nueva clase denominada Square que se deriva de la clase Polygon.
La clase Polygon tiene el siguiente código:
class Polygon
{
public virtual void Draw()
{
// código adicional. . .
}
}
El método Draw de la clase Square debe proporcionar nueva funcionalidad, pero
también ocultar la implementación de la clase Polygon del método Draw. ¿Qué
segmento de código debe usar para lograr este objetivo?
a. class Square: Polygon
{
public override void Draw()
{
// código adicional. . .
}
}
b. class Square: Polygon
{
public new void Draw()
{
// código adicional. . .
}
}
c. class Square: Polygon
{
public virtual void Draw()
{
// código adicional. . .
}
}
62 | Lección 2
■ Evaluación de competencias
Escenario 2-1: Creación de propiedades
Debe crear una clase denominada Product que representa un producto. La clase tiene una sola
propiedad, denominada Name. Los usuarios de la clase Product deben poder obtener y también
definir el valor de la propiedad Name. Sin embargo, cualquier intento de establecer el valor de
Name en una cadena vacía o un valor null debe iniciar una excepción. Además, los usuarios
de la clase Product no deben tener la capacidad de obtener acceso a ningún otro miembro de
datos de la clase Product. ¿Cómo se puede crear dicha clase?
■ Evaluación de aptitudes
Escenario 2-1: Invalidación del método ToString
Supongamos que estamos escribiendo código para una clase Product. La clase Product
contiene el nombre y el precio de un producto. Debe invalidar el método ToString de la
clase base (System.Object) de modo que proporcione información sobre los objetos de la
clase Product al código de llamada. ¿Qué código debe escribir para la clase Product a fin de
satisfacer este requisito?
TÉRMINOS CLAVE
administración de versiones estructuras de datos pruebas de integración
administración del ciclo de vida lista de vínculo pruebas de regresión
de las aplicaciones (ALM) matrices pruebas de software
algoritmos de ordenación pila pruebas del sistema
análisis de requisitos proceso de diseño pruebas unitarias
BubbleSort pruebas de aceptación QuickSort
cola pruebas de caja blanca
desarrollo de software pruebas de caja negra
65
66 | Lección 3
En esta sección, conoceremos mejor los diferentes roles y actividades correspondientes a cada
fase del proceso de ALM.
El ciclo de vida de una aplicación se inicia cuando se identifica la necesidad de una nueva
aplicación de software. Normalmente, el director general del negocio es quien patrocina el
proyecto. Esta persona analiza la necesidad, comprueba en qué medida encaja el proyecto en
la estrategia de negocio global, organiza el financiamiento e inicia el proceso de dotación de
personal para el proyecto.
Probablemente, la primera persona a quien contratará el director general será el jefe de
proyecto. El jefe de proyecto es responsable de la ejecución global del proyecto. Sus
principales responsabilidades consisten en asegurarse de que el proyecto no se salga del
presupuesto y se finalice a tiempo. El jefe de proyecto también es responsable de contratar a
los miembros del equipo y de facilitar la cooperación en el seno del equipo.
El análisis de requisitos es uno de los pasos más importantes del ciclo de vida de una
aplicación. Contar con requisitos precisos, completos y bien documentados es fundamental
para el éxito del proyecto. Estos requisitos pueden ser funcionales o no funcionales. Los
requisitos funcionales especifican exactamente qué tareas deberá realizar el sistema.
En cambio, los requisitos no funcionales son aquellos relativos a la calidad, tales como
escalabilidad, seguridad, confiabilidad, etc.
Un analista de negocios es responsable de analizar las necesidades empresariales y convertirlas
en requisitos que el equipo de desarrollo pueda satisfacer.
El proceso de diseño genera especificaciones técnicas detalladas que se usarán para desarrollar
el sistema. La salida del proceso de diseño es un conjunto de modelos y especificaciones
técnicos que orientarán a los desarrolladores y a los demás miembros del equipo durante la
actividad de desarrollo del software. La salida del proceso de diseño es más abstracta y menos
concreta. En este punto, no existe ningún sistema real con el que se pueda interactuar.
Algunos de los participantes más importantes de esta fase del proceso de ALM son el
arquitecto y el diseñador de la experiencia del usuario:
• Arquitecto: un arquitecto diseña los planos técnicos del sistema. Esto incluye identificar
los componentes y servicios, su comportamiento y las interacciones entre ellos y con el
mundo exterior.
• Diseñador de la experiencia del usuario: un diseñador de la experiencia del usuario
crea la experiencia del usuario con el sistema. Esto incluye diseñar los elementos de la
interfaz de usuario (IU); diseñar la navegación entre los diversos formularios, pantallas o
páginas; etc.
El desarrollo de software es la parte del proceso de ALM en que se aplican los requisitos de
negocio en el código de trabajo, basándose en el diseño elaborado durante la actividad anterior.
Al final de esta actividad, se dispone de una salida concreta que consiste en un sistema de
software con el que los usuarios pueden interactuar.
Los participantes fundamentales de la fase de desarrollo de software son:
• Desarrolladores: los desarrolladores escriben código basado en los requisitos recopilados
por el analista de negocios, en la arquitectura elaborada por el arquitecto y la experiencia
del usuario desarrollada por el diseñador de la experiencia del usuario.
• Administradores de bases de datos (DBA): los DBA son responsables de implementar
y mantener las bases de datos del software. Los DBA también planean la integridad,
seguridad y velocidad de los datos.
• Escritores técnicos: los escritores técnicos elaboran los manuales del sistema y los
archivos de ayuda que se entregarán con la aplicación.
• Desarrolladores de contenido: los desarrolladores de contenido son expertos en la
materia que desarrollan el contenido para el sistema. Por ejemplo, si la aplicación es
un sitio web de críticas de películas, no bastará con implementar el sitio web, sino que
además será preciso asegurarse de que este contenga contenido suficiente para suscitar
interés en los usuarios.
68 | Lección 3
Durante las pruebas de software se comprueba que la aplicación coincida con los
requisitos del sistema.
Las pruebas de software se usan para garantizar la calidad del producto final. Las pruebas
pueden identificar posibles diferencias entre las expectativas respecto al sistema descritas en el
documento de requisitos y el comportamiento real del sistema.
Entre los participantes más importantes de la actividad de pruebas de software se encuentran
los evaluadores, que comprueban la aplicación de trabajo para asegurarse de que satisface
las necesidades identificadas. Cuando estos evaluadores identifican cualquier defecto en la
aplicación, se lo asignan a la persona adecuada para que lo arregle. Por ejemplo, un defecto del
código se asignaría a un desarrollador para que lo subsanase.
Las pruebas de software consisten en comprobar el software en relación con sus requisitos.
CONCLUSIÓN Las pruebas se llevan a cabo después de completar la mayor parte del trabajo de desarrollo.
Como hemos mencionado anteriormente, las pruebas de software consisten en comprobar que
una aplicación de software funciona tal y como se esperaba y satisface todos los requisitos
de negocios y técnicos. Cuando existe una diferencia entre los comportamientos esperado y
real del sistema, se registra un defecto de software (o “error”) que se asigna a una persona
responsable de corregirlo.
Las pruebas de software pueden incluir pruebas funcionales y no funcionales. Las pruebas
funcionales se refieren a los requisitos funcionales del sistema y comprueban las características
que conforman la funcionalidad básica del sistema. Por ejemplo, comprobar si los usuarios
pueden agregar elementos al carro de la compra constituye una parte importante de las pruebas
Conceptos generales del desarrollo de software | 69
funcionales de un sitio web de comercio electrónico. Por su parte, las pruebas no funcionales
se refieren a comprobar los atributos de software que no forman parte de la funcionalidad
básica, sino de los requisitos no funcionales del software, tales como la usabilidad, la
escalabilidad o la seguridad.
Es importante señalar que el proceso de las pruebas de software solo puede ayudar a
encontrar defectos pero no puede garantizar la ausencia de estos. Todo software complejo
posee un gran número de rutas de ejecución posibles y gran cantidad de parámetros que
*
TOME NOTA
pueden afectar a su comportamiento. No es viable ni, con frecuencia, posible, probar todas
las situaciones diferentes que se le presentarán a ese software en un entorno de producción.
Los métodos de las pruebas de software se suelen dividir en dos categorías: pruebas
de caja blanca y pruebas de caja negra.
Las pruebas se llevan a cabo en diferentes fases del ciclo de vida de desarrollo de las
aplicaciones. Los distintos niveles de pruebas especifican en qué punto del ciclo de
vida se lleva a cabo una prueba concreta y qué tipo de prueba se ha de efectuar.
Los niveles de pruebas se definen en función del momento del ciclo de vida del desarrollo de
software en que tienen lugar las pruebas. Existen cinco niveles de pruebas distintos:
• Pruebas unitarias: las pruebas unitarias comprueban la funcionalidad de una unidad de
código. Por ejemplo, una prueba unitaria puede evaluar si un método devuelve el valor
correcto. Las pruebas unitarias son de caja blanca y con frecuencia las realiza el propio
desarrollador que está escribiendo el código. Para las pruebas unitarias se suele usar
una herramienta automatizada que simplifica el desarrollo de casos y también realiza
el seguimiento por si una modificación del código provoca que no se supere alguna de
las pruebas unitarias existentes. Visual Studio presenta compatibilidad integrada con las
pruebas unitarias. También se pueden usar herramientas de código abierto como NUnit
para automatizar las pruebas unitarias del código de .NET Framework.
• Pruebas de integración: las pruebas de integración evalúan las interfaces entre los com-
70 | Lección 3
Las estructuras de datos son técnicas que permiten organizar y almacenar datos en la
memoria del equipo. El modo en que se almacenan los datos afecta a su recuperación
CONCLUSIÓN y manipulación. Para comprender una estructura de datos no solo es preciso entender
el patrón de almacenamiento, sino también saber qué métodos se usan para crear la
estructura de datos, obtener acceso a ella y manipularla.
Las estructuras de datos son los bloques de creación de la mayoría de los programas y
permiten a los desarrolladores implementar funcionalidades complejas. La mayoría de los
entornos de programación proporcionan compatibilidad integrada con gran variedad de
estructuras de datos y métodos asociados para manipularlas. En esta sección, conoceremos
varios tipos de estructuras de datos diferenciados, a fin de familiarizarnos con las técnicas
generales que nos permiten manipularlas.
Una matriz es una estructura de datos común que representa una colección de elementos de
tipo similar. Los elementos de una matriz se almacenan en ubicaciones de memoria contiguas.
Una matriz es una estructura de datos homogénea porque todos los elementos que contiene
son del mismo tipo de datos. A cualquier elemento de la matriz se puede obtener acceso
directamente mediante un índice. En .NET Framework, los índices de las matrices son de base
cero.
REPRESENTACIÓN INTERNA
En el código siguiente, la primera instrucción crea una variable de matriz y la segunda
inicializa la variable con una matriz de cuatro enteros:
int[] numbers;
numbers = new int[4];
Al principio, los números de la variable se establecen en null porque la matriz todavía no se
ha inicializado. Sin embargo, la segunda instrucción inicializa la matriz mediante la asignación
de un espacio de memoria contigua lo bastante grande para almacenar cuatro enteros en el
montón de memoria. La dirección inicial de la asignación de memoria se almacena en la
Figura 3-2
Representación interna de
una estructura de datos de
matriz
variable de matriz numbers, como se muestra en la figura 3-2. Todos los elementos de la
matriz se inicializan en este caso con el valor 0, que es el valor predeterminado para un entero.
A continuación, la variable numbers actúa como referencia a la ubicación de memoria asignada
a la matriz. El nombre de la matriz se puede usar para obtener acceso directamente a cada
uno de los elementos de la matriz. En .NET Framework, todas las matrices son de base cero;
es decir, al primer elemento de la matriz se obtiene acceso mediante el índice numbers[0], al
segundo mediante numbers[1] y así sucesivamente.
También es posible usar matrices multidimensionales. Podemos imaginarnos una matriz
bidimensional como una tabla en la que cada celda es un elemento de la matriz, que puede
direccionarse mediante los números de la fila y la columna a las que pertenece. Tanto
el número de fila como el número de columna se indizan con base cero. Por ejemplo, la
expresión table[2, 3] haría referencia a un elemento de la tercera fila y la cuarta columna de
una matriz denominada table.
OPERACIONES COMUNES
Las matrices admiten las siguientes operaciones:
• Asignación
• Acceso
Para trabajar con una matriz, en primer lugar se asigna la memoria. Para ello, es preciso crear
e inicializar la matriz como hemos mostrado anteriormente. Una vez realizada la asignación,
se puede obtener acceso a cualquier elemento de la matriz en cualquier orden que se desee
mediante una referencia directa a su índice. Por ejemplo, el código siguiente asigna el valor
10 al cuarto elemento de la matriz y, a continuación, asigna el doble de ese valor a la variable
calc:
number[3] = 10;
int calc = number[3] * 2;
72 | Lección 3
RENDIMIENTO Y USO
El contenido de una matriz se presenta como un bloque de memoria contiguo al que se puede
obtener acceso directamente mediante el índice de la matriz. Por lo tanto, leer una matriz y
escribir en ella son operaciones sumamente rápidas. Sin embargo, las matrices están limitadas
por sus requisitos de homogeneidad y tamaño fijo. Aunque se puede aumentar el tamaño de
una matriz, para hacerlo es preciso reasignar todos sus elementos y esta operación requiere
mucho tiempo.
Las matrices funcionan mejor cuando el número de elementos de la colección es una cantidad
predeterminada y se requiere un acceso veloz y directo a cada elemento.
En .NET Framework, se puede usar la clase ArrayList para eludir los requisitos de tamaño fijo
y homogeneidad de una matriz. ArrayList es un tipo de colección que puede contener objetos
de cualquier tipo de datos y ampliarse dinámicamente cuando sea necesario. Sin embargo,
ArrayList no resulta tan rápida de usar como una matriz.
La estructura de datos de una cola imita las colas de la vida real. En una cola, los elementos
se procesan en el orden en que se agregaron a ella. En concreto, los elementos siempre se
agregan al final de la cola y se retiran del principio. Este tipo de procesamiento se denomina
de tipo primero en entrar, primero en salir (FIFO). La capacidad de una cola se refiere al
número de elementos que puede contener. Sin embargo, a medida que se agregan elementos
a la cola, su capacidad se aumenta automáticamente. Una cola es también una estructura de
datos heterogéneos, lo que significa que sus elementos pueden ser de diferentes tipos de datos.
REPRESENTACIÓN INTERNAL
Para evitar una excesiva reasignación de espacio de memoria y facilitar su administración,
las colas suelen implementarse internamente como matrices circulares de objetos, como se
muestra en la figura 3-3.
Figura 3-3
Representación interna de
una estructura de datos de
cola
Dentro de una cola, el índice del principio señala al primer elemento y el índice del final
señala al último elemento. En la figura 3-3, por ejemplo, el índice del principio señala a la
ubicación 2 de la cola. Como la cola es circular, siempre y cuando se realice el seguimiento de
los punteros del principio y el final no importará en qué ubicación comience la cola. Cuando
se quita un elemento, el principio se mueve al siguiente elemento de la cola. Cuando se agrega
un nuevo elemento, siempre aparece al final de la cola y el final señala al elemento recién
agregado. Las ranuras null de una cola (tales como las representadas en la figura 3-3) son los
lugares vacíos disponibles para llenarlos antes de que la cola requiera una reasignación de
memoria.
Conceptos generales del desarrollo de software | 73
RENDIMIENTO Y USO
Una cola es una estructura de datos de uso especial, adecuada principalmente para aplicaciones
en que se requiere procesar los elementos en el orden en que se reciben. Algunos ejemplos
de ello son las colas de impresión, los sistemas de mensajería y programadores de trabajos.
A diferencia de una matriz, una cola no puede usarse para obtener acceso a los elementos de
manera aleatoria. Las operaciones como Enqueue y Dequeue agregan y quitan realmente los
elementos de la cola.
En contraposición a las colas, las pilas son estructuras de datos de tipo último en entrar,
primero en salir (LIFO). Podemos plantearnos una pila como una estructura semejante a una
serie de platos apilados sobre una mesa de un bufé; el último plato que se agrega es el primero
que se retira. La capacidad de la pila se refiere al número de elementos que puede contener.
Sin embargo, a medida que se agregan elementos a la pila, su capacidad se incrementa
automáticamente. Una pila es una estructura de datos heterogéneos, lo que significa que los
elementos que contiene pueden ser de diferentes tipos de datos.
REPRESENTACIÓN INTERNA
Al igual que una cola, una pila se suele implementar como un búfer circular a fin de evitar
una excesiva reasignación de espacio de memoria y facilitar su administración. Podemos
imaginarnos una pila con el mismo aspecto que se muestra en la figura 3-3, con la salvedad de
que el final es lo que ahora denominamos la parte superior de la pila y el principio es lo que
denominamos la parte inferior de la pila.
Los elementos nuevos siempre se agregan a la parte superior de la pila. Cuando esto sucede,
la parte superior de la pila comienza a señalar al elemento recién agregado. Los elementos
también se quitan de la parte superior de la pila; cuando eso sucede, la parte superior de la pila
se ajusta de modo que señale al siguiente elemento de la pila.
74 | Lección 3
RENDIMIENTO Y USO
Una pila es una estructura de datos de uso especial, adecuada principalmente para aplicaciones
en que se requiere procesar los elementos según el principio de primero en entrar, primero
en salir. Las pilas son estructuras útiles debido a sus aplicaciones en la administración de
la memoria en tiempo de ejecución, evaluación de expresiones, seguimiento de llamadas a
métodos, etc. A diferencia de las matrices, las pilas no se pueden usar para obtener acceso a los
elementos de forma aleatoria. Las operaciones como Push y Pop agregan y quitan realmente
los elementos de la pila.
Listas de vínculo
Una lista de vínculo es una colección de nodos organizados de modo que cada uno
de ellos contenga un vínculo al nodo siguiente de la secuencia.
Una lista de vínculo es una colección de nodos donde cada nodo contiene una referencia (o
vínculo) al nodo siguiente de la secuencia. A diferencia de una matriz, no es necesario que los
elementos de una lista de vínculo sean contiguos, de modo que esta última no requiere que se
reasigne el espacio de memoria de toda la lista para poder agregar más vínculos.
REPRESENTACIÓN INTERNA
En la memoria, una lista de vínculo puede visualizarse como una colección de nodos, como se
muestra en la figura 3-4.
Figura 3-4
Representación interna de
una estructura de datos de
lista de vínculo simple
Conceptos generales del desarrollo de software | 75
Cada nodo de una lista de vínculo contiene dos datos: la información correspondiente al
nodo y el vínculo al siguiente nodo. El primer nodo de la lista se denomina nodo principal.
Mediante el vínculo del nodo principal, se puede llegar al siguiente nodo y seguir atravesando
los nodos hasta que el último vínculo sea un valor null. A menudo, se usa el término final para
referirse a la lista a la que señala el primer nodo; es decir, se refiere a todo lo que aparece
después del nodo principal. Así pues, en la figura 3-4, el final es la lista de vínculo que
empieza en el nodo B.
Se pueden usar otras implementaciones de listas de vínculo en función de los requisitos. Por
ejemplo, en una lista de vínculo circular, el último nodo de la lista señala al primero, para
crear un círculo. En cambio, en una lista de doble vínculo, cada nodo contiene dos vínculos,
como se muestra en la figura 3-5.
Figura 3-5
Representación interna de
una estructura de datos de
lista de doble vínculo
En cada nodo de una lista de doble vínculo, un vínculo es una referencia adelantada que señala
al siguiente nodo de la secuencia y el otro es una referencia regresiva que señala al nodo
anterior de la secuencia. Como podemos imaginar, una lista de doble vínculo resulta fácil de
cruzar en cualquier dirección.
.NET Framework proporciona una clase LinkedList como parte del espacio de nombres
System.Collections.Generic. Esta clase implementa una lista de doble vínculo homogénea del
tipo de datos especificado. El desarrollador también puede escribir sus propias clases para
implementar un tipo diferente de lista de vínculo.
OPERACIONES COMUNES
Una lista de vínculo admite las siguientes operaciones comunes:
• Add: la operación Add (agregar o insertar) en una lista de vínculo consiste en cambiar los
vínculos, como se muestra en la figura 3-6. Supongamos que vamos a insertar un nuevo
nodo (con el valor Z) entre los nodos con los valores A y B. En primer lugar, es preciso
asignar memoria para el nuevo nodo y asignarle el valor Z a la sección de datos del nodo.
A continuación, será preciso copiar la sección de vínculo del nodo A a la sección de
vínculo del nodo Z, para que este último señale al nodo B. Por último, habrá que copiar
Figura 3-6
Adición de un nuevo nodo a
una lista de vínculo
76 | Lección 3
la dirección del nodo Z recién creado en la sección de vínculo del nodo A, para que este
empiece a señalar al nodo Z.
• Remove: de modo parecido a la operación Add, la operación Remove (quitar o eliminar)
también consiste en cambiar los vínculos. Por ejemplo, para eliminar el tercer nodo de la
figura 3-4, será preciso cambiar el vínculo del segundo nodo por un valor null. El tercer
nodo se convertirá en una ubicación de memoria sin referencia y, en última instancia, se
devolverá al bloque de memoria disponible.
• Find: la operación Find (buscar) halla el nodo con el valor dado en la lista de vínculo.
Para encontrar un valor, generalmente se comienza por el nodo principal y se comprueba
si el valor coincide. En caso negativo, se sigue el vínculo al siguiente nodo y se continúa
con la operación Find hasta alcanzar el final de la lista, lo que sucede cuando se encuen-
tra un vínculo null.
RENDIMIENTO Y USO
Una lista de vínculo no permite el acceso aleatorio a sus elementos. La única manera de
obtener un elemento consiste en empezar desde el nodo del principio y seguir los vínculos a
partir de él. En consecuencia, las listas de vínculo resultan lentas para recuperar datos. Sin
embargo, en las operaciones de inserción y eliminación, las listas de vínculo ofrecen una
velocidad excelente, porque para insertar o eliminar un nodo solo hay que cambiar un vínculo.
Por otro lado, las listas de vínculo no presentan ninguna capacidad máxima a partir de la cual
deba reasignarse su contenido.
De hecho, una lista de vínculo proporciona una manera alternativa de implementar las
estructuras de datos de cola y pila. Si los requisitos exigen un acceso frecuente a los datos pero
LISTO PARA CERTIFICACIÓN
rara vez será preciso insertar o eliminar datos, una matriz es la implementación de elección.
¿Comprende las estructuras
En cambio, si los requisitos exigen operaciones frecuentes de inserción y eliminación,
de datos comunes?
posiblemente sea preferible usar una lista de vínculo.
3.2
Los algoritmos de ordenación son aquellos que organizan los elementos de una lista en un
orden determinado. Por ejemplo, podemos usarlos para ordenar una lista de alumnos de forma
ascendente en función de su apellido. En los albores del procesamiento de datos, la ordenación
era un problema importante al que se dedicaron muchos esfuerzos de investigación. En la
actualidad, encontramos la funcionalidad básica de ordenación ya integrada en las bibliotecas
y estructuras de datos más populares. Por ejemplo, en .NET Framework, podemos usar el
método Array.Sort para ordenar una matriz. Sin embargo, sigue siendo importante estudiar la
ordenación para comprender la resolución de problemas y el análisis de algoritmos.
En esta sección, estudiaremos dos algoritmos de ordenación de uso frecuente, BubbleSort y
QuickSort.
Conceptos de BubbleSort
Tabla 3-1
Primera pasada de Pasada Antes Después Comentarios
BubbleSort
1 20, 30, 10, 40 20, 30, 10, 40 El algoritmo compara los dos primeros
elementos (20 y 30); dado que están
en el orden correcto, no es necesario
intercambiarlos.
2 20, 30, 10, 40 20, 10, 30, 40 El algoritmo compara los dos
elementos siguientes (30 y 10);
puesto que están desordenados, se
intercambian.
3 20, 10, 30, 40 20, 10, 30, 40 El algoritmo compara los dos
elementos siguientes (30 y 40); como
están en el orden correcto, no es
necesario intercambiarlos.
Como se muestra en la tabla 3-1, al final del primer paso, BubbleSort ha realizado un
intercambio y existe la posibilidad de que los elementos sigan sin estar totalmente ordenados.
Por lo tanto, BubbleSort da otra pasada a la lista, como se muestra en la tabla 3-2.
Tabla 3-2
Segunda pasada de Pasada Antes Después Comentarios
BubbleSort
1 20, 10, 30, 40 10, 20, 30, 40 El algoritmo compara los dos primeros
elementos (20 y 10); dado que están
desordenados, se intercambian.
2 10, 20, 30, 40 10, 20, 30, 40 El algoritmo compara los dos
elementos siguientes (20 y 30); como
están en el orden correcto, no es
necesario intercambiarlos.
3 10, 20, 30, 40 10, 20, 30, 40 El algoritmo compara los dos
elementos siguientes (30 y 40); como
están en el orden correcto, no es
necesario intercambiarlos.
78 | Lección 3
Al final de la segunda pasada, BubbleSort ha realizado un intercambio más, así que todavía
no puede garantizar que la lista esté ordenada completamente. Por lo tanto, BubbleSort da otra
pasada a la lista, como se muestra en la tabla 3-3.
Tabla 3-3
Tercera pasada de Pasada Antes Después Comentarios
BubbleSort
1 10, 20, 30, 40 10, 20, 30, 40 El algoritmo compara los dos primeros
TOME NOTA
* elementos (10 y 20); dado que están
Cuando se usa en el orden correcto, no es necesario
BubbleSort, una intercambiarlos.
matriz se ordenará en 2 10, 20, 30, 40 10, 20, 30, 40 El algoritmo compara los dos
todos los casos en una elementos siguientes (20 y 30); como
pasada menos que el están en el orden correcto, no es
número de elementos. necesario intercambiarlos.
Así pues, si hay cuatro
elementos (como en el 3 10, 20, 30, 40 10, 20, 30, 40 El algoritmo compara los dos
escenario de ejemplo), elementos siguientes (30 y 40); como
la matriz se ordenará están en el orden correcto, no es
(con independencia del necesario intercambiarlos.
orden de partida) en tres
pasadas.
Al final de la tercera pasada, BubbleSort no ha realizado ningún intercambio. Esto garantiza
que ahora la lista está ordenada correctamente y el algoritmo puede finalizar.
En C#, el algoritmo BubbleSort se puede expresar mediante el método siguiente:
static int[] BubbleSort(int[] numbers)
{
bool swapped;
do
{
swapped = false;
for (int i = 0; i < numbers.Length − 1; i++)
{
if (numbers[i] > numbers[i + 1])
{
//intercambio
int temp = numbers[i + 1];
numbers[i + 1] = numbers[i];
numbers[i] = temp;
swapped = true;
}
}
} while (swapped == true);
return numbers;
}
Conceptos generales del desarrollo de software | 79
Conceptos de QuickSort
El algoritmo QuickSort usa operaciones de particionamiento y comparación para
organizar los elementos de una lista en el orden correcto.
Tabla 3-4
Visualización de QuickSort Pasada Datos que se van a ordenar Comentarios
1 50, 10, 30, 20, 40 S e comienza por una lista desordenada y se toma
un elemento de referencia; en este caso, 30.
2 20, 10 30 50, 40 Se crea una partición en la lista. Los elementos
menores que el elemento de referencia
se incluyen en la lista de la izquierda y
los mayores, en aquella de la derecha. A
continuación, para ordenar la lista de la
izquierda, se toma un elemento de referencia
(en este caso, el 10). De igual forma, para
ordenar la lista de la derecha, se toma un
elemento de referencia (en este caso, el 40)
para ordenarla.
3 - 10 20 30 - 40 50 E n la lista de la izquierda, 20 es mayor que
10; en la lista de la derecha, 50 es mayor que
40; por lo tanto, tanto 20 como 50 se llevan
a la lista de la derecha. Con ello se obtienen
listas de un solo número que, por definición,
siempre están ordenadas.
4 10, 20, 30, 40, 50 Todas las pequeñas listas ordenadas se
combinan para crear la lista ordenada final
completa.
Hasta ahora, podría parecer que el principal inconveniente del algoritmo QuickSort es la
cantidad de memoria adicional que se requiere para crear las pequeñas listas independientes.
Sin embargo, no es necesario crear estas listas independientes. Mediante una técnica
ligeramente modificada, las particiones de la matriz se pueden realizar in situ, como se
muestra en el siguiente listado de código:
static int Partition (int[] numbers, int left,
int right, int pivotIndex)
80 | Lección 3
{
int pivotValue = numbers[pivotIndex];
// mover el elemento de referencia al final
int temp = numbers[right];
numbers[right] = numbers[pivotIndex];
numbers[pivotIndex] = temp;
// newPivot almacena el índice del primero
// el número es mayor que el elemento de referencia
int newPivot = left;
for (int i = left; i < right; i++)
{
if (numbers[i] <= pivotValue)
{
temp = numbers[newPivot];
numbers[newPivot] = numbers[i];
numbers[i] = temp;
newPivot++;
}
}
//mover el elemento de referencia a su posición ordenada
temp = numbers[right];
numbers[right] = numbers[newPivot];
numbers[newPivot] = temp;
return newPivot;
}
Con esta técnica, primero se mueve el elemento de referencia al final de la matriz. Luego,
todos los elementos menores o iguales que él se mueven a la parte delantera de la matriz. Por
último, el elemento de referencia se sitúa justo antes del elemento mayor que sí mismo, con lo
que se crea una partición efectiva de la matriz.
Luego, QuickSort puede usar este algoritmo de particionamiento para dividir la lista, reducir el
problema a otros de menor tamaño y resolverlos recursivamente:
static int[] QuickSort(int[] numbers,
int left, int right)
{
if (right > left)
{
int pivotIndex = left + (right − left) / 2;
//particionamiento de la matriz
pivotIndex = Partition(
numbers, left, right, pivotIndex);
//ordenación de la partición izquierda
QuickSort(
numbers, left, pivotIndex − 1);
Conceptos generales del desarrollo de software | 81
RESUMEN DE CONOCIMIENTOS
■ Evaluación de conocimientos
Rellene los espacios en blanco
Complete las oraciones siguientes escribiendo la palabra o palabras correctas en los
espacios en blanco proporcionados.
1. En las pruebas de ______, los evaluadores aplican sus conocimientos del funcionamiento
interno del sistema mientras lo comprueban.
2. Generalmente, con cada corrección, los evaluadores de software llevan a cabo una batería
de ______ para asegurarse de que cada funcionalidad de la cual se tenía constancia de
que funcionaba correctamente siga de ese modo.
82 | Lección 3
3. El algoritmo BubbleSort usa una serie de operaciones de ______ e ______ para organizar
los elementos de una lista en el orden correcto.
4. Un(a) ______ es una colección de elementos en la que el último elemento que se agrega
es el primero que se quita.
5. El ______ es el proceso de definición pormenorizada de los requisitos empresariales de
un sistema de software nuevo.
6. Una lista de vínculo es una colección de nodos organizados de tal forma que cada uno de
ellos contiene un(a) ____ al siguiente nodo de la secuencia.
7. La operación ______ agrega un elemento a la cola y la operación ______ quita un
elemento de ella.
8. El algoritmo QuickSort usa operaciones de ______ y comparación para organizar los
elementos de una lista en el orden correcto.
9. Un(a) ______ es responsable de analizar las necesidades empresariales y convertirlas en
requisitos que el equipo de desarrollo pueda satisfacer.
10. Las pruebas alfa y beta forman parte de las pruebas de ______ de un sistema.
Varias opciones
Rodee con un círculo la letra correspondiente a la mejor respuesta.
1. El producto que está desarrollando aún no está terminado, pero le gustaría distribuirlo a
un público más amplio de clientes para realizar pruebas y obtener comentarios. ¿En cuál
de los siguientes niveles de pruebas encajaría esta actividad?
a. Pruebas de integración
b. Pruebas del sistema
c. Pruebas de aceptación
d. Pruebas de regresión
2. Los evaluadores de una aplicación de software tienen acceso a su código fuente y planean
escribir casos de prueba que garanticen que los métodos devuelvan valores correctos. ¿En
cuál de los siguientes niveles de pruebas figuraría esta actividad?
a. Pruebas de integración
b. Pruebas unitarias
c. Pruebas alfa
d. Pruebas beta
3. ¿Cuál de las siguientes estructuras de datos permite el acceso directo a todos sus elemen-
tos?
a. Matriz
b. Pila
c. Cola
d. Lista de vínculo
4. ¿Cuál de las siguientes actividades del ciclo de vida de las aplicaciones usa el arquitecto
para crear los planos técnicos de un sistema?
a. Análisis de requisitos
b. Diseño
c. Desarrollo
d. Mantenimiento
5. En su aplicación, usa una estructura de datos de cola para manipular la información.
Necesita encontrar qué elemento de datos se procesará a continuación, pero no desea pro-
cesarlo aún. ¿Cuál de las siguientes operaciones de cola debe usar?
a. Enqueue
b. Dequeue
c. Peek
d. Contains
Introducción a la programación orientada a objetos | 83
■ Evaluación de competencias
Escenario 3-1: Uso de matrices
Está escribiendo un programa que usa una matriz bidimensional. La matriz tiene cuatro filas y
cinco columnas. Debe imprimir el elemento mayor de cada fila de la matriz. ¿Cómo se escribe
tal programa?
84 | Lección 3
■ Evaluación de aptitudes
Escenario 3-3: Uso de pilas
Está escribiendo un programa que usa dos pilas. Los datos de cada pila ya están organizados
en orden descendente. Debe procesar el contenido de ambas pilas de manera tal que la salida
se muestre en la pantalla en orden ascendente. ¿Cómo se escribe tal programa?
TÉRMINOS CLAVE
administración de estado hospedaje de sitios web programación del lado servidor
administración de estado del Internet Information Protocolo simple de acceso a
lado cliente Services (IIS) objetos (SOAP)
administración de estado del JavaScript servicios web
lado servidor Lenguaje de marcado de sitio web
directorio virtual hipertexto (HTML) Web Service Description
hojas de estilos en programación del lado cliente Language (WSDL)
cascada (CSS)
Una página web es un documento que se presenta a través de la World Wide Web (WWW)
y que puede mostrarse en un explorador web. Las páginas web se desarrollan usando
CONCLUSIÓN el Lenguaje de marcado de hipertexto (HTML) y se almacenan en un servidor web.
Los exploradores web descargan el código HTML solicitado desde el servidor web y lo
representan en la pantalla del usuario.
85
86 | Lección 4
La World Wide Web (también denominada WWW o “la Web”) es un sistema de documentos
de hipertexto y otros recursos (como imágenes y vídeo) interconectados a los que se puede
obtener acceso a través de Internet. Para hacer posible la WWW, han de funcionar en
combinación varias tecnologías. En esta sección, analizaremos dos de estas tecnologías:
• Protocolo de transferencia de hipertexto (HTTP); y
• Lenguaje de marcado de hipertexto (HTML)
HTTP es el protocolo de comunicación subyacente que se usa en la World Wide Web. HTTP
proporciona el lenguaje común que usan los servidores y exploradores web para comunicarse.
HTTP usa un localizador uniforme de recursos (URL) para identificar de forma exclusiva y
direccionar cada recurso en Internet. Una dirección URL es esencialmente una dirección web
con este aspecto: http://www.microsoft.com/en/us/default.aspx. Cada dirección URL comienza
con un protocolo. En este ejemplo, el protocolo es HTTP. Seguramente observará también el
protocolo HTTPS (HTTP seguro) que se usa para las aplicaciones seguras en las que es preciso
cifrar los datos antes de transmitirlos a través de la red. Después del protocolo, la siguiente
parte de la dirección URL es la dirección del servidor web (en este caso, www.microsoft.com),
seguida de la ubicación del recurso dentro del servidor web (/en/us/) y, por último, el recurso
solicitado en sí (default.aspx). Todos los documentos, imágenes, vídeos y otros recursos de la
web se identifican mediante una dirección URL.
Cuando un explorador envía una solicitud HTTP de una página web a un servidor web (tanto
la página como el servidor se identifican mediante una dirección URL), el servidor prepara
una respuesta HTTP para el explorador. Esta respuesta especifica el contenido y el diseño de la
página web.
Los términos “Internet” y “la Web” a menudo se usan indistintamente, pero en realidad son
distintos y no deben confundirse. Internet es un sistema de comunicaciones de datos global
*
TOME NOTA que proporciona conectividad entre equipos. En cambio, la Web es uno de los diversos
servicios disponibles en Internet que permite a los usuarios obtener acceso a recursos con
hipervínculos.
El lenguaje que el servidor y explorador web usan para describir una página web es el
Lenguaje de marcado de hipertexto (HTML). HTML es un lenguaje basado en texto que usa
varias etiquetas de marcado que describen el modo en que se muestra el contenido. HTML
permite hacer referencia a imágenes, vídeos y otros objetos en un archivo, a fin de crear
páginas web multimedia. HTML también puede incrustar scripts (por ejemplo, JavaScript) que
afectan al comportamiento de las páginas web y se pueden usar para incluir hojas de estilos en
cascada (CSS) que definen el formato y el diseño del contenido de una página. El explorador
lee el código HTML y representa los resultados en la pantalla.
Una página web puede contener hipervínculos a otros recursos, tales como imágenes y vídeos.
Cada uno de estos recursos se identifica mediante su propia dirección URL. Así pues, para
representar una página en su totalidad, el explorador realizará solicitudes HTTP adicionales
con objeto de obtener estos recursos y mostrarlos como parte de la página web.
En las siguientes secciones, conoceremos mejor los diversos componentes que conforman una
página web, tales como HTML, CSS y JavaScript.
Conceptos de HTML
El propósito de HTML es proporcionar un lenguaje estándar para describir páginas web, de tal
forma que los diversos exploradores web lo entiendan y muestren la página correspondiente.
HTML es un lenguaje basado en texto, lo que significa que es posible escribir y editar páginas
Comprensión de las aplicaciones web | 87
HTML con cualquier editor de texto. Cuando se envía HTML a un explorador web, se envía el
TOME NOTA
* texto completo de la página. De hecho, la mayoría de los exploradores permiten ver el código
HTML es un lenguaje fuente HTML de una página web.
basado en el texto por
lo que se refiere a la El código HTML consta de un conjunto de etiquetas (también denominadas elementos HTML)
escritura del código. que definen la estructura y el contenido de una página. Por ejemplo, la etiqueta <html>
HTML proporciona especifica el principio de un documento HTML. Las etiquetas HTML siempre van entre
etiquetas para integrar corchetes angulares y se usan en parejas. En concreto, cada etiqueta inicial tiene una etiqueta
imágenes, audio, vídeo final correspondiente. Las etiquetas finales contienen una barra diagonal que las identifica
y muchos otros tipos de como tales. Por ejemplo, la etiqueta final de <html> es </html>.
contenido multimedia Una página HTML tiene dos partes diferentes: un encabezado y un cuerpo. El encabezado
e interactivo en una se incluye entre las etiquetas <head> y </head> y se usa para proporcionar un título para
página web. el documento y vínculos a los elementos externos que se usen en la página, tales como los
archivos CSS y JavaScript. El cuerpo va incluido entre las etiquetas <body> y </body> y se
usa para proporcionar la estructura y contenido completos de la página que se mostrará en un
TOME NOTA
* explorador web.
En este ejemplo, observe
que el documento A continuación se muestra un ejemplo de etiqueta HTML que muestra una imagen:
HTML no contiene la <img height="400px" width="400px"
imagen propiamente
dicha. En cambio, alt="Mimas Cassini" src=
la etiqueta <img> "http://upload.wikimedia.org/wikipedia/commons/b/bc/Mimas_Cassini.jpg"/>
especifica la dirección Observe que la etiqueta <img> especifica atributos adicionales. Por ejemplo, el atributo src
URL de la imagen, especifica la ubicación del archivo de imagen y los atributos height y width especifican las
que el explorador dimensiones que se deberán aplicar al representar la imagen en un explorador.
descarga por separado y
representa como parte de Ahora, vamos a estudiar otro ejemplo de etiqueta HTML:
la página.
<a href="http://en.wikipedia.org/wiki/Mimas_(moon)">
Luna de Saturno</a>
En este caso, <a> es la etiqueta de anclaje, que se usa para crear hipervínculos en una página
web. El atributo href asociado a esta etiqueta especifica la dirección URL de destino y el texto
contenido en la etiqueta de anclaje es el que se muestra como vínculo.
En esta lección no se abarcan todos los elementos HTML. Para obtener más información
*
TOME NOTA
sobre ellos, busque “elementos HTML” en MSDN.
<body>
<h1>Mimas Cassini</h1>
La etiqueta img se usa para mostrar la imagen de una
<a href="http://en.wikipedia.org/wiki/Mimas_(moon)">
Luna de Saturno</a>: <br />
<img height="400px" width="400px"
alt="Mimas Cassini"
src="http://goo.gl/3BeK"/>
</body>
</html>
4. Seleccione Depurar > Iniciar depuración (o presione F5). Se abrirá la página default.
htm en un explorador web. La salida debe ser similar a la figura 4-1, donde se observa
cómo funcionan las etiquetas <img> y <a>.
Figura 4-1
Página HTML sencilla que
contiene una imagen y un
hipervínculo
Las hojas de estilos en cascada (CSS) permiten almacenar la información acerca del
estilo y el formato de una página web en un espacio separado del código HTML. Esta
separación hace más fácil actualizar la apariencia de su sitio web. Visual Studio incluye
herramientas para crear hojas de estilos y ver su vista previa.
CSS es un lenguaje que describe información sobre cómo se muestra una página web. Al
representar las páginas web en el explorador, HTML especifica lo que se mostrará y las hojas
de estilos en cascada (CSS) especifican cómo se mostrará ese material. Por ejemplo, HTML
puede especificar que el documento tiene un título H1 con un texto determinado y CSS puede
especificar la fuente y el color que se aplicarán a ese título.
CSS permite separar el diseño de una página web de su contenido. Esta separación permite
cambiar uno de ellos sin que afecte al otro. Combinar el contenido y el estilo dificulta el
Comprensión de las aplicaciones web | 89
mantenimiento de un sitio web. Por ejemplo, supongamos que deseamos cambiar el color
y la fuente de todos los títulos H1 del sitio web. Una forma de hacerlo podría ser abrir un
editor de HTML y modificar cada archivo del sitio web donde se use la etiqueta H1. Podría
ser una solución aceptable si el sitio web solo tuviese una o dos páginas. Pero ¿y si tiene más,
por ejemplo, 50 o 100? Imagínese lo que supondría cambiar manualmente todas las páginas.
Si este tipo de cambios se solicitan con frecuencia, el proceso de desarrollo web resultará
TOME NOTA
* aburrido y proclive a cometer errores. Si lo pensamos, ¿existe un modo de garantizar que no se
Cuando se usa con
haya omitido ninguna etiqueta H1?
eficacia, las CSS
son una excelente Afortunadamente, con CSS es posible incluir toda la información de estilos en un archivo
herramienta para separado y conectarlo a todas las páginas del sitio web. Así, una vez configurado el archivo
aumentar la coherencia CSS, es posible modificar cualquier estilo (por ejemplo, el color y la fuente de los títulos H1)
y la facilidad de con solo cambiarlo en el archivo CSS; este único cambio afectará a todas las páginas del sitio
mantenimiento de todo web.
el sitio.
DISEÑO DE HOJAS DE ESTILOS EN CASCADA
El lenguaje CSS se basa en texto y es fácil de leer y entender. A continuación se muestra un
ejemplo de una página HTML que define estilos CSS:
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Conceptos de CSS</title>
<style type="text/css">
body
{
grosor de fuente: Verdana;
font-size: 9pt;
}
div
{
color:Red;
}
.block
{
background-color: Yellow;
border-color: Blue;
border-width: thin;
border-style: outset;
font-family: Arial;
}
</style>
</head>
<body>
Ejemplo de texto del cuerpo <br />
<div>Ejemplo de texto DIV</div>
<div class="block">Ejemplo de texto DIV
con la clase block</div>
<span class="block">Ejemplo de texto SPAN
con la clase block</span>
</body>
</html>
90 | Lección 4
Tenga en cuenta que las definiciones de CSS deben estar dentro del elemento <style> y bajo
el elemento <head>. Este código CSS concreto define dos estilos de elemento y un estilo de
clase. El primer estilo se aplica al elemento HTML body y especifica que todo el texto de ese
elemento debe usar la fuente Verdana con un tamaño de letra de 9 puntos. El segundo estilo
de elemento especifica que el texto del elemento DIV debe escribirse en rojo. Por último, se
define una clase denominada “block”. Las definiciones de clase de CSS llevan un punto (“.”)
como prefijo. El contenido de todos los elementos HTML que usen esta clase se mostrará con
fondo amarillo y borde. Cuando esta página concreta aparezca en un explorador, su aspecto
deberá ser el que se muestra en la figura 4-2.
Figura 4-2
Formato HTML con hojas de
estilos en cascada
En la figura, observe que el texto resaltado aparece como resultado de la clase block. Sin
embargo, la clase CSS block no especifica el color del texto. En la primera línea de texto
resaltado, la clase block se aplica al elemento DIV; en la segunda línea de texto resaltado, la
clase block se aplica al elemento SPAN. En el primer caso, como la clase block se aplica a un
texto DIV, el estilo de color del elemento DIV se propaga a la representación final.
En el ejemplo anterior, el archivo CSS se escribió dentro del archivo HTML. Suele resultar
más útil escribir el código CSS en su propio archivo independiente y, después, vincular el
archivo HTML a este archivo CSS. Aprenderemos a hacerlo en el siguiente ejercicio.
PREPÁRESE. Para escribir un archivo CSS y vincularlo a un archivo HTML, siga este
procedimiento:
1. Agregue un nuevo proyecto basado en la plantilla Aplicación web vacía de ASP.NET a la
solución Lesson04. Asigne al proyecto el nombre UnderstandingCSS.
2. Seleccione Proyecto > Agregar nuevo elemento. Seleccione la plantilla Hoja de estilos.
Asigne al archivo el nombre styles.css. Sustituya el código predeterminado del archivo
por el siguiente:
body
{
grosor de fuente: Verdana;
font-size: 9pt;
}
div
{
color:Red;
}
Comprensión de las aplicaciones web | 91
.block
{
background-color: Yellow;
border-color: Blue;
border-width: thin;
border-style: outset;
font-family: Arial;
}
3. Seleccione Proyecto > Agregar nuevo elemento y, a continuación, seleccione la
plantilla Página HTML. Asigne al archivo el nombre default.htm. Sustituya el código
predeterminado del archivo por el siguiente:
<!DOCTYPE html PUBLIC
"–//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1–
transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="STYLESHEET"
type="text/css" href="styles.css" />
<title>Conceptos de CSS</title>
</head>
<body>
Ejemplo de texto del cuerpo <br />
<div>Ejemplo de texto DIV</div>
<div class="block">Ejemplo de texto DIV
con la clase block</div>
<span class="block">Ejemplo de texto SPAN
con la clase block</span>
</body>
</html>
4. Seleccione Depurar > Iniciar depuración (o presione F5). La página default.htm se
TOME NOTA
* abrirá en un explorador web; la salida debe ser similar a la figura 4-2 (presentada
Cuando las CSS se
almacenan en archivos anteriormente).
separados, el explorador Como se muestra en el ejercicio de ejemplo, el elemento HTML <link> se usa para vincular un
del usuario descargará y archivo CSS a una página HTML:
guardará estos archivos
localmente. Por lo tanto, <link rel="STYLESHEET"
se pueden usar en varias type="text/css" href="styles.css" />
páginas sin necesidad
de descargarlos otra El elemento <link> siempre se coloca dentro del elemento <head> y el atributo href especifica
vez. Esto reduce la dirección del archivo CSS que se va a usar. Para vincular varias páginas al mismo archivo
las transferencias CSS, deberá incluir el elemento <link> dentro de cada página HTML.
innecesarias de datos. Visual Studio incluye un diseñador de estilos integrado que le ayudará a diseñar nuevos
estilos CSS o modificar los ya existentes. Al abrir un archivo .css, aparece un nuevo menú
denominado Estilos. Desde este menú, se puede crear un nuevo estilo seleccionando Estilos >
Agregar regla de estilo. También puede modificar el estilo seleccionado actualmente; para ello,
elija la opción Estilos > Generar estilo. Esta opción abre el cuadro de diálogo Modificar estilo,
como se muestra en la figura 4-3.
92 | Lección 4
Figura 4-3
Cuadro de diálogo Modificar
estilo
Conceptos de JavaScript
JavaScript es un lenguaje de scripting del lado cliente que se ejecuta en los exploradores
web para ayudar a crear páginas web mucho más interactivas de lo que es posible usando
solamente HTML. JavaScript se usa en millones de páginas web y es compatible con
todos los exploradores modernos.
JavaScript se usa para aportar capacidad de respuesta a los sitios web e interactividad a las
páginas web. Para ello, JavaScript ejecuta el código en el lado cliente (el explorador web)
y minimiza las idas y venidas innecesarias al servidor web. Tomemos como ejemplo a un
usuario que tiene que especificar en una página web sus datos personales, tales como su
nombre, dirección de correo electrónico y número de teléfono. Un requisito común consiste
en realizar la validación de los datos para asegurarse de que los campos de entrada no estén
vacíos y de que la dirección de correo electrónico y el número de teléfono del usuario se
hayan especificado con el formato correcto. Sin JavaScript, sería preciso enviar el formulario
al servidor, que validaría los datos y devolvería los resultados al cliente. Esta transmisión de
información tarda tiempo y degrada la experiencia del usuario. Sin embargo, una solución
JavaScript puede realizar este tipo de validación de datos desde el propio explorador, con lo
que mejora la experiencia del usuario.
Como hemos mencionado anteriormente, el código JavaScript se ejecuta localmente en el
explorador web (el cliente), no en el servidor web. Por este motivo, en ocasiones nos referimos
a JavaScript como un “lenguaje de scripting del lado cliente” y denominamos la programación
con JavaScript “programación del lado cliente”.
El comportamiento en tiempo de ejecución del código del lado cliente depende del explorador
que lo ejecute. Sin embargo, este comportamiento es independiente de la tecnología de
servidor y del marco de programación. Por consiguiente, para el código JavaScript ejecutado
en un explorador web, no importa si la página web se generó mediante ASP.NET o PHP ni si
la presenta un servidor web Windows o Linux.
Los lenguajes de programación JavaScript y C# usan una sintaxis influenciada por el
lenguaje de programación C. Sin embargo, JavaScript y C# son muy diferentes en la forma
de ejecutarse. En concreto, JavaScript lo ejecuta el explorador web y el código JavaScript se
interpreta, no se compila como ocurre con C#.
Todo el código JavaScript debe incluirse dentro del elemento <script>. El elemento <script>
suele ir dentro del elemento <head>, aunque no es obligatorio que sea así. Pueden existir
Comprensión de las aplicaciones web | 93
Muchos sitios web modernos ofrecen una experiencia sumamente interactiva equiparable
a la de las aplicaciones de escritorio. Dichos sitios se pueden desarrollar mediante la
programación Ajax. Ajax es la abreviatura de “Asynchronous JavaScript and XML”
*
TOME NOTA
(JavaScript y XML asincrónicos). Ajax toma muchos recursos de JavaScript a fin de
proporcionar aplicaciones web con gran capacidad de respuesta. El marco ASP.NET AJAX
permite implementar la funcionalidad de Ajax en páginas web ASP.NET.
varios elementos <script> en una misma página. Para ver cómo funciona JavaScript, pruebe
con el ejercicio siguiente.
PREPÁRESE. Para empezar a trabajar con JavaScript, lleve a cabo las siguientes tareas:
1. Agregue un nuevo proyecto basado en la plantilla Aplicación web vacía de ASP.NET a la
solución Lesson04. Asigne al proyecto el nombre UnderstandingJavaScript.
2. Seleccione Proyecto > Agregar nuevo elemento y, a continuación, seleccione la
plantilla Página HTML. Asigne al archivo el nombre default.htm. Sustituya el código
predeterminado del archivo por el siguiente:
<!DOCTYPE html PUBLIC
"–//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1–
transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Conceptos de JavaScript</title>
<script type="text/javascript"
language="javascript">
username = prompt("Escriba su nombre");
message = "Hola, " + username 1+
". Su nombre tiene ";
nameLen = username.length;
if (nameLen > 5)
message = message + "más de ";
else if (nameLen < 5)
message = message + "menos de ";
else
message = message + "exactamente ";
message = message + "5 caracteres.";
alert(message);
</script>
</head>
<body>
</body>
</html>
94 | Lección 4
Figura 4-5
Cuadro de diálogo de
JavaScript
Como sucede con los archivos CSS, el código JavaScript también puede incluirse en un
archivo separado y vinculado a un archivo HTML mediante el elemento de script, como se
muestra a continuación:
<script src="SampleScript.js">
</script>
En este caso, el archivo SampleScript.js contiene todo el código JavaScript y el elemento
script establece un vínculo a este archivo mediante el atributo src. Almacenar el código
JavaScript en archivos externos ofrece varias ventajas:
TOME NOTA
* • Facilita el mantenimiento: si se usa el mismo código JavaScript en todas las páginas de
Aunque todos los un sitio web, es posible almacenar ese código en una página central en lugar de repetirlo
exploradores modernos en todas ellas. De este modo, cuando sea preciso modificar el código JavaScript, solo
admiten JavaScript, habrá que cambiarlo en un lugar.
pueden establecerse de • Mejora el rendimiento: almacenar el código JavaScript en un archivo separado reduce
modo que JavaScript el tamaño de la página web. Además, los exploradores pueden descargar y almacenar en
esté desactivado. Puede caché el archivo JavaScript externo para que no se vuelva a descargar a menos que se
usar un elemento modifique.
<noscript> para mostrar
un mensaje específico Visual Studio incluye compatibilidad plena de IntelliSense con el código JavaScript. Incluso
a los usuarios que los controles ASP.NET, como el control TreeView o los controles de validación, usan
optan por no ejecutar JavaScript siempre que es posible para representar el contenido dinámicamente.
JavaScript.
Conceptos de la programación del lado cliente comparada con la
programación del lado servidor
Si un programa es del lado cliente o del lado servidor depende de dónde se ejecute en
última instancia.
La programación del lado cliente se refiere a los programas que se ejecutan totalmente en el
equipo local de un usuario. Ejemplos de programas del lado cliente son la aplicación Windows
Forms y el código JavaScript que se ejecuta en un explorador web. Los programas del lado
cliente no consumen recursos del servidor.
Por otra parte, la programación del lado servidor se refiere a programas que se ejecutan
íntegramente en un servidor y que consumen los recursos de cálculo del servidor. En este caso,
los únicos recursos del cliente que se usan son aquellos que intervienen en la recuperación de
los resultados de procesamiento del servidor. Las aplicaciones web y los servicios web son
Comprensión de las aplicaciones web | 95
ejemplos de programación del lado servidor. Este tipo de programación usa tecnologías del
lado servidor, como ASP.NET, PHP o Ruby on Rails.
En los últimos tiempos, están cobrando popularidad las aplicaciones híbridas, que usan
programación del lado cliente y del lado servidor. Por ejemplo, se pueden diseñar aplicaciones
de cliente inteligente que se ejecutan localmente en equipos cliente pero usan los servicios web
LISTO PARA CERTIFICACIÓN para llevar a cabo determinadas tareas. De hecho, las aplicaciones Ajax usan una combinación
¿Comprende cómo se de programación del lado servidor y de código del lado cliente para crear aplicaciones web
usan HTML, JavaScript interactivas con una gran capacidad de respuesta.
y CSS para desarrollar
páginas web? ASP.NET permite crear aplicaciones que se ejecutan íntegramente en el servidor o aplicaciones
4.1 Ajax híbridas que proporcionan interfaces rápidas con gran capacidad de respuesta pero
almacenan la mayor parte de sus datos en la Web.
Figura 4-6
Comunicación entre un
cliente y un servidor web
96 | Lección 4
Como desarrollador, debe saber lo que ocurre entre bambalinas cuando un servidor web
ejecuta una solicitud de una página ASP.NET. En los siguientes pasos se describe este proceso:
1. Cuando Internet Information Service (IIS) recibe una solicitud HTTP, usa la
extensión de archivo para determinar qué programa de la Interfaz de programación
de aplicaciones para servidores de Internet (ISAPI) debe ejecutar para procesar la
solicitud. Cuando lo que se solicita es una página ASP.NET, pasa la solicitud al
archivo DLL de ISAPI que controla las solicitudes de páginas ASP.NET, que es
aspnet_isapi.dll.
2. El proceso aspnet_isapi.dll pasa la solicitud al proceso de trabajo de ASP.NET
(aspnet_wp.exe), que satisface la solicitud.
3. El proceso de trabajo de ASP.NET compila el archivo .aspx en un ensamblado
y da las instrucciones al Common Language Runtime (CLR) para que ejecute el
ensamblado.
4. Cuando el ensamblado se ejecuta, usa los servicios de varias clases en la biblioteca de
clases de .NET Framework para realizar su trabajo y generar mensajes de respuesta
para el cliente solicitante.
5. El proceso de trabajo de ASP.NET recopila las respuestas generadas por la ejecución
de la página web, crea un paquete de respuesta y lo pasa al proceso aspnet_isapi.dll.
6. aspnet_isapi.dll reenvía el paquete de respuesta a IIS que, a su vez, lo pasa al equipo
cliente solicitante.
Antes de la ejecución, cada página ASP.NET se convierte en una clase. Esta clase deriva la
mayor parte de su funcionalidad de la clase System.Web.UI.Page. La clase Page proporciona
varias propiedades importantes, tales como Request, Response, Session y Server.
Conceptos del modelo de eventos y del ciclo de vida de las páginas ASP.NET
Durante su ejecución, una página ASP.NET atraviesa varias fases de procesamiento
diferenciadas. Cada una de estas fases a su vez atraviesa varios pasos de procesamiento
específicos, tales como inicialización, carga, ejecución del código de controlador de
eventos y representación.
A medida que se ejecuta, la página pasa por las diversas fases de procesamiento. La página
también activa varios eventos a los que es posible adjuntar un controlador de eventos para
poder ejecutar código personalizado en las diferentes fases del procesamiento de la página.
De hecho, los desarrolladores de ASP.NET deben conocer bien el ciclo de vida de las
páginas, para poder escribir un código que se ejecute exactamente en las fases deseadas del
procesamiento de la página.
En la tabla 4.1 se enumeran las distintas fases del ciclo de vida y los eventos asociados a ellas.
Tabla 4-1
Fases importantes del ciclo de vida de las páginas ASP.NET
Cuando deseamos controlar un evento, debemos escribir código que registre con el evento
un método que lo controle (también denominado controlador de eventos). Esto suele hacerse
mediante el patrón común de registro de eventos que se usa en .NET Framework:
objeto.evento += new EventHandler(controladorEventos);
En esta expresión, reemplazamos objeto por el nombre del objeto que expone el evento, evento
por el nombre del evento y controladorEventos por el nombre del método que controla el
evento.
Sin embargo, cabe destacar que ASP.NET proporciona seis métodos especiales reconocidos
como controladores de eventos de forma predeterminada y para los que no se requiere
el código de registro anterior. Se trata de los métodos con nombres especiales Page_Init,
Page_Load, Page_DataBind, Page_PreRender y Page_Unload. Estos métodos se tratan como
controladores de eventos para los eventos correspondientes expuestos por la clase Page.
Estas conexiones de eventos automáticos se controlan mediante el atributo AutoEventWireup
de la directiva @Page. De forma predeterminada, el valor de este atributo es true, lo que
significa que estos métodos con nombres especiales están conectados automáticamente a sus
correspondientes eventos.
98 | Lección 4
PREPÁRESE. Para ver cómo se ejecutan los diferentes eventos de la clase Page, realice las
siguientes acciones:
1. Cree un nuevo proyecto basado en la plantilla Aplicación web vacía de ASP.NET en la
solución Lesson04. Asigne al proyecto el nombre PageEvents.
2. Seleccione Proyecto > Agregar nuevo elemento. Seleccione la plantilla Formulario
Web Forms. Asigne al archivo el nombre WebForm1.aspx.
3. En el formato HTML de la página (WebForm1.aspx), asegúrese de que el atributo
AutoEventWireup de la directiva @Page esté establecido en true:
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="WebForm1.aspx.cs"
Inherits="PageEvents.WebForm1" %>
4. Haga clic en la ventana de código y seleccione Ver código en el menú contextual para
cambiar a la vista de código. Reemplace el código del archivo de código subyacente
(WebForm1.aspx.cs) por lo siguiente:
using System;
namespace PageEvents
{
public partial class WebForm1
: System.Web.UI.Page
{
protected void Page_Load
(object sender, EventArgs e)
{
Response.Write
("Message from Page_Load. <br/>");
}
protected void Page_Init
(object sender, EventArgs e)
{
Response.Write
("Message from Page_Init. <br/>");
}
protected void Page_PreRender
(object sender, EventArgs e)
{
Response.Write
("Message from Page_PreRender. <br/>");
}
protected void Page_PreInit
(object sender, EventArgs e)
{
Response.Write
("Mensaje de Page_PreInit. <br/>");
}
}
}
Comprensión de las aplicaciones web | 99
Figura 4-7
Formulario Web Forms en
que se muestra el orden de
ejecución de eventos de una
página ASP.NET
En el ejercicio del ejemplo, observe que se usan los caracteres <% y %> para insertar bloques
de código en el formato HTML de una página. El código contenido en estos bloques insertados
se ejecuta durante la fase de representación de la página. Dentro de los bloques de código
insertado, se usa la sintaxis <%=expresión> para resolver una expresión y devolver su valor en
el bloque. Por ejemplo, vamos a fijarnos en el bloque de código siguiente:
<i><% = DateTime.Now.ToShortDateString() %></i>
Al ejecutarlo, este código mostrará la fecha actual en cursiva:
12/01/2010
La directiva @Page especifica varios atributos que controlan cómo ASP.NET representará
una página. Por ejemplo, en este ejercicio, los atributos de la directiva @Page especifican lo
siguiente:
• C# es el lenguaje de programación de esta página web (Language="C#")
• los eventos de la página se conectan automáticamente (AutoEventWireup=true)
• el nombre del archivo de código que contiene la clase asociada con la página
(CodeBehind="WebForm1.aspx.cs")
• el nombre de clase de la página que se hereda (Inherits="PageEvents.WebForm1")
• Estado de aplicación: el estado de aplicación se usa para almacenar los datos usados
en una aplicación. Se puede obtener fácilmente acceso al estado de aplicación mediante
la propiedad Application de la clase Page. Esta propiedad proporciona acceso al objeto
HttpApplicationState que almacena el estado de aplicación como una colección de pares
clave-valor.
En el ejercicio siguiente se muestra cómo usar el estado de sesión. En el ejercicio se usan dos
formularios Web Forms. WebForm1.aspx obtiene un nombre de usuario y lo almacena en el
estado de sesión. A continuación, el formulario transfiere al usuario a WebForm2.aspx, que
recupera el nombre de usuario de la sesión.
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="Label1" runat="server"
Text="Escriba su nombre:" /><br />
<asp:TextBox ID="TextBox1" runat="server" />
<br /><br />
<asp:Button ID="Button1" runat="server"
Text="Enviar" onclick="Button1_Click" />
</div>
</form>
</body>
</html>
4. Haga clic en la ventana de código y seleccione Ver código en el menú contextual para
cambiar al archivo de código subyacente (WebForm1.aspx.cs). Reemplace el código de
ese archivo por lo siguiente:
using System;
namespace UsingSessionState
{
public partial class WebForm1
: System.Web.UI.Page
{
protected void Page_Load
(object sender, EventArgs e)
{
if (Session["Name"] != null)
Response.Redirect("WebForm2.aspx");
}
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="Label1" runat="server" /> <br />
<asp:Button ID="Button1" runat="server"
Text="Borrar sesión"
onclick="Button1_Click" />
</div>
</form>
</body>
</html>
6. Cambie el código del archivo de código subyacente (WebForm2.aspx.cs) del formulario
de modo que sea como el siguiente:
using System;
namespace UsingSessionState
{
public partial class WebForm2
: System.Web.UI.Page
{
protected void Page_Load(
object sender, EventArgs e)
{
if (Session["Name"] != null)
Label1.Text = String.Format(
"Bienvenido, {0}", Session["Name"]);
else
Response.Redirect("WebForm1.aspx");
}
protected void Button1_Click(
object sender, EventArgs e)
{
Session.Remove("Name");
Response.Redirect("WebForm1.aspx");
}
}
}
7. Seleccione Depurar > Iniciar depuración (o presione F5). Se abrirá la página
WebForm1.aspx en un explorador web, como se muestra en la figura 4-8. Escriba
un nombre y haga clic en el botón "Enviar". En esta página se almacena el nombre
especificado en el estado de sesión.
104 | Lección 4
Figura 4-8
En esta página se almacena
el nombre especificado en el
estado de sesión
Figura 4-9
En esta página se recupera el
nombre mostrado del estado
de sesión
El hospedaje de sitios web consiste en configurar un servidor web con los archivos de
CONCLUSIÓN código y la configuración correctos para que los usuarios remotos puedan obtener acceso
satisfactoriamente a una aplicación web.
IIS se puede usar para hospedar varios sitios web y compartir información con los usuarios a
través de Internet o de una intranet. IIS aplica una relación jerárquica entre sitios, aplicaciones
y directorios virtuales que constituye un bloque de creación básico para hospedar contenido en
línea.
IIS se puede administrar mediante el Administrador de IIS, una herramienta incluida en el
sistema operativo Windows. Esta herramienta, como se muestra en la figura 4-10, proporciona
una interfaz gráfica de usuario para configurar sitios web, aplicaciones y directorios virtuales.
La captura de pantalla de la figura 4-10 se ha tomado en un equipo que ejecuta Windows 7.
La interfaz de usuario del Administrador de IIS es diferente en Windows XP.
Figura 4-10
Interfaz del Administrador de
IIS en un equipo que ejecuta
Windows 7
como se muestra en el ejemplo anterior. Cuando IIS recibe una solicitud de una dirección URL
de este tipo, asigna el directorio virtual a la ubicación física de los archivos. En el ejercicio
siguiente se muestra cómo crear un directorio virtual.
PREPÁRESE. Para crear un directorio virtual mediante el Administrador de IIS, realice los
pasos siguientes:
1. Abra el Administrador de IIS. Para abrir el Administrador de IIS en Windows 7, escriba
IIS en el menú Inicio y, a continuación, haga clic en el acceso directo Administrador
de IIS. Para obtener acceso al Administrador de IIS en Windows XP, vaya a Inicio >
Ejecutar, escriba “inetmgr” y haga clic en el botón Aceptar.
2. Expanda los nodos del panel izquierdo (consulte la figura 4-10) y seleccione el nodo
Sitio web predeterminado.
3. Haga clic con el botón secundario en el nodo Sitio web predeterminado y seleccione
la opción Agregar directorio virtual en el menú contextual. En Windows XP, el
comando será Nuevo > Directorio virtual. En este punto, se abrirá en la pantalla el
Asistente para crear un directorio virtual.
4. En el cuadro de diálogo Agregar directorio virtual, especifique un alias y una ruta de
acceso física, como se muestra en la figura 4-11. A continuación, haga clic en Aceptar.
Figura 4-11
Cuadro de diálogo Agregar
directorio virtual
Los servicios web proporcionan un modo de interactuar con los objetos de programación
ubicados en equipos remotos. La característica especial de los servicios web es que todas las
comunicaciones entre sus clientes y servidores se lleva a cabo mediante mensajes en lenguaje
de marcado extensible (XML) que se transmiten a través del Protocolo de transferencia de
hipertexto (HTTP).
Mediante el uso de estas tecnologías estándar, los objetos remotos se pueden publicar y
consumir en sistemas que de otro modo serían incompatibles. Por ejemplo, un objeto remoto
escrito en C# y publicado como servicio web en un servidor web Windows se puede procesar
mediante código Java ejecutado en un equipo Linux.
Antes de entrar en los detalles de la creación y el consumo de los servicios web, vamos a
familiarizarnos con dos tecnologías esenciales que hacen posibles los servicios web:
• Protocolo simple de acceso a objetos (SOAP)
• Web Services Description Language (WSDL)
Introducción a SOAP
SOAP es el protocolo de intercambio de información estructurada en comunicaciones de
servicios web entre dos equipos remotos.
SOAP es el protocolo que define el modo en que los equipos remotos intercambian mensajes
durante una comunicación de servicios web. SOAP usa XML para el formato de los mensajes
y HTTP para transmitirlos. El uso de SOAP para las comunicaciones presenta dos ventajas
principales. En primer lugar, puesto que el formato de los mensajes es XML, resultan más
fáciles de entender en los sistemas no compatibles. En segundo lugar, como estos mensajes se
transmiten mediante el omnipresente protocolo HTTP, suelen poder obtener acceso a cualquier
equipo de Internet sin quedar bloqueados en los cortafuegos.
Este es un paquete SOAP típico enviado desde un cliente a un servicio web:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope
xmlns:xsi=http://www.w3.org/2001/XMLSchema–instance
xmlns:xsd=http://www.w3.org/2001/XMLSchema
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ToLower xmlns="http://northwindtraders.com">
<inputString>CADENA DE MUESTRA</inputString>
</ToLower>
</soap:Body>
</soap:Envelope>
108 | Lección 4
Si nos fijamos en el ejemplo, observaremos algunos de los elementos evidentes de este paquete
SOAP:
• El paquete consta de un sobre (envelope) que contiene un cuerpo (body); cada uno de
estos elementos se identifica mediante una etiqueta XML específica.
• El cuerpo consiste en el nombre del método que se invoca. En este paquete SOAP, el
nombre del método es ToLower y toma un solo parámetro denominado inputString con
un valor dado.
Este es el paquete de respuesta del servidor:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ToLowerResponse
xmlns="http://northwindtraders.com">
<ToLowerResult>cadena de muestra</ToLowerResult>
</ToLowerResponse>
</soap:Body>
</soap:Envelope>
En el paquete de respuesta, el elemento XML ToLowerResponse es el resultado de la
invocación del método en el servidor.
Introducción a WSDL
WSDL es un lenguaje basado en XML para describir servicios web.
TOME NOTA
* WSDL son las siglas de Web Services Description Language (lenguaje de descripción de
Un servicio web puede servicios web) y proporciona un estándar que permite a un servicio web informar a su cliente
existir sin un archivo sobre qué tipo de mensajes aceptará y qué resultados se devolverán. Un archivo WSDL actúa
WSDL, pero es preciso como la interfaz pública de un servicio web e incluye la siguiente información:
conocer el mensaje • los tipos de datos que puede procesar;
SOAP entrante exacto
que el servicio web • los métodos que expone;
espera recibir para poder • las direcciones URL a través de las que se puede obtener acceso a los métodos.
usar dicho servicio.
{
[WebMethod]
public string ToUpper(string inputString)
{
return inputString.ToUpper();
}
[WebMethod]
public string ToLower(string inputString)
{
return inputString.ToLower();
}
}
4. Seleccione Depurar > Compilar TextWebService para compilar el proyecto y
TOME NOTA
* asegurarse de que no hay ningún error. Ahora, el servicio web está listo para su uso.
Puede incluir el nombre
de dominio de su En el código anterior, hay algunos aspectos importantes que cabe destacar. En primer
empresa en el espacio de lugar, observe que cada clase que se expone como servicio web XML debe tener el atributo
nombres para distinguir WebService. El atributo WebService tiene una propiedad Namespace que toma de forma
sus servicios web de predeterminada el valor https://tempuri.org/. Aunque durante el desarrollo es aceptable usar
aquellos publicados por este valor, el valor del espacio de nombres debe cambiarse antes de publicar el servicio web.
otras empresas. De hecho, cada servicio web individual debe tener un espacio de nombres exclusivo para que
las aplicaciones cliente lo distingan de los demás servicios web.
Cada método que se expone desde el servicio web debe tener además el atributo WebMethod.
Los métodos marcados con atributos WebMethod se denominan también “métodos web”. Los
dos métodos que se usan en este ejercicio convierten una cadena determinada a mayúsculas y
minúsculas, respectivamente.
Para probar un servicio web sencillo como TextWebService, creado anteriormente, solo se
necesita un explorador web. Puede seleccionar métodos para invocarlos, pasar parámetros
y revisar los valores devueltos desde el propio explorador, como se muestra en el siguiente
ejercicio.
4. En cada página de prueba de un método web se muestran el código SOAP y los demás
mensajes que el servicio web entiende. También hay un formulario que permite
especificar los parámetros del método web y probarlo. Especifique una cadena de
entrada de prueba y haga clic en el botón Invocar. El resultado debería aparecer en la
página siguiente, como se muestra en la figura 4-16.
Figura 4-16
Valor devuelto por la prueba
del servicio web
5. Pruebe los dos métodos. Cuando haya terminado, cierre el explorador web.
112 | Lección 4
En esta misma lección, hemos aprendido a invocar un servicio web desde la página de
prueba del servicio web. En esta sección, aprenderemos a llamar a un servicio web mediante
programación desde una aplicación cliente ASP.NET.
PREPÁRESE. Para obtener acceso a un servicio web desde una aplicación cliente, realice los
siguientes pasos:
1. Agregue un nuevo proyecto a la solución Lesson04 basado en la plantilla Aplicación
web ASP.NET. Asigne al proyecto el nombre TextWebServiceClient.
2. Haga clic con el botón secundario en el nombre del proyecto en la ventana Explorador
de soluciones y, a continuación, seleccione la opción Agregar referencia web en el
menú contextual. En el cuadro de diálogo Agregar referencia web, escriba la dirección
URL del servicio creado en el ejercicio anterior y presione Intro. (También puede
copiar la dirección URL de la barra de direcciones del explorador.) Esta acción carga la
lista de operaciones disponibles en el servicio web, como se muestra en la figura 4-17.
Figura 4-17
Cuadro de diálogo Agregar
referencia web
Figura 4-18
Nodo de referencias web del
proyecto
Método ToUpper:
<asp:Label ID="toUpperLabel"
runat="server"
Text="Label" ForeColor="Green" />
</p>
</form>
</body>
</html>
5. Abra la vista Diseño de Default.aspx y haga doble clic en el control Button. Se agregará
el código del controlador de eventos Click. Modifique el código como se muestra a
continuación:
TOME NOTA
* protected void Button1_Click(
Al invocar un método
de un servicio web, object sender, EventArgs e)
puede usar un método {
sincrónico o asincrónico. var webService =
El método asincrónico
puede ser conveniente new textWebService.TextWebService();
para aumentar la toLowerLabel.Text =
capacidad de respuesta webService.ToLower(TextBox1.Text);
de la aplicación cliente. toUpperLabel.Text =
webService.ToUpper(TextBox1.Text);
}
6. Seleccione Depurar > Iniciar depuración para ejecutar la aplicación web. Escriba texto
de muestra y haga clic en el botón Invocar métodos de servicio. Deberían aparecer los
resultados de TextWebService, como se muestra en la figura 4-19.
Figura 4-19
Valor devuelto por el servicio
web
En el ejercicio anterior, al agregar una referencia web, Visual Studio crea un proxy local que
representa el servicio remoto. El proxy simplifica la comunicación con el servicio web porque
acepta los mensajes, los reenvía al servicio web y devuelve los resultados del servicio web.
Este proxy se puede usar fácilmente para crear objetos desde el servicio web e invocar
métodos. En consecuencia, resulta similar trabajar con objetos remotos o con objetos locales.
Comprensión de las aplicaciones web | 115
Cuando se crea una referencia web, Visual Studio lee el archivo WSDL apropiado para
LISTO PARA CERTIFICACIÓN
determinar qué clases y métodos están disponibles en el servidor remoto. Cuando se llama
¿Comprende los conceptos
a un método para un objeto remoto, .NET Framework traduce la llamada y los resultados a
básicos del desarrollo de
mensajes SOAP y los transmite sin que usted intervenga en absoluto.
servicios web?
4.4
RESUMEN DE CONOCIMIENTOS
■ Evaluación de conocimientos
Rellene los espacios en blanco
Complete las oraciones siguientes escribiendo la palabra o palabras correctas en los
espacios en blanco proporcionados.
1. En la etiqueta de anclaje HTML (<a>), el atributo _________ especifica la dirección URL
del destino.
2. Puede poner código CSS en un archivo separado y vincularlo a una página web mediante
el uso del elemento HTML _________.
116 | Lección 4
Varias opciones
Rodee con un círculo la letra correspondiente a la mejor respuesta.
1. Ha escrito el siguiente código para su página web:
<html>
<head>
<title>Página de muestra</title>
<style type="text/css">
div
{
grosor de fuente: Verdana;
font-size: 9pt;
}
</style>
</head>
<body>
<div style=
"font-weight: bold; font-size: 12pt;">
Texto de muestra</div>
</body>
</html>
¿Cuál sería el estilo del texto mostrado como parte del elemento <div>?
a. Font family: Verdana; font weight: bold; font size: 12pt
b. Font family: Verdana; font weight: bold; font size: 9pt
c. Font family: Verdana; font size: 12pt
d. Font family: Verdana; font size: 9pt
Comprensión de las aplicaciones web | 117
2. Está desarrollando un sitio web de mapas que permite a los usuarios explorar mapas
interactivamente mediante acciones como panorámicas y acercamiento. Desea que el
sitio web sea dinámico y accesible en la mayor parte de los exploradores modernos.
Sin embargo, no desea que los usuarios tengan que instalar complementos adicionales
para usar su sitio web. ¿Cuál de las siguientes tecnologías debería usar para mostrar
los mapas?
a. HTML
b. Tecnología de programación del lado servidor como ASP.NET
c. Adobe Flash
d. JavaScript
3. Su página ASP.NET contiene una variable de nivel de página del tipo Customer.
Desea conservar el valor de esta variable a través de los postback de la página,
pero no necesita esta variable en ninguna otra página de la aplicación. ¿Cuál de las
siguientes técnicas de administración de estado es la mejor manera de lograrlo?
a. Cadenas de consulta
b. Cookies
c. ViewState
d. Sesión
4. Está desarrollando una aplicación web para un banco de Internet. La aplicación
permite a los usuarios obtener acceso a su información de cuenta y transacciones
desde el interior de un explorador web. Cuando un usuario inicie una sesión en la
aplicación web, usted desea mostrar el nombre de usuario y el balance de la cuenta
en todas las páginas de la aplicación hasta que el usuario cierre la sesión. También
desea que esta aplicación esté a salvo de usuarios malintencionados. ¿Cuál de las
siguientes técnicas de administración de estado debe usar?
a. Cookies
b. ViewState
c. ViewState con cifrado
d. Sesión
5. Está desarrollando un formulario Web Forms para mostrar información
meteorológica. Cuando un usuario solicita el formulario Web Forms, este debe
realizar una inicialización para cambiar su apariencia y asignar valores a algunos
controles. ¿Dónde debería poner el código?
a. En el controlador del evento PreInit de la clase Page
b. En el controlador del evento Init de la clase Page
c. En el controlador del evento Load de la clase Page
d. En el controlador del evento PreRender de la clase Page
6. Desea mostrar valores de las expresiones de C# en una página ASP.NET. ¿Cuál de los
siguientes tipos de bloques de código debería usar para delimitar la expresión?
a. <script runat="server">…</script>
b. <script>…</script>
c. <%= … %>
d. <form>…</form>
7. Ha desarrollado una aplicación de planilla de horas trabajadas que usarán todos los
empleados de su empresa. Ha usado ASP.NET para desarrollar esta aplicación y la
ha implementado en el servidor web de la empresa. ¿Qué deben instalar todos los
empleados de la empresa en sus equipos para poder obtener acceso a la aplicación de
la planilla?
a. .NET Framework Redistributable
b. .NET Framework Software Development Kit
c. Visual Studio
d. Un explorador web
118 | Lección 4
8. La aplicación cliente llama a un servicio web que realiza cálculos complejos que tardan
mucho tiempo. Un usuario se queja de que, mientras se devuelven los resultados, la
interfaz de usuario deja de actualizarse momentáneamente. ¿Qué enfoque debe adoptar
para solucionar este problema?
a. Se debe instalar un procesador mejor en el servidor web.
b. Se debe instalar un procesador mejor en el equipo cliente.
c. Se debe actualizar la conexión a Internet a una más rápida.
d. Se deben usar llamadas asincrónicas para invocar el servicio web.
9. Ha creado un servicio web ASP.NET que convierte una divisa en otra. Uno de los
métodos del servicio web se define con el siguiente código:
public double Convert(double amount,
string from, string to)
{
// código para realizar la conversión de divisa
}
Los usuarios del servicio web notifican que, si bien pueden establecer una referencia
al servicio web, el método Convert no está disponible para ellos. ¿Cuál puede ser el
problema?
a. El archivo .asmx del servicio web no está disponible en el servidor web.
b. La clase del servicio web no está marcada con el atributo WebService.
c. El método Convert no está marcado con el atributo WebMethod.
d. Los servicios web solo pueden exponer métodos que devuelven valores de texto.
10. Está trabajando en dos proyectos de Visual Studio. El primer proyecto es un servicio
web que devuelve un objeto DataSet perteneciente al espacio de nombres System.Data.
El segundo proyecto tiene acceso al servicio web creado por el primer proyecto. ¿Qué
proyecto de este escenario requiere una referencia al espacio de nombres System.Data?
a. El proyecto de servicio web
b. El proyecto de cliente que obtiene acceso al servicio web
c. Tanto el proyecto de cliente como el proyecto del servicio web
d. Ni el proyecto de cliente ni el proyecto del servicio web
■ Evaluación de competencias
Escenario 4-1: Uso de JavaScript y HTML
Está desarrollando una página web que proporciona una interfaz de usuario interactiva. Decide
mostrar una imagen en la página. Cuando el usuario mueve el mouse sobre la imagen, se
sustituye la imagen original por una imagen nueva. A continuación, cuando el mouse sale del
área de la imagen, la imagen original se muestra otra vez. Desea lograr este comportamiento
mediante código JavaScript del lado cliente y código HTML. ¿Cómo se crea una página web
que funcione como hemos descrito?
■ Evaluación de aptitudes
Escenario 4-3: Llamada a un servicio web de forma asincrónica
La clase proxy generada por Visual Studio para un servicio web incluye métodos para
llamar al servicio web tanto sincrónica como asincrónicamente. De forma predeterminada,
la aplicación usa el método sincrónico. Si prefiere la invocación asincrónica, debe llamar a
la versión asincrónica del método. Las versiones asincrónicas no esperan a que el servicio
web devuelva una respuesta y usan un mecanismo de devolución de llamada para obtener
una respuesta cuando está lista. La invocación asincrónica de un servicio web puede ayudar
a incrementar la capacidad de respuesta de las aplicaciones cliente. Desea llamar al método
ToLower del servicio TextWebServices creado anteriormente de forma asincrónica. ¿Qué
código escribiría para invocar asincrónicamente un servicio web?
TÉRMINOS CLAVE
aplicación basada en consola delegados parámetros de línea de
Aplicaciones de interfaz de eventos comandos
múltiples documentos (MDI) herencia visual servicio de Windows
aplicaciones de Windows instalador
Forms
120
Comprensión de las aplicaciones de escritorio | 121
Un formulario de Windows Forms es una superficie visual que puede mostrar gran
variedad de controles, tales como menús, botones y cuadros de texto. Visual Studio
proporciona un Diseñador de Windows Forms con funcionalidad de arrastrar y colocar
que puede usar para crear fácilmente sus aplicaciones.
TOME NOTA
* Para diseñar formularios de Windows Forms, primero debe decidir qué controles desea
Un control es un colocar en el formulario. Los formularios de Windows Forms proporcionan una amplia
elemento de interfaz colección de controles comunes que se pueden usar directamente para crear una excelente
de usuario particular interfaz de usuario. Si la funcionalidad que precisa no está disponible en uno de los controles
que acepta entradas comunes existentes, puede crear un control personalizado o bien comprárselo a un proveedor
del usuario o muestra independiente.
salidas al usuario.
Puede usar la funcionalidad que aporta el Diseñador de Windows Forms de Visual Studio
para colocar y organizar rápidamente los controles conforme a sus requisitos. Visual Studio
proporciona fácil acceso a los controles disponibles a través de su cuadro de herramientas,
como se muestra en la figura 5-1.
Figura 5-1
Cuadro de herramientas de
Visual Studio
Un formulario y sus componentes suelen responder a las acciones de los usuarios, tales como
pulsaciones de teclado o movimientos del mouse. Estas acciones se denominan eventos. Gran
parte del código que se escribe como desarrollador de formularios de Windows Forms está
orientado a la captura de estos eventos y su control mediante la creación de una respuesta
adecuada. Por ejemplo, en el ejercicio siguiente, crearemos un formulario de Windows Forms
que muestra el valor de fecha seleccionado por el usuario.
Figura 5-2
Cuadro de diálogo Nuevo proyecto de Visual Studio
Figura 5-3
Formulario de Windows
Forms con un control
DateTimePicker y un control
Label
5. Seleccione Depurar > Iniciar depuración (o presione F5) para ejecutar el proyecto. En
TOME NOTA
* la interfaz de usuario, seleccione una nueva fecha y compruebe que esta aparece en el
En este ejercicio, hemos
control Label.
usado los nombres
predeterminados de En este ejercicio, observe que, la primera vez que se muestra el formulario, el control Label
los controles. En los está establecido en una cadena vacía. Después, al cambiar la selección de fecha manipulando
formularios complejos el control DateTimePicker, el valor de fecha seleccionado se establece como el texto del
con más controles, control Label.
siempre es conveniente
asignar a los controles
nombres más Conceptos del modelo de eventos de Windows Forms
significativos.
El control de eventos desempeña una función primordial en la programación basada
en interfaz de usuario, pues permite responder a los diversos eventos que se activan
como consecuencia de las acciones del usuario y, de este modo, hace que los programas
sean interactivos. El modelo de eventos de Windows Forms usa delegados de .NET
Framework para vincular los eventos a sus controladores de eventos respectivos.
Figura 5-4
Plantilla Formulario
heredado
Comprensión de las aplicaciones de escritorio | 125
Figura 5-5
Cuadro de diálogo Selector
de herencia
8. Seleccione Depurar > Iniciar depuración (o presione F5) para ejecutar el proyecto.
Cuando InheritedForm se carga, se muestra la fecha seleccionada actualmente en el
control Label. Esto no sucedía en el formulario Form1 creado anteriormente, donde
inicialmente el control Label estaba vacío.
El formulario InheritedForm demuestra que se puede obtener toda la funcionalidad de Form1
con solo heredar el formulario. Una vez que ha cambiado de private a protected el modificador
de acceso de los controles miembros de Form1, label1 y dateTimePicker1, ya es posible
tener acceso a ellos desde el formulario heredado. En este ejercicio también se muestra cómo
extender la funcionalidad del formulario base en un formulario heredado.
Las aplicaciones de interfaz de múltiples documentos (MDI) son aquellas en que varias
ventanas secundarias residen en una sola ventana principal.
Las aplicaciones MDI permiten que varias ventanas compartan un solo menú de aplicación
y una sola barra de herramientas. Las aplicaciones MDI suelen tener un menú denominado
Ventana que permite a los usuarios administrar varias ventanas secundarias y ofrece
características como cambiar entre ventanas secundarias y organizar las ventanas secundarias.
Por ejemplo, la figura 5-6 muestra Microsoft Excel 2010 en modo MDI.
Figura 5-6
Microsoft Excel 2010 como
aplicación MDI
Comprensión de las aplicaciones de escritorio | 127
Las aplicaciones MDI contrastan con las aplicaciones de interfaz de un único documento
(SDI), donde cada ventana contiene su propio menú y barra de herramientas. Las aplicaciones
SDI dependen del sistema operativo para proporcionar la funcionalidad de administración de
TOME NOTA
* ventanas. Por ejemplo, en Windows, puede cambiar entre varias ventanas mediante el uso de la
Puede resultar barra de tareas de Windows.
complicado implementar Entre los diseñadores de interfaces de usuario existe diversidad de opiniones sobre cuál de
la compatibilidad con las interfaces de aplicación funciona mejor. En términos generales, las SDI se consideran más
varios monitores en adecuadas para usuarios noveles y las MDI, para usuarios avanzados. Muchas aplicaciones
las aplicaciones MDI, populares como Microsoft Word y Microsoft Excel admiten tanto SDI como MDI. Word y
porque la ventana Excel se instalan de forma predeterminada como aplicaciones SDI, pero proporcionan a los
principal tiene que usuarios la opción de cambiar entre SDI y MDI. Por ejemplo, en Word 2010 y Excel 2010,
abarcar todos los usted puede cambiar al modo MDI desactivando la opción “Mostrar todas las ventanas en la
monitores del usuario. barra de tareas” en el menú Opciones.
Figura 5-7
Adición de opciones de
menú
128 | Lección 5
6. En el formulario principal, haga doble clic en el elemento de menú Ventana > Nueva
ventana y agregue el siguiente controlador de eventos para su evento Click:
private void newWindowToolStripMenuItem_Click(
object sender, EventArgs e)
{
ChildForm child = new ChildForm();
child.MdiParent = this;
child.Show();
}
7. En el formulario principal, haga doble clic en Ventana > Organizar, Ventana > Cascada,
Ventana > Organizar, Ventana > Horizontal y Ventana > Organizar, Ventana > Vertical,
respectivamente, y agregue los siguientes controladores de eventos para sus eventos
Click:
private void cascadeToolStripMenuItem_Click(
object sender, EventArgs e)
{
LayoutMdi(MdiLayout.Cascade);
}
private void horizontalToolStripMenuItem_Click(
object sender, EventArgs e)
{
LayoutMdi(MdiLayout.TileHorizontal);
}
private void verticalToolStripMenuItem_Click(
object sender, EventArgs e)
{
LayoutMdi(MdiLayout.TileVertical);
}
Comprensión de las aplicaciones de escritorio | 129
8. Seleccione Depurar > Iniciar depuración (o presione F5) para ejecutar el proyecto.
Seleccione Ventana > Nueva ventana para crear varias ventanas secundarias nuevas.
Cambie entre las ventanas secundarias. Observe que solo hay una instancia de la apli-
cación en la barra de tareas de Windows. Ahora, use las opciones del menú Ventana
> Organizar para organizar las ventanas secundarias. Por ejemplo, una aplicación con
tres ventanas secundarias podría presentar el aspecto de la imagen que se muestra en
la figura 5-8 cuando las ventanas secundarias estén organizadas horizontalmente.
Figura 5-8
Una aplicación MDI con
tres ventanas secundarias
organizadas horizontalmente
Vamos a revisar algunos de los métodos y las propiedades importantes que hemos usado en
este ejercicio. En primer lugar, para el formulario principal, la propiedad IsMdiContainer
se establece en true. Esta propiedad indica que el formulario es un contenedor de varios
formularios secundarios MDI. Por consiguiente, para cada formulario secundario, se establece
la propiedad MdiParent a fin de especificar el formulario contenedor principal.
A continuación, se establece la propiedad MdiWindowListItem de MenuStrip con objeto de
indicar qué elemento de menú se usará para mostrar la lista de ventanas secundarias MDI. Una
vez establecida esta propiedad, el elemento de menú mostrará una lista de todas las ventanas
secundarias y, además, permitirá cambiar entre ellas. Como resultado del código del método
LISTO PARA CERTIFICACIÓN ChildForm_Load, la barra de título de cada formulario muestra la fecha y hora del instante en
¿Comprende cómo que se cargó el formulario.
desarrollar aplicaciones de Por último, el método LayoutMdi se usa en los elementos de menú del menú Ventana para
Windows Forms? organizar las ventanas secundarias. El método acepta un parámetro del tipo de enumeración
5.1 MdiLayout. El valor de la enumeración determina si las ventanas secundarias deben
organizarse en mosaico horizontal o vertical, en cascada o mostrarse como iconos.
Las aplicaciones basadas en consola no cuentan con una interfaz gráfica de usuario
CONCLUSIÓN
y usan una ventana de consola de modo de texto para interactuar con el usuario. Estas
aplicaciones son más adecuadas para tareas que requieren una interfaz de usuario
mínima o ninguna.
Como su nombre indica, una aplicación de consola se ejecuta desde la ventana de consola. La
TOME NOTA
* entrada a esta aplicación se puede proporcionar mediante parámetros de línea de comandos;
Para habilitar la lectura o bien, la aplicación puede leer interactivamente los caracteres de la ventana de consola.
o escritura en la consola Del mismo modo, la salida de una aplicación de consola se escribe también en la ventana de
desde una aplicación comandos. Puede habilitar la lectura o escritura en la consola mediante la creación de una
de Windows Forms, aplicación que use la plantilla Aplicación de consola de Visual Studio.
establezca el tipo de También puede usar aplicaciones basadas en consola para crear comandos que se ejecuten
salida del proyecto en desde la línea de comandos. Por ejemplo, puede aprovechar las canalizaciones y los filtros
aplicación de consola proporcionados por el sistema operativo para pasar la salida de un comando como entrada de
en las propiedades del otro comando; con esta combinación de comandos simples se crean otros más eficaces.
proyecto.
130 | Lección 5
En el siguiente ejercicio se crea una aplicación de consola simple que acepta el nombre de un
archivo de texto como argumento de línea de comandos y muestra el contenido de ese archivo.
Figura 5-9
Plantilla Aplicación de
consola
5. Cree un archivo de texto mediante Visual Studio o el Bloc de notas, escriba algún texto
de muestra y guarde el archivo como Sample.txt en la misma carpeta que el archivo
ejecutable. (El archivo ejecutable se crea de forma predeterminada en la carpeta
bin\debug bajo la carpeta del proyecto.)
6. Abra un símbolo del sistema y vaya a la ruta de acceso del archivo EXE del proyecto.
Ejecute el siguiente comando:
DisplayFile sample.txt
LISTO PARA CERTIFICACIÓN
Este comando debe mostrar el contenido del archivo de texto en la ventana de
¿Comprende cómo
comandos.
desarrollar aplicaciones
basadas en consola? 7. Como alternativa, también puede pasar el argumento de línea de comandos desde
5.2 Visual Studio mediante la ventana de propiedades del proyecto, como se muestra en
la figura 5-10. Para ver la ventana de propiedades del proyecto, seleccione la opción
de menú Proyecto > Propiedades de DisplayFile.
Figura 5-10
Establecimiento de las
opciones de inicio en la
ventana de propiedades del
proyecto
Por su naturaleza, los servicios de Windows son idóneos para crear programas de ejecución
prolongada que se ejecutan en segundo plano y no proporcionan directamente ninguna
interacción con el usuario. Un servicio de Windows se puede iniciar, pausar, reiniciar
y detener. También se puede definir un servicio de Windows de manera que se inicie
automáticamente al arrancar el equipo.
Algunos ejemplos de servicios de Windows son un servidor web que escucha las solicitudes
entrantes y envía una respuesta, o la cola de impresión de un sistema operativo que
proporciona servicios de impresión a los programas de aplicación.
132 | Lección 5
Dado que un servicio de Windows se puede ejecutar en segundo plano, no necesita que un
usuario haya iniciado sesión para poder funcionar. Los servicios de Windows se ejecutarán
TOME NOTA
* en su propia sesión de Windows en el contexto de seguridad especificado. Aun así, según
qué permisos se necesiten, se puede especificar una cuenta de usuario en la que ejecutar el
servicio.
Figura 5-11
Selección de la plantilla
de proyecto Servicio de
Windows
Comprensión de las aplicaciones de escritorio | 133
7. Agregue el código siguiente a los métodos de cambio de estado del servicio para
definir su comportamiento. El método WriteEntry del componente de registro de
eventos, eventLog1, se usa para escribir un mensaje en un registro de eventos. En el
método se puede especificar el tipo de mensaje. Por ejemplo, el mensaje puede ser
un mensaje de error, un mensaje de advertencia o solo un dato:
protected override void OnStart(string[] args)
{
eventLog1.WriteEntry(
"Iniciando el servicio",
EventLogEntryType.Information, 1001);
}
protected override void OnStop()
{
eventLog1.WriteEntry(
"Deteniendo el servicio",
134 | Lección 5
EventLogEntryType.Information, 1001);
}
protected override void OnPause()
{
eventLog1.WriteEntry(
"Pausando el servicio",
EventLogEntryType.Information, 1001);
}
protected override void OnContinue()
{
eventLog1.WriteEntry(
"Continuando el servicio",
EventLogEntryType.Information, 1001);
}
protected override void OnShutdown()
{
eventLog1.WriteEntry(
"Apagando el servicio",
EventLogEntryType.Information, 1001);
}
8. Seleccione Compilar > Compilar solución (o presione F6) para compilar el proyecto.
En este caso, el código de FirstService invalida los métodos OnStart, OnStop, OnPause,
OnContinue y OnShutdown para escribir mensajes en el registro de eventos. Sin embargo,
no todos los servicios requieren invalidar estos métodos. La necesidad de invalidarlos o no
depende del valor de las propiedades CanPauseAndContinue y CanShutdown del servicio de
Windows.
El método WriteEntry del registro de eventos toma el mensaje de escribir en el registro, el tipo
de entrada del registro de eventos (información, error, advertencia, etc.) y un Id. de evento, que
es un identificador específico de la aplicación que se usa para identificar el evento.
El servicio de Windows FirstService está listo, pero para poder usarlo antes es preciso
instalarlo en la base de datos del servicio de Windows. Para ello, hay que agregar un instalador
del servicio al proyecto del servicio de Windows. En el siguiente ejercicio se muestra cómo.
Figura 5-12
Vista del diseñador de
ProjectInstaller.cs
Comprensión de las aplicaciones de escritorio | 135
Figura 5-13
Uso de installutil.exe
Figura 5-14
La sección de servicios
permite trabajar con los
servicios instalados
Comprensión de las aplicaciones de escritorio | 137
Figura 5-15
Mensaje Control de servicio
mostrado al iniciar un
servicio
Figura 5-16
Registro de aplicación de
Windows
RESUMEN DE CONOCIMIENTOS
• La herencia visual permite volver a usar la funcionalidad y los diseños existentes en
formularios de Windows Forms.
• Las aplicaciones de interfaz de múltiples documentos (MDI) son aquellas en que
varias ventanas secundarias residen en una sola ventana principal.
• Las aplicaciones basadas en consola no cuentan con una interfaz gráfica de usuario y
usan una ventana de consola de modo de texto para interactuar con el usuario. Estas
aplicaciones son más adecuadas para tareas que requieren una interfaz de usuario
mínima o ninguna.
• Los servicios de Windows son idóneos para crear aplicaciones de ejecución prolonga-
da que se ejecutan en segundo plano y no presentan ninguna interfaz de usuario.
• Puede crear servicios de Windows mediante la plantilla Servicios de Windows de
Visual Studio.
• Para poder usar un servicio de Windows, es preciso instalarlo antes en el Registro de
Windows. Para ello, agregue el componente Installer a la aplicación del servicio de
Windows. Esto permite instalar el servicio de Windows mediante una herramienta de
instalación como InstallUtil.exe.
■ Evaluación de conocimientos
Rellene los espacios en blanco
Complete las oraciones siguientes escribiendo la palabra o las palabras correctas en los
espacios en blanco proporcionados.
1. Use la propiedad _________ de la clase ServiceInstaller para especificar un
comentario breve que explique el propósito del servicio.
2. La propiedad _________ de la clase _________ indica el tipo de cuenta en que se
ejecutará un servicio de Windows.
3. La propiedad _________ de la clase EventLog se usa para especificar el nombre de
aplicación que se usará al escribir en un registro de eventos.
4. _________ permite volver a usar la funcionalidad y los diseños existentes en
formularios de Windows Forms.
5. Las aplicaciones _________ son aquellas en que varias ventanas secundarias residen
en una misma ventana principal.
6. Un(a) _________ es idóneo(a) para crear aplicaciones de ejecución prolongada que
se ejecutan en segundo plano y no presentan ninguna interfaz de usuario.
7. _________ no cuentan con una interfaz gráfica de usuario y usan una ventana de
consola de modo de texto para interactuar con el usuario.
8. Las aplicaciones de _________ proporcionan su propia funcionalidad de
administración de ventanas, mientras que las aplicaciones de _________ dependen
del sistema operativo para la administración de las ventanas.
9. Un delegado puede enlazarse a cualquier método cuya signatura coincida con la de
________.
10. Los(Las) _________ se pueden enlazar a más de un método, lo que hace posibles las
notificaciones de uno a varios cuando se desencadena un evento.
Comprensión de las aplicaciones de escritorio | 139
Varias opciones
Rodee con un círculo la letra correspondiente a la mejor respuesta.
1. Tiene que diseñar un servicio de Windows que no se pueda pausar. ¿Cuál de las
siguientes opciones le ayudará a realizar esta tarea?
a. Establecer la propiedad CanPauseAndContinue del servicio de Windows en False.
b. Establecer la propiedad CanPauseAndContinue del servicio de Windows en True.
c. Establecer la propiedad CanStart del servicio de Windows en True, pero establecer
la propiedad CanShutdown en False.
d. No invalidar los métodos OnPause y OnContinue en el servicio de Windows.
2. Ha desarrollado un servicio de Windows. Tiene que instalarlo para instalar su funcio-
nalidad. ¿Cuál de las siguientes opciones debe elegir para llevar a cabo esta tarea?
a. Usar el Explorador de servidores de Visual Studio.
b. Usar el nodo Servicios de la ventana Administración de equipos.
c. Usar InstallUtil.exe.
d. Usar gacutil.exe.
3. Ha desarrollado un servicio de Windows. Este servicio se tiene que ejecutar como
usuario sin privilegios, para minimizar cualquier posibilidad de riesgos de seguridad.
¿Cuál de las siguientes cuentas debe usar para ejecutar este servicio de Windows?
a. LocalSystem
b. NetworkService
c. LocalService
d. User (cuya propiedad UserName se establece en un miembro del rol de adminis-
trador)
4. Está diseñando una aplicación de servicio de Windows que contiene un solo servicio
de Windows. Desea que este servicio se inicie automáticamente al reiniciar el equipo.
¿Cuál de las siguientes clases debería usar para especificar esta opción?
a. ServiceBase
b. ServiceInstaller
c. ServiceProcessInstaller
d. ServiceController
5. Necesita cambiar la pantalla y el comportamiento de un formulario de Windows
Forms para que pueda contener varias ventanas secundarias. ¿Qué debe hacer?
a. Establecer la propiedad IsMdiContainer del formulario en True.
b. Establecer la propiedad MdiParent de todas las ventanas secundarias.
c. Establecer la propiedad MdiChild del formulario.
d. Establecer la propiedad IsMdiChild del formulario.
6. Está desarrollando un formulario de Windows Forms que responde a los eventos del
mouse. Al mover el mouse, debe invocar el método Form1_HandleMouse. El código
que escriba no debe afectar a ningún código de control de eventos existente. ¿Qué
instrucción debe usar para asociar el controlador de eventos al evento?
a.
this.MouseDown = new MouseEventHandler
(Form1_HandleMouse);
b.
this.MouseMove = new MouseEventHandler
(Form1_HandleMouse);
c.
this.MouseDown += new MouseEventHandler
(Form1_HandleMouse);
140 | Lección 5
d.
this.MouseMove += new MouseEventHandler
(Form1_HandleMouse);
8. Está desarrollando una aplicación que se ejecutará desde la línea de comandos. ¿Cuál
de los siguientes métodos usaría para la salida de la línea de comandos?
a. Console.Read
b. Console.Write
c. File.Read
d. File.Write
9. Desea desarrollar una aplicación que muestre una superficie visual que pueda mostrar
gran variedad de controles, como cuadros de texto, botones y menús. La aplicación
también debe permitir que varias ventanas secundarias residan en una ventana princi-
pal única. ¿Cuál de los siguientes tipos de aplicación debe desarrollar?
a. Una aplicación basada en consola
b. Una aplicación de servicio de Windows
c. Una aplicación de interfaz de un único documento (SDI)
d. Una aplicación de interfaz de múltiples documentos (MDI)
10. Está extendiendo una aplicación existente de Windows. Desea crear un nuevo formu-
lario que derive sus características visuales (lo que incluye tamaño, color y algunos
controles) de un formulario creado anteriormente. ¿Qué técnica debería usar para
crear el nuevo formulario?
a. Herencia visual
b. Encapsulación visual
c. Abstracción visual
d. Polimorfismo visual
■ Evaluación de competencias
Escenario 5-1: Uso de la herencia visual
Tiene que crear un formulario de Windows Forms similar al que creó en el ejercicio de
VisualInheritance. Sin embargo, esta vez el requisito es que el color de fondo de este
formulario coincida con el color seleccionado del escritorio del usuario. ¿Cómo se puede
desarrollar este formulario?
■ Evaluación de aptitudes
Escenario 5-3: Trabajo con entrada de consola
Está desarrollando un programa que manipula texto. Debe escribir una aplicación basada
en consola que acepta texto del usuario y que lo convierte a mayúsculas. ¿Qué código debe
escribir para cumplir con este requisito?
TÉRMINOS CLAVE
aplicaciones desconectadas diseño de bases de datos procedimiento almacenado
archivos planos relacionales procedimientos almacenados
atributo elemento parametrizados
base de datos instrucciones de procesamiento segunda forma normal (2FN)
base de datos relacional integridad de bases de datos sistema de administración de
clave principal Lenguaje de consulta bases de datos (DBMs)
DataSet estructurado (SQL) tercera forma normal (3FN)
dependencia funcional Lenguaje de marcado
extensible (XML)
diagramas de relación entre
entidades (ERD) normalización
primera forma normal (1FN)
Una base de datos permite almacenar, mantener y recuperar datos importantes. Si una base
de datos está diseñada correctamente, la pueden usar varias aplicaciones y varios usuarios.
Un sistema de administración de bases de datos (DBMS), por su parte, es un software que
organiza las bases de datos y proporciona características tales como almacenamiento, acceso
a datos, seguridad, copia de seguridad, etc. Algunos DBMS conocidos son, por ejemplo,
Microsoft SQL Server, Microsoft Access, Oracle y MySql.
Los sistemas de administración de bases de datos se pueden implementar de acuerdo con
diferentes modelos. De estos modelos, el relacional es el más popular. En el modelo relacional,
los datos se organizan en tablas, cada una de las cuales puede tener varias filas. Los DBMS
basados en modelos relacionales se denominan DBMS relacionales (RDBMS). SQL Server,
Access, Oracle y MySql son RDBMS.
Otros sistemas de administración de bases de datos se basan en diferentes modelos. Por
ejemplo, los DBMS de objetos (ODBMS) se basan en el modelo de objetos, en el cual
los datos se almacenan como una colección de objetos. Sin embargo, en esta lección nos
centraremos únicamente en las bases de datos relacionales más populares.
Los DBMS relacionales usan el Lenguaje de consulta estructurado (SQL) para recuperar
y manipular los datos. Los sistemas de administración de bases de datos relacionales más
conocidos proporcionan compatibilidad con la versión estándar de SQL, lo que le permitirá
usar sus conocimientos en distintos sistemas de bases de datos relacionales.
Una base de datos relacional organiza los datos en tablas bidimensionales que
constan de filas y columnas.
Una base de datos relacional organiza la información en tablas. Una tabla es una lista de filas
y columnas, conceptualmente similar a una hoja de cálculo de Microsoft Excel. A las filas
también se las denomina registros o tuplas y a las columnas, campos. La columna o campo
especifica el tipo de datos que se almacenará para cada registro de la tabla. Por ejemplo, los
pedidos de clientes se pueden almacenar en una tabla denominada Orders (Pedidos) en que
cada fila represente un único pedido. En esta tabla, se pueden usar columnas, como OrderDate
(Fecha pedido), para especificar que un valor válido es del tipo de datos correcto. En la figura
6-1 se muestra un ejemplo de tabla de pedidos.
Figura 6-1
Tabla de pedidos de una
base de datos relacional
144 | Lección 6
Los datos de una organización son uno de sus activos más importantes. Por lo tanto, garantizar
la integridad de la base de datos debe ser uno de los principios rectores al diseñarla. Por
integridad entendemos que los datos de la base de datos sean exactos y coherentes en todo
momento.
El proceso de diseño de bases de datos consta de los siguientes pasos:
1. Desarrollar una declaración de objetivos de la base de datos: identifica el propósito
de la base de datos, cómo se usará y quién la usará. En este paso se marca la pauta para el
resto del proceso de diseño.
2. Determinar los datos que se desea almacenar: identifica todos los tipos de datos que
deben almacenarse en la base de datos. Generalmente, esta información se recopila
durante la tarea de análisis de requisitos, mediante diagramas de relación entre entidades.
3. Dividir los datos en tablas y columnas: identifica las tablas y la información que se
desea almacenar en ellas.
4. Elegir las claves principales: una clave principal es una columna o conjunto de
columnas que identifica de forma exclusiva cada fila de datos de una tabla.
5. Identificar las relaciones: identifica cómo se relacionan los datos de una tabla con los de
otra. Por ejemplo, para cada cliente de una tabla denominada Customers (Clientes), puede
haber muchos pedidos en la tabla Orders (Pedidos); esta relación se denomina relación de
uno a varios.
6. Aplicar el proceso de normalización: aplica las reglas de normalización de datos para
asegurarse de que se resuelvan todos los problemas que pueden afectar a la integridad
de los datos. Aprenderemos más sobre el proceso de normalización más adelante en esta
lección.
Una vez que se ha establecido el propósito de una base de datos, los siguientes pasos (del 2
al 5) se pueden realizar durante el modelado de relación entre entidades. A continuación, el
último paso de la normalización puede aplicarse a la salida de este modelo.
Los diagramas de relación entre entidades (ERD) se usan para modelar las entidades,
sus atributos y las relaciones entre ellas. Los diagramas de relación entre entidades
pueden ayudarle a determinar qué datos es preciso almacenar en una base de datos.
El modelado de relación entre entidades es un proceso que se usa para crear el modelo de
datos conceptual de un sistema; los diagramas de relación entre entidades son las herramientas
gráficas de modelado gráfico que permiten realizar este proceso. Los bloques de creación
básicos de un ERD son la entidad, el atributo y la relación:
• Entidad: una entidad es una construcción de un objeto físico o un concepto. Algunos
ejemplos de entidades son un pedido, un cliente, un empleado, etc. Una entidad suele
designarse por el sustantivo que representa.
• Atributo: los atributos son las propiedades específicas de una entidad. Por ejemplo,
si la entidad es Order, algunos atributos útiles pueden ser OrderNumber, OrderDate,
ShipDate y ShipVia (respectivamente, Número pedido, Fecha pedido, Fecha envío y
Transportista). Del mismo modo, si la entidad es Empleado, algunos atributos útiles
pueden ser EmployeeId, LastName, FirstName, Title y HireDate (respectivamente, Id.
empleado, Apellidos, Nombre, Cargo y Fecha contratación). Cada entidad debe contar
con un conjunto de atributos que lo identifican de forma exclusiva y se denominan clave
principal de la entidad. Por ejemplo, OrderNumber es un atributo que identifica de forma
exclusiva un pedido, por lo que es una clave principal de la entidad Order (Pedido).
Comprensión de bases de datos | 145
• Relación: una relación es una asociación entre las entidades. Por ejemplo, Takes (Acepta)
es una relación entre las entidades Employee (Empleado) y Order (Pedido) (es decir,
Employee Takes Order, que significa Empleado Acepta Pedido).
Tenga en cuenta que los ERD no muestran entidades ni relaciones individuales. Por ejemplo,
puede haber miles de entidades Order y cientos de entidades Customer (Cliente). Así pues, en
estos diagramas se muestran conjuntos de entidades y de relaciones; por ejemplo, los miles de
entidades Order pueden constituir un único conjunto de entidades. De hecho, cuando aparece
Order o Customer en un ERD, generalmente se refiere a un conjunto de entidades, no a una
entidad individual.
Los ERD usan algunas convenciones de diseño. En concreto:
• Un rectángulo representa un conjunto de entidades.
• Una elipse representa un atributo.
• Un rombo representa un conjunto de relaciones.
• Las líneas continuas vinculan los conjuntos de entidades a los conjuntos de
relaciones y a los atributos.
En la figura 6-2 se muestra un ejemplo de ERD. En este diagrama, los dos conjuntos de
entidades son Customer y Order. Los atributos asociados con el cliente son ID (Identificador),
Name (Nombre) y City (Ciudad). Los atributos asociados con Order son OrderID, OrderDate
y ShipDate (respectivamente, Id. pedido, Fecha pedido y Fecha envío). Los atributos que
constituyen una clave principal están subrayados. Además, como se muestra en la figura, la
relación entre Customer y Order es Places (Realiza).
Figura 6-2
Diagrama de relación entre
entidades
En un ERD, se puede clasificar una relación como una relación de uno a uno, de uno a varios
o de varios a varios. En la figura 6-2, la línea que conecta la relación Places con el conjunto
de entidades Customer tiene la etiqueta “1”, mientras que la línea que conecta Places con el
conjunto de entidades Order tiene la etiqueta “N”. Este es un ejemplo de una relación de uno a
varios. En esta relación, un cliente puede realizar muchos pedidos, pero un pedido solo puede
tener asociado un cliente.
Cuando se asigna a una base de datos relacional, el ERD de la figura 6-2 genera las siguientes
tablas:
Customers
ID Name City
1001 Jane Doe Berlín
1002 John Doe Tokio
1003 Howard Steel Sidney
Orders
En análisis de relación entre entidades ayuda a asegurarse de haber identificado los elementos
de datos correctos para la base de datos. Luego, a través del proceso de normalización
de datos, se aplica un conjunto de reglas de normalización para asegurarse de que se ha
establecido el diseño de base de datos correcto; es decir, se comprueba si las columnas
pertenecen a las tablas correctas con objeto de asegurarse de que la base de datos esté libre de
problemas no deseados.
Por ejemplo, como parte del análisis de relación entre entidades, se podría descubrir una tabla
denominada Books (Libros) con las siguientes columnas:
Books
Para que esta tabla sea conforme con 1FN, es preciso dividirla en dos:
Cliente
Id FirstName LastName
1 Jane Doe
2 John Doe
3 Howard Steel
CustomerPhones
Id PhoneNumber
1 (503) 555-6874
2 (509) 555-7969
2 (509) 555-7970
3 (604) 555-3392
3 (604) 555-3393
148 | Lección 6
Ahora, tanto la tabla Customers como la tabla CustomerPhones (Teléfonos clientes) cumplen
con 1FN. Ambas tablas tienen una clave principal (el Id. de la primera tabla y la combinación
de Id. y PhoneNumber en la segunda tabla) que establece una relación entre ellas. Para
cualquier Id. de un cliente, puede encontrar todos los números de teléfono que le pertenecen
sin ninguna confusión. Por otro lado, LastName no es una clave principal porque puede haber
entradas de apellidos duplicadas.
2FN solo se aplica a las tablas que tienen claves principales compuestas (es decir, cuando
varias columnas tomadas juntas conforman la clave principal). Los valores combinados de
*
TOME NOTA todos los campos de una clave principal compuesta deben ser únicos. Si una tabla satisface
1FN y tiene una sola columna en su clave principal, entonces la tabla también se ajusta a
2FN.
Orders
En ella, las columnas OrderId (Id. pedido) y CustomerId (Id. cliente) identifican
conjuntamente una fila exclusiva y, por lo tanto, constituyen una clave principal compuesta.
Sin embargo, la columna OrderDate solo depende funcionalmente de OrderId y la columna
CustomerName solo depende de CustomerId. Esto infringe 2FN, porque las columnas no clave
son funcionalmente dependientes solo de una parte de la clave principal.
Una manera posible de modificar la tabla Orders de modo que se ajuste a 2FN es sacar
CustomerName de la tabla y tener solo tres columnas (OrderId, CustomerId y OrderDate),
de tal forma que únicamente OrderId constituya la clave principal. En esta solución, tanto
CustomerId como OrderDate dependen funcionalmente de OrderId, en consecuencia,
satisfacen 2FN.
Comprensión de bases de datos | 149
Aquí, ItemId (Id. artículo) es la clave principal. Sin embargo, ReorderFax (Fax reclamación)
es un número de fax del proveedor y, por lo tanto, depende funcionalmente de SupplierId (Id.
proveedor). Para satisfacer el requisito de 3FN, esta tabla debe descomponerse en dos tablas:
Items (Artículos) (ItemId, SupplierId) y Supplier (Proveedor) (SupplierId, ReorderFax).
Items
ItemId SupplierId
101 100
102 11
103 525
Supplier
En SQL, le decimos a la base de datos lo que tiene que hacer y es la propia base de datos
la que debe averiguar cómo hacerlo; por ejemplo, podemos pedirle a la base de datos que
seleccione las 10 primeras filas de una tabla. Comparemos este proceder con un lenguaje de
programación imperativo como C#, en el que hay que especificar con todo detalle el trabajo
que debe realizar. Por ejemplo, en este caso, habría que crear un bucle que se ejecute diez
veces, configurar e inicializar variables, mover punteros de registros, etc.
SQL es un estándar de ANSI (American National Standards Institute), pero los diversos
proveedores de bases de datos han implementado sus propias extensiones del SQL estándar. La
implementación de SQL de Microsoft SQL Server se denomina Transact-SQL (T-SQL).
Existen dos modos principales de enviar T-SQL a SQL Server. Se pueden usar instrucciones
SQL ad hoc, que se ejecutan directamente, o bien procedimientos almacenados. Los
procedimientos almacenados son colecciones de instrucciones SQL y lógica de programación
que se almacenan en el servidor de bases de datos como objetos con nombre.
Las instrucciones SELECT, INSERT, UPDATE y DELETE son los cuatro tipos
principales de instrucciones SQL que se usan para manipular datos de SQL Server.
El uso de consultas ad hoc de SQL es una manera flexible de trabajar con bases de datos de
SQL Server. En esta parte de la lección, aprenderemos los conceptos básicos de los cuatro
tipos principales de instrucciones SQL que le ayudan a manipular datos de SQL Server:
• Las instrucciones SELECT permiten recuperar los datos almacenados en una base de
datos.
• Las instrucciones INSERT permiten agregar nuevos datos a una base de datos.
• Las instrucciones UPDATE permiten modificar los datos existentes en una base de
datos.
• Las instrucciones DELETE permiten borrar datos de una base de datos.
CONEXIÓN A UNA BASE DE DATOS DE SQL SERVER
Para poder manipular la información de una base de datos de SQL Server, previamente
deberá conectarse a ella.
En este ejercicio, aprenderemos a trabajar con una base de datos de Microsoft SQL Server. Si
no dispone de acceso a una versión reciente de SQL Server, puede descargar SQL Server 2008
Express gratis desde www.microsoft.com/express/database. En este ejercicio se usa la base
de datos de ejemplo de SQL Server denominada Northwind. Esta base de datos no se instala
de forma predeterminada con SQL Server, pero puede descargar el archivo de base de datos
siguiendo las instrucciones en www.msdn.com/es-es/library/ms143221.aspx.
Complete el siguiente ejercicio para conectarse a la base de datos Northwind con Visual Studio
y usarla.
Figura 6-3
Conexión a la base de datos
Northwind
Figura 6-5
Ventana Propiedades de la
base de datos Northwind
PAUSA. En el próximo ejercicio, obtendremos acceso a los datos desde la base de datos
Northwind.
Existen varios modos de comunicarse con SQL Server para llevar a cabo consultas de
base de datos.
Hay muchas maneras de enviar consultas a un servidor SQL Server. Por ejemplo, podemos
usar cualquiera de las siguientes:
• Entorno de desarrollo integrado (IDE) de Visual Studio
• Aplicación C#
• Analizador de consultas SQL
• Utilidad de símbolo del sistema osql
Observe que el Analizador de consultas SQL y las utilidades de símbolo del sistema osql son
herramientas instaladas con SQL Server.
PREPÁRESE. Para usar el IDE de Visual Studio y las aplicaciones C# para ejecutar consultas
SQL, siga estos pasos:
1. Seleccione la base de datos Northwind en el Explorador de servidores. Haga clic con
el botón secundario en la base de datos y seleccione Nueva consulta. Esta acción abre
un diseñador de consultas y muestra el cuadro de diálogo Agregar tabla. Seleccione la
tabla Customers (Clientes) y haga clic en Agregar. Haga clic en Cerrar en el cuadro de
diálogo Agregar tabla.
2. En el panel de SQL del diseñador de consultas (que es la zona que muestra el texto de
la consulta), modifique la instrucción SQL de la manera siguiente:
SELECT * FROM Customers
3. En el menú Visual Studio, seleccione la opción Diseñador de consultas > Ejecutar SQL
o haga clic en el botón Ejecutar SQL de la barra de herramientas. La instrucción SQL
se enviará al servidor SQL Server para su ejecución y se mostrarán unos resultados
parecidos a los de la figura 6-6.
Comprensión de bases de datos | 153
Figura 6-6
Diseñador de consultas de
Visual Studio
El diseñador de consultas de Visual Studio muestra hasta cuatro paneles. De arriba abajo, los
paneles son:
• Panel de diagrama: este panel muestra las tablas implicadas en la consulta y las
relaciones entre ellas, así como todas las columnas que contienen las tablas.
• Panel de criterios: el panel de criterios muestra las columnas que se han seleccionado en
la consulta, así como información adicional de clasificación y filtrado.
• Panel de SQL: este panel muestra la instrucción SQL real que se ejecutará.
• Panel de resultados: este panel muestra los resultados (si los hay) después de ejecutar la
consulta.
La barra de herramientas del diseñador de consultas incluye botones que puede usar para
ocultar o mostrar cualquiera de estos cuatro paneles. En el ejercicio siguiente, solamente
necesitaremos los paneles de SQL y de resultados.
Figura 6-7
Ejecución de consultas desde
una aplicación C#
Comprensión de bases de datos | 155
SELECCIÓN DE DATOS
La instrucción SELECT se usa para recuperar datos de una o más tablas de la base de
datos.
Esta consulta indica a SQL Server que tome cada fila de la tabla Orders y la haga coincidir
con todas las filas de la tabla Customers en que el valor de CustomerId del pedido sea igual
al valor de CustomerId del cliente. Dado que CustomerId es exclusivo en la tabla Customers,
esto equivale a incluir una sola fila para cada pedido en el conjunto de resultados. En este
caso, el conjunto de resultados tendrá tantas filas como la tabla Orders.
Pero ¿qué sucede si solamente queremos ver algunas de las filas de la tabla? En esta situación,
podemos usar la cláusula WHERE. La cláusula WHERE evalúa cada fila para comprobar si se
TOME NOTA
* cumple una condición y decide si la incluirá en el conjunto de resultados. Por ejemplo:
El delimitador estándar SELECT *
para el texto y las fechas
en SQL Server es la FROM Orders
comilla simple. WHERE ShipCountry = 'Canada'
Aquí, la cláusula WHERE busca en todas las filas de la tabla Orders para comprobar si
ShipCountry (País envío) tiene el valor exacto “Canada” (Canadá). En caso afirmativo, la fila
se incluye en el conjunto de resultados; en caso negativo, no se incluye.
También podemos combinar varias condiciones en una sola cláusula WHERE. Por ejemplo:
SELECT *
FROM Orders
WHERE (ShipCountry = 'Canada')
AND (OrderDate >= '01/01/97')
AND (OrderDate <= '01/31/97')
Aquí, las condiciones WHERE filtran los pedidos cuyo ShipCountry es “Canada” y cuya fecha
es “January 1997” (Enero de 1997).
De forma predeterminada, SQL no garantiza que los resultados se muestren en un orden
determinado. Sin embargo, podemos usar la cláusula ORDER BY para asegurarnos de que
los datos deseados se devuelvan en un orden concreto. Por ejemplo, para mostrar una lista de
pedidos ordenados por su fecha de realización, podemos usar la siguiente consulta:
SELECT *
FROM Orders
WHERE (ShipCountry = 'Canada')
AND (OrderDate >= '01/01/97')
AND (OrderDate <= '01/31/97')
ORDER BY OrderDate
Podemos modificar el orden mediante las palabras clave ASC (en orden ascendente) o DESC
(en orden descendente). El orden predeterminado es el ascendente. Por lo tanto, la consulta
siguiente muestra los pedidos más recientes al principio:
SELECT *
FROM Orders
WHERE (ShipCountry = 'Canada')
AND (OrderDate >= '01/01/97')
AND (OrderDate <= '01/31/97')
ORDER BY OrderDate DESC
Comprensión de bases de datos | 157
Es bastante frecuente que las aplicaciones empresariales soliciten datos agregados o resumidos.
Estos requisitos pueden satisfacerse mediante la cláusula GROUP BY y las funciones de
agregado. Por ejemplo, podemos usar la siguiente consulta para encontrar a qué países se
envían la mayor parte de los pedidos:
SELECT ShipCountry, COUNT(ShipCountry) AS OrderCount
FROM Orders
GROUP BY ShipCountry
ORDER BY OrderCount DESC
Esta consulta mostrará el nombre de cada país, seguido del número total de pedidos enviados a
ese país. La cláusula ORDER BY ordena el resultado y coloca a los países con más pedidos en
la parte superior de la lista.
Podemos imaginarnos que la cláusula GROUP BY crea “depósitos”; en este caso, uno por cada
país. A medida que el motor de la base de datos examina cada registro, lo coloca en el depósito
apropiado. Una vez finalizado este proceso, el motor de base de datos cuenta el número de
registros que ha colocado en cada depósito y muestra en la salida una fila para cada uno de
ellos. En la figura 6-8 se muestra el comienzo del resultado de esta consulta.
Figura 6-8
Uso de la cláusula GROUP BY
para resumir información
ACTUALIZACIÓN DE DATOS
Otra instrucción SQL útil es UPDATE. La finalidad de una instrucción UPDATE es actualizar
o modificar datos. Por ejemplo, podemos actualizar un campo de un registro de la tabla
Customers mediante la siguiente consulta:
UPDATE Customers
SET ContactName = 'Maria Anderson'
WHERE CustomerId = 'ALFKI'
158 | Lección 6
En esta consulta, la palabra clave SET indica a SQL Server qué columnas debe actualizar y la
TOME NOTA
* palabra clave WHERE indica qué filas se van a actualizar. En la tabla Customers, CustomerId
En una instrucción es una clave principal que identifica de forma exclusiva una sola fila. Por lo tanto, esta
UPDATE, la cláusula instrucción UPDATE puede actualizar como máximo una fila.
SET es obligatoria y
solo se puede especificar Sin embargo, cabe destacar que no estamos limitados a actualizar un único registro. Por el
una vez. contrario, si la cláusula WHERE selecciona varios registros, todos ellos se actualizarán:
UPDATE Customers
SET Country = 'United States'
TOME NOTA
* WHERE Country = 'USA'
Se recomienda
encarecidamente revisar También podemos actualizar más de un campo a la vez con una instrucción UPDATE, como
con todo cuidado la en el ejemplo siguiente:
cláusula WHERE UPDATE Customers
para cada instrucción
SET ContactName = 'Maria Anderson',
UPDATE. Si no
presta atención, podría CITY = 'Tokyo'
actualizar los datos WHERE CustomerId = 'ALFKI'
en más filas de las
deseadas.
INSERCIÓN DE DATOS
La instrucción INSERT se usa para agregar una o más filas a una tabla de la base de
datos.
El comando INSERT enumera los campos de la tabla de destino seguidos por un conjunto
de valores que se insertarán en estos campos. Por ejemplo, la siguiente instrucción INSERT
inserta una fila en la tabla Order Details (Detalles de pedidos):
INSERT INTO [Order Details]
(OrderId, ProductId, UnitPrice, Quantity, Discount)
VALUES (10248, 2, 19.00, 2, 0)
Los corchetes son obligatorios cuando los nombres de las tablas o los campos contienen
espacios. En este caso, el primer conjunto de paréntesis contiene una lista de columnas y el
segundo, los valores que se deben insertar. Si un campo tiene un valor predeterminado, puede
ser null o es un campo de identidad, podemos dejarlo fuera de la lista de campos, como en el
ejemplo siguiente:
INSERT INTO [Order Details]
(OrderId, ProductId, UnitPrice, Quantity)
VALUES (10249, 2, 19.00, 2)
Esta instrucción funciona aunque no se haya especificado ningún valor para el campo Discount
(Descuento). Además, esta instrucción nos permite reorganizar la lista de campos siempre y
cuando reorganicemos la lista de valores del mismo modo:
INSERT INTO [Order Details]
(ProductId, OrderId, UnitPrice, Quantity)
VALUES (2, 10250, 19.00, 2)
La instrucción INSERT no se limita a insertar un único registro. De hecho, hay un segundo
formato que inserta los resultados de una instrucción SELECT en la tabla de destino. Por
ejemplo, esta consulta inserta un producto de cada proveedor en la tabla Products (Productos):
INSERT INTO Products
(SupplierId, ProductName, CategoryId)
SELECT SupplierId, 'Almond', 7
FROM Suppliers
Comprensión de bases de datos | 159
Esta consulta genera los resultados de la instrucción SELECT y, a continuación, incluye cada
una de las filas devueltas por las instrucciones SELECT en la tabla de destino. Por supuesto,
las columnas deben coincidir correctamente también en este caso.
ELIMINACIÓN DE DATOS
La instrucción DELETE se usa para quitar información de las tablas de la base de datos.
La instrucción DELETE elimina los datos de una tabla. Para practicar y evitar que se eliminen
los datos de la misma base de datos, puede copiar una tabla mediante una instrucción
SELECT, como en el ejemplo siguiente:
SELECT * INTO CustomersCopy
FROM Customers
Esta instrucción selecciona todos los registros de la tabla Customers y los copia en una tabla
nueva denominada CustomersCopy (Copia clientes).
Para eliminar una fila de datos de la tabla CustomersCopy, usamos la siguiente instrucción
DELETE:
DELETE FROM CustomersCopy
WHERE CustomerId = 'ALFKI'
Es preciso extremar las precauciones porque, si omitimos la cláusula WHERE, eliminaremos
todos los datos de la tabla:
DELETE FROM CustomersCopy
PREPÁRESE. Para crear un procedimiento almacenado desde Visual Studio, realice las
siguientes acciones:
1. Abra el Explorador de servidores y seleccione la base de datos Northwind. Haga clic
con el botón secundario en el nodo Procedimiento almacenado y seleccione la opción
Agregar nuevo procedimiento almacenado.
2. En el diseñador de procedimientos almacenados, sustituya el texto del documento por el
siguiente código:
CREATE PROCEDURE GetCustomersFromFrance
AS
SELECT * FROM Customers
Where Country = 'France'
RETURN
TOME NOTA
* 3. Guarde el procedimiento almacenado. El procedimiento almacenado se agregará a la base
Puede usar la de datos.
instrucción ALTER 4. Para ejecutar el procedimiento almacenado, haga clic en él con el botón secundario
PROCEDURE para en el Explorador de servidores y seleccione Ejecutar. El resultado del procedimiento
modificar la definición almacenado debe mostrarse en la ventana de salida.
de un procedimiento 5. También puede ejecutar este procedimiento almacenado desde el proyecto QueryCS que
almacenado existente. creó anteriormente. Aquí, en lugar de una instrucción SQL, solo hay que escribir el nombre
del procedimiento almacenado y hacer clic en el botón Ejecutar SQL. El resultado del
procedimiento almacenado se mostrará en el formulario de Windows Forms.
AS
SELECT @TotalSales = SUM(Quantity * UnitPrice)
FROM (Customers INNER JOIN Orders
ON Customers.CustomerId = Orders.CustomerId)
INNER JOIN [Order Details]
ON Orders.OrderId = [Order Details].OrderId
WHERE Customers.CustomerId = @CustomerId
RETURN
3. Guarde el procedimiento almacenado. El procedimiento almacenado se agregará a la
base de datos.
En este procedimiento almacenado, tanto @CustomerId como @TotalSales son parámetros.
@CustomerId es un parámetro de entrada; debe proporcionar un valor para este parámetro al
ejecutar el procedimiento almacenado. @TotalSales es un parámetro de salida; devuelve un
valor desde el procedimiento almacenado. Al ejecutar este procedimiento almacenado desde
Visual Studio, se abre un cuadro de diálogo que pide que se especifique el valor de todos los
parámetros, como se muestra en la figura 6-9.
Figura 6-9
El cuadro de diálogo Ejecutar
procedimiento almacenado
solicita los valores de los
parámetros
Para ejecutar este procedimiento almacenado, especifique ALFKI como valor de @CustomerId
y NULL como valor de @TotalSales. Al hacer clic en el botón Aceptar, el valor calculado del
parámetro de salida, @TotalSales, se muestra en la ventana de salida.
Sin embargo, un procedimiento almacenado parametrizado no se puede ejecutar desde el
proyecto QueryCS, porque su código no acepta parámetros.
PREPÁRESE. Para ejecutar procedimientos almacenados parametrizados desde C#, realice las
siguientes tareas:
1. Cree un nuevo proyecto de aplicación de Windows denominado ParameterizedSP.
2. Coloque un control Label en el formulario y establezca su propiedad Text
en “Id. cliente:”. Coloque un control TextBox junto a él y asígnele el nombre
CustomerIdTextBox. A continuación, coloque un control Button y establezca su
propiedad Name en GetTotalSalesButton y su propiedad Text propiedad en “Obtener
ventas totales”. Por último, coloque un control Label en el formulario y asígnele el
nombre TotalSalesLabel. Organice los controles para lograr una apariencia similar a la
de la figura 6-10.
162 | Lección 6
3. Haga doble clic en el control Button para generar un controlador de eventos para su
evento Click. Modifique el controlador de eventos como se muestra a continuación:
private void GetTotalSalesButton_Click(
object sender, EventArgs e)
{
TotalSalesLabel.Text = String.Format(
"Ventas totales: {0}",
GetTotalSales(CustomerIdTextBox.Text));
}
4. Agregue el método siguiente a la clase. Asegúrese de cambiar la cadena de conexión
para que coincida con la ruta local del archivo de base de datos de su equipo:
private double GetTotalSales(string customerId)
{
double totalSales = −1;
try
{
// Cambie la cadena de conexión
// de modo que coincida con su sistema.
string connectionString =
@"Data Source=.\SQLEXPRESS;" +
@"AttachDbFilename=" +
@"c:\SqlSampleDB\NORTHWND.MDF;" +
@"Integrated Security=True;" +
@"Connect Timeout=30;User Instance=True";
SqlConnection connection =
new SqlConnection(connectionString);
SqlCommand command =
connection.CreateCommand();
command.CommandType =
CommandType.StoredProcedure;
command.CommandText = "GetCustomerSales";
command.Parameters.AddWithValue(
"@CustomerId", customerId);
command.Parameters.AddWithValue(
"@TotalSales", null);
command.Parameters["@TotalSales"].DbType
= DbType.Currency;
command.Parameters["@TotalSales"].Direction
= ParameterDirection.Output;
connection.Open();
command.ExecuteNonQuery();
totalSales = Double.Parse(
Comprensión de bases de datos | 163
command.Parameters["@TotalSales"]
.Value.ToString());
connection.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return totalSales;
}
5. Agregue las siguientes directivas using al código:
using System.Data;
using System.Data.SqlClient;
Seleccione Depurar > Iniciar depuración para ejecutar el proyecto. Especifique un Id.
de cliente válido. Debe aparecer la salida que se muestra en la figura 6-10.
Figura 6-10
Ejecución de procedimientos
almacenados parametrizados
desde una aplicación C#
Si agrega una nueva fila a una tabla con una columna de identidad, puede usar la variable
@@IDENTITY de SQL Server para recuperar el valor de la columna de identidad
*
TOME NOTA
correspondiente a la fila recién creada.
C# también proporciona una instrucción using que nos puede ayudar a asegurarnos de que
TOME NOTA
* los objetos costosos, tales como las conexiones de base de datos, se cierren automáticamente
El objeto que se usa con cuando hemos terminado de usarlos. A continuación se muestra una versión alternativa del
la instrucción using debe código anterior que usa la instrucción using para cerrar automáticamente la conexión de bases
implementar la interfaz de datos:
IDisposable.
// eliminación de objetos mediante la instrucción using
using (connection)
LISTO PARA CERTIFICACIÓN {
¿Comprende los diversos
connection.Open();
métodos de consulta de
bases de datos? command.ExecuteNonQuery();
6.2 totalSales = Double.Parse(
command.Parameters["@TotalSales"]
LISTO PARA CERTIFICACIÓN .Value.ToString());
¿Comprende los }
métodos de conexión
de bases de datos? Observe que la instrucción using define un ámbito para el objeto de conexión. Cuando el
6.3 código llega al final de ese ámbito, el objeto de conexión se cierra automáticamente y se
liberan todos los recursos.
Las aplicaciones empresariales pueden requerir datos en varios formatos. Por ejemplo,
CONCLUSIÓN es posible que debamos trabajar con archivos planos, archivos XML y objetos en
memoria.
.NET Framework proporciona clases que están optimizadas para funcionar con archivos
planos, archivos XML y objetos en memoria. Los datos almacenados en archivos planos se
pueden controlar mediante las clases del espacio de nombres System.IO. Para trabajar con
datos XML, se pueden usar las clases del espacio de nombres System.Xml. Por último, para
trabajar con objetos en memoria como DataSet, se usan las clases del espacio de nombres
System.Data. En las secciones siguientes aprenderemos cómo trabajar con cada uno de estos
formatos de datos.
Un archivo plano suele contener una fila de datos por línea y sus columnas están separadas por
delimitadores, como comas, o tienen una longitud fija. Los datos de un archivo plano pueden
ser de texto o binarios. Estos archivos se denominan “archivos planos” para distinguirlos de
otras formas de almacenamiento más estructuradas, como las bases de datos relacionales y los
archivos XML.
Históricamente, antes del advenimiento de las bases de datos modernas, los archivos planos
eran una forma popular de almacenar y organizar la información. Siguen siendo útiles hoy
en día, aunque solamente en algunas situaciones y no como bases de datos de uso general.
Algunos de los lugares donde se usan archivos planos son el sistema operativo, los archivos
de configuración de aplicaciones, al realizar transferencias de datos a sistemas remotos y al
migrar datos entre sistemas incompatibles.
La entrada y salida basada en archivos de .NET Framework gira en torno a los conceptos de
las secuencias y las memorias auxiliares. Una secuencia es un flujo de datos sin procesar;
la memoria auxiliar es el origen o destino de la secuencia. Una memoria auxiliar puede ser
un archivo de disco, memoria, conexión de red, etc. Encontrará clases para trabajar con las
secuencias y las memorias auxiliares en el espacio de nombres System.IO.
Comprensión de bases de datos | 165
Como hemos mencionado anteriormente, el formato de los archivos planos puede ser de texto
o binario. Los archivos de texto se organizan con frecuencia como líneas de texto separadas
por caracteres de fin de línea. Las clases StreamReader y StreamWriter proporcionan una
manera fácil de manipular dichos archivos de texto.
Los archivos binarios almacenan su contenido como una secuencia de bytes. Aunque los
archivos binarios no son legibles como los archivos de texto, permiten almacenar gran
variedad de datos, tales como imágenes, sonidos, vídeo, etc. Para interpretar el contenido de
un archivo binario siempre se necesita un programa informático. Las clases BinaryReader y
BinaryWriter proporcionan una manera fácil de manipular los archivos binarios.
En el siguiente ejercicio, seleccionaremos columnas de la tabla Customers y las escribiremos
en un archivo de texto. Más tarde, abriremos este archivo de texto y mostraremos su contenido
en la ventana de consola.
command.CommandText =
"SELECT CustomerId, CompanyName,"
+ "ContactName, Phone FROM Customers";
using (connection)
{
connection.Open();
SqlDataReader reader =
command.ExecuteReader();
using (StreamWriter sw =
new StreamWriter(fileName))
{
while (reader.Read())
{
string customerRow =
String.Format("{0}, {1}, {2}, {3}",
reader.GetValue(0),
reader.GetValue(1),
reader.GetValue(2),
reader.GetValue(3));
sw.WriteLine(customerRow);
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
static void DisplayTextFile(string fileName)
{
try
{
using (StreamReader sr =
new StreamReader(fileName))
{
string line;
while ((line = sr.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
}
Comprensión de bases de datos | 167
En XML, puede almacenar tanto datos y como metadatos (información sobre los datos
almacenados). Por ejemplo, el siguiente código XML representa los datos de dos clientes:
<?xml version="1.0" encoding="utf-8"?>
<!--Customer List-->
<Customers>
<Customer Id="ALFKI">
<CompanyName>Alfreds Futterkiste</CompanyName>
<Phone>030-0074321</Phone>
</Customer>
<Customer Id="EASTC">
<CompanyName>Eastern Connection</CompanyName>
<Phone>(171) 555-0297</Phone>
</Customer>
</Customers>
Incluso sin saber nada acerca de XML, podemos entender el contenido de este archivo
con solo mirarlo. XML consta de etiquetas (contenidas entre corchetes angulares) y datos.
Las etiquetas siempre aparecen en pares, de tal forma que a cada etiqueta de apertura le
corresponde una de cierre. Por ejemplo, <Customers> es una etiqueta de apertura y </
Customers> es la etiqueta de cierre correspondiente.
La primera línea de un documento XML es la declaración XML:
<?xml version="1.0" encoding="utf-8"?>
Las etiquetas XML que comienzan por <? se denominan instrucciones de procesamiento. Esta
instrucción de procesamiento nos indica que este es un documento XML, que se ajusta a las
especificaciones de la versión 1.0 de XML y que usa el conjunto de caracteres UTF-8 para sus
elementos de datos.
168 | Lección 6
if (reader.IsStartElement())
{
switch (reader.Name)
{
case "CompanyName":
if (reader.Read())
{
Console.Write(
"Nombre de la empresa: {0}, ",
reader.Value);
}
break;
case "Phone":
if (reader.Read())
{
Console.WriteLine(
"Teléfono: {0}", reader.Value);
}
break;
}
}
}
}
3. A continuación, agregue la siguiente directiva using al programa:
using System.Xml;
4. Ahora, agregue un nuevo archivo XML denominado Customers.xml al proyecto.
Asegúrese de que el archivo xml contenga los siguientes datos:
<?xml version="1.0" encoding="utf-8"?>
<!--Customer List-->
<Customers>
<Customer Id="ALFKI">
<CompanyName>Alfreds Futterkiste</CompanyName>
<Phone>030-0074321</Phone>
</Customer>
<Customer Id="EASTC">
<CompanyName>Eastern Connection</CompanyName>
<Phone>(171) 555-0297</Phone>
</Customer>
</Customers>
Compile el programa. Copie el archivo Customers.xml en la carpeta del archivo
ejecutable del programa. Ejecute el programa. Debe aparecer una lista de todos los
nombres y números de teléfono de las empresas.
170 | Lección 6
El código de este ejercicio crea en primer lugar una nueva instancia de XmlReader mediante
el método XmlReader.Create. Esto inicia una excepción si no se encuentra el archivo. El
programa terminará cuando el método XmlReader.Read no tenga nada que leer. Puede usar
propiedades como Name y Value para obtener acceso a diversas partes de XML.
DataSet es una representación en memoria de datos relacionales. Al igual que una base de
datos, DataSet puede tener tablas, relaciones y restricciones de integridad de datos, tales como
restricciones únicas o de clave externa. Un objeto DataSet suele crearse al recuperar datos
de un origen de datos, como una base de datos. Una vez creado, podemos trabajar con todos
los datos de DataSet aunque el vínculo al origen de datos no está disponible temporalmente.
Cuando se produzcan cambios en los datos, solo se actualizará la copia en memoria de los
datos. La conexión al origen de datos solo se requiere cuando hay que actualizar el origen de
datos con los cambios del objeto DataSet. DataSet resulta muy útil para crear aplicaciones
desconectadas. Las aplicaciones desconectadas son aquellas que pueden continuar
funcionando sin una conexión constante a los recursos de red, como las bases de datos.
Todas las clases relacionadas con DataSet forman parte del espacio de nombres System.
Data. Un objeto DataSet se crea mediante la clase DataSet. DataSet consta de una colección
de objetos DataTable. Un objeto DataTable es exactamente igual que una tabla de una base
de datos relacional. El objeto DataTable tiene una colección de objetos DataColumn que
representan las columnas de la tabla. Las filas del objeto DataTable se representan mediante la
colección DataRow.
DataAdapter es un puente de conexión entre el origen de datos y el objeto DataSet.
DataAdapter almacena los comandos y las conexiones de datos necesarios para conectarse al
origen de datos. DataAdapter también proporciona comandos que permiten recuperar datos del
origen de datos y actualizar este último con los cambios pertinentes.
.NET Framework proporciona tres clases DataAdapter para trabajar con diferentes tipos de
orígenes de datos:
• La clase OdbcDataAdapter se usa para trabajar con orígenes de datos ODBC. La
clase OdbcDataAdapter forma parte del espacio de nombres System.Data.Odbc.
• La clase OleDbDataAdapter se usa para trabajar con orígenes de datos OLEDB. La
clase OleDbDataAdapter forma parte del espacio de nombres System.Data.OleDb.
• La clase SqlDataAdapter se usa para trabajar con bases de datos de SQL Server. La
clase SQLDataAdapter forma parte del espacio de nombres System.Data.SqlClient.
En una aplicación típica que crea y actualiza un objeto DataSet, tendremos que llevar a cabo
los siguientes pasos:
También puede conectar a una base de datos de SQL Server mediante el uso de las clases
OdbcAdapter y OleDbAdapter. Sin embargo, la clase SQLDataAdapter está optimizada
*
TOME NOTA
para SQL Server. Por lo tanto, cuando se trabaja con SQL Server, es preferible usar la clase
SQLDataAdapter.
1. Construir y llenar cada objeto DataTable de DataSet con los datos del origen de datos
mediante el uso de un objeto DataAdapter.
Comprensión de bases de datos | 171
Un objeto DataSet puede leer y escribir datos como documentos XML. Para escribir datos
como XML, use el método WriteXml de la clase DataSet. Para leer datos del documento
TOME NOTA
* XML, use el método ReadXml de la clase DataSet.
Comprensión de bases de datos | 173
RESUMEN DE CONOCIMIENTOS
■ Evaluación de conocimientos
Rellene los espacios en blanco
Complete las oraciones siguientes escribiendo la palabra o palabras correctas en los
espacios en blanco proporcionados.
1. Para que una tabla se ajuste a la _______________, ninguna de las columnas de la tabla
debe tener varios valores en la misma fila de datos.
2. Además, la _______________ exige que todas las columnas no clave sean
funcionalmente dependientes de la clave principal completa.
3. La _______________ exige que no exista ninguna dependencia funcional entre atributos
no clave.
4. Los bloques de creación básicos de un diagrama de relación entre entidades son la
_______________, el _______________ y la _______________.
5. La cláusula _______________ de una instrucción SELECT evalúa cada fila para
comprobar si se cumple una condición y decide si la incluirá en el conjunto de resultados.
6. El objeto que se usa con la instrucción using debe implementar la interfaz
_______________.
7. La instrucción _______________ de T-SQL se puede usar para crear un procedimiento
almacenado.
174 | Lección 6
Varias opciones
Rodee con un círculo la letra correspondiente a la mejor respuesta.
1. La aplicación tiene que almacenar la imagen del producto en un archivo de disco. Desea
reducir al mínimo el tamaño de este archivo de disco. ¿Cuál de los siguientes objetos
debe usar para escribir el archivo?
a. FileStream
b. StreamWriter
c. BinaryWriter
d. XmlWriter
2. El programa C# tiene que devolver el número total de clientes de una base de datos. El
programa se usará varias veces al día. ¿Cuál es la forma más rápida de devolver esta
información desde el programa?
a. Escribir una consulta SQL y usar el método SqlCommand.ExecuteScalar para ejecutar
la consulta.
b. Crear un procedimiento almacenado para devolver el número total de clientes;
a continuación, usar el método SqlCommand.ExecuteScalar para ejecutar el
procedimiento almacenado.
c. Escribir una consulta SQL y usar el método SqlDataAdapter.Fill para ejecutar la
consulta.
d. Crear un procedimiento almacenado para devolver el número total de clientes; a
continuación, usar el método SqlDataAdapter.Fill para ejecutar el procedimiento
almacenado.
3. Debe modificar los registros de una tabla Products marcando ciertos productos como
descontinuados. Sin embargo, debe hacerlo solo cuando tanto el valor de UnitsInStock
como el de UnitsOnOrder sea cero. ¿Cuál de las siguientes instrucciones SQL se debe
usar?
a. INSERT
b. SELECT
c. UPDATE
d. DELETE
4. Debe actualizar los campos Region de los clientes de Japón. Escribe la siguiente
instrucción SQL UPDATE:
UPDATE Customers
SET Region = 'EastAsia'
Al llevar a cabo una consulta en una base de datos de prueba, descubre que hay más
registros afectados de los que esperaba. Es preciso corregir la instrucción SQL. ¿Qué
debe hacer?
a. Agregar una cláusula WHERE a la instrucción UPDATE.
b. Agregar una cláusula SET adicional a la instrucción UPDATE.
c. Agregar una cláusula GROUP BY a la instrucción UPDATE.
d. Agregar una cláusula HAVING a la instrucción UPDATE.
5. Está desarrollando una aplicación que tiene que recuperar una lista de clientes de una
base de datos de SQL Server. La aplicación debe recorrer la lista secuencialmente una
vez, mientras procesa cada registro de cliente. ¿Cuál de las siguientes clases debe usar
para contener la lista de clientes a fin de lograr el máximo rendimiento?
a. DataSet
b. DataTable
c. DataView
d. SqlDataReader
Comprensión de bases de datos | 175
6. La aplicación que está desarrollando tiene que leer datos de un archivo plano que incluye
elementos tales como una clave de tipo integer de cinco dígitos, seguida de un nombre de
cliente de 20 caracteres, seguido de dos campos de fecha y hora. ¿Cuál de las siguientes
clases debe usar?
a. FileStream
b. StreamReader
c. BinaryReader
d. DataReader
7. Está desarrollando una aplicación que deberá copiar datos de una vista de SQL Server en
un DataSet. Asigna al objeto DataSet el nombre dsData. ¿Cuál de los siguientes métodos
debe usar para copiar los datos?
a. Fill
b. InsertCommand
c. SelectCommand
d. Update
8. Está desarrollando una aplicación para administrar los clientes y sus pedidos. ¿Cuál de
las siguientes situaciones no es una buena candidata para implementarla en su aplicación
mediante procedimientos almacenados?
a. Recuperación de la lista de todos los clientes de la base de datos.
b. Recuperación de la lista de todos los pedidos de clientes específicos.
c. Inserción de un nuevo pedido en la tabla Orders.
d. Creación de consultas ad hoc por parte del administrador de la base de datos.
9. Su aplicación se conecta a una base de datos de SQL Server que contiene una tabla
denominada Employees con las siguientes columnas:
EmployeeID (int, identity)
EmployeeType (char(1))
EmployeeDate (datetime)
Debe escribir una consulta que elimine todas las filas de la tabla cuando el valor de
EmployeeType sea C o T. No desea eliminar las demás filas. ¿Qué instrucción debe usar?
a. DELETE FROM Employees
WHERE EmployeeType LIKE '[CT]'
b. DELETE FROM Employees
WHERE EmployeeType LIKE '[C-T]'
c. DELETE FROM Employees
WHERE EmployeeType LIKE 'C' OR 'T'
d. DELETE * FROM Employees
WHERE EmployeeType IN ('C', 'T')
10. Su aplicación incluye un objeto SqlDataAdapter denominado sqlDataAdapter que se
conecta a la tabla Employees. La aplicación, que se basa en este SQLDataAdapter,
también incluye un objeto DataSet denominado dsEmployees. ¿Qué línea de código debe
usar para cargar los datos de la base de datos en el objeto DataSet?
a. dsEmployees = sqlDataAdapter.Fill("Employees");
b. sqlDataAdapter.Fill("dsEmployees", "Employees");
c. sqlDataAdapter.Fill(dsEmployees);
d. sqlDataAdapter.Fill(dsEmployees, "Employees");
176 | Lección 6
■ Evaluación de competencias
Escenario 6-1: Creación de un diagrama de relación entre entidades
Una empresa tiene un número de empleados y cada empleado se puede asignar a uno o más
proyectos. Además, cada proyecto puede tener uno o más empleados trabajando en ellos.
Dibuje un diagrama de relación entre entidades para esta situación.
■ Evaluación de aptitudes
Escenario 6-3: Normalización de tablas
Está convirtiendo un diagrama de relación entre entidades en tablas. Idea el siguiente diseño
de tabla:
Books
Debe aplicar reglas de normalización para garantizar la integridad de los datos. ¿Cómo
garantizaría que la tabla Books sea conforme con la tercera forma normal?
177
Índice
179
180 | Índice
O Propiedades
Objetos creación, 36–37
clases, creación, 33–34 de implementación automática, 37–38
constructores, 35 definición, 36
conversión entre tipos, 52–53 descriptores de acceso, 36
creación, 35–36 solo escritura, 37
DataSet en memoria, lectura, 171 solo lectura, 37
definición, 33, 35 Protocolo de transferencia de hipertexto (HTTP), 86, 95, 107
delegados, 40 Protocolo simple de acceso a objetos (SOAP)
espacios de nombres, 42–43 definición, 107
eventos, 40–42 elementos, 108
métodos, 34–35 Prueba de bucle, 19
miembros estáticos, 43–44 Pruebas de aceptación, 70
new, palabra clave, 35 Pruebas de caja blanca, 69
propiedades de implementación automática, 37–38 Pruebas de caja negra, 69
propiedades, creación, 36–37 Pruebas de integración, 69–70
this, palabra clave, 38–39 Pruebas de regresión, 70
Operadores binarios, 10 Pruebas de software. Véase Pruebas
Operadores ternarios, 10 Pruebas del sistema, 70
Operadores unarios, 10 Pruebas unitarias, 69
Operadores Pruebas
+=, 42 aceptación, 70
definición, 10 caja blanca, 69
precedencia en C#, 10 caja negra, 69
override, palabra clave, 55–56 integración, 69–70
métodos, 69
P niveles, 69–70
Parámetros de línea de comandos, 129 regresión, 70
Peek, 73, 74 Servicios web, 110–112
Pensamiento orientado a objetos, 33 sistema, 70
Pilas unitarias, 69
operaciones, 74 Push, 74
rendimiento y uso, 74
representación interna, 73–74 Q
Polimorfismo QueryString, propiedad, 100
definición, 53 QuickSort, 79–81
uso, 54–55
Pop, 74 R
Postback, 96, 97 Recursión, 22
Primera forma normal, 147–148 Relación de uno a uno, 145
Procedimientos almacenados parametrizados, 160–164 Relación de uno a varios, 144, 145
Procedimientos almacenados Relación de varios a varios, 145
creación y ejecución, 159–160 Relacionales, bases de datos
definición, 159 conceptos, 143
parametrizados, creación, 160–161 definición, 142
parametrizados, ejecución a partir de C#, 161–164 diagramas de relación entre entidades, 144–146
Visual Studio, creación a partir de, 160 diseño, 144
Proceso de diseño, 67 normalización de datos, 146–149
Programa, 4 tablas, 143
Programación del lado cliente, 94–95
Programación del lado servidor, 94–95 S
Programación orientada a objetos Segunda forma normal, 148
encapsulación, 47–48 SELECT, instrucción, 150, 155–157
herencia, 48–53 ServiceInstaller, clase, 135
interfaces, 56–58 ServiceProcessorInstaller, clase, 135
objetos, 33–44 Servicios de Windows
polimorfismo, 53–56 creación, 132–134
valores y referencias, 44–47 definición, 131
Propiedades de implementación automática, 37–38 ejemplos, 131
Índice 183
instalación, 135–136 V
instalador, adición al, 134–135 Value, palabra clave, 37
trabajo con, 136–137 Variables, 8
Servicios web ViewState, 100
aplicación cliente, acceso desde, 112–114 Visual Studio
creación, 108–110 consultas, ejecución a partir de, 152–153
definición, 107 Diseñador de consultas, 153
pruebas, 110–112 Instalador del Servicio de Windows, adición, 134–135
SOAP, 107–108 Plantilla del Servicio de Windows, 132–134
WebMethod, atributo, 110 Servicio de Windows, instalación, 135–136
Set, descriptor de acceso, 36
Sistema de administración de bases de datos (DBMS), 143 W
Sistema de numeración binario, 4 WebMethod, atributo, 101
Sitios web, 104–105 WebService, atributo, 101
SQL. Véase Lenguaje de consulta estructurado (SQL) While, bucle
StartType, propiedad, 135 definición, 17
Static, palabra clave, 43 partes, 19
Structs, 44–45 World Wide Web, 86
Switch, bloque, 15 WSDL, 108
Switch, instrucción, 15
X
T xcopy, 106
Tablas de decisión, 3–4 XML
Tablas, 143, 146–149 archivos, lectura, 168–170
Tercera forma normal, 149 atributos, 168
This, palabra clave, 38–39, 44 definición, 167
Tipos de datos, 8–9 elementos, 168
Tipos de referencia, 44–45, 46–47 etiquetas, 167
Tipos de valor, 44, 45, 46 XmlDocument, 168
Try, bloque, 25 XmlReader, 168
Try-catch-finally, instrucción, 25–26 XmlWriter, 168
T-SQL. Véase Lenguaje de consulta estructurado (SQL)
U
UPDATE, instrucción, 150, 157–158
Using, directiva, 7
Using, instrucción, 164
Notas
Notas
Notas
Notas
Notas
Notas
Notas
Notas
Notas
Notas