c# Curso Completo

Introducción a Microsoft .NET Contenido Notas generales 1 Lección: Introducción a la plataforma .NET 2 Lección: Int

Views 78 Downloads 5 File size 3MB

Report DMCA / Copyright

DOWNLOAD FILE

Recommend stories

Citation preview

Introducción a Microsoft .NET

Contenido Notas generales

1

Lección: Introducción a la plataforma .NET

2

Lección: Introducción a servicios Web XML 14 Lección: Dentro de .NET Framework

20

Lección: Compilación y ejecución en .NET

25

Introducción a Microsoft .NET

i

Notas para el instructor Este módulo ofrece a los estudiantes una introducción a Microsoft® .NET. El módulo identifica problemas de las tecnologías actuales que se pueden resolver con la iniciativa .NET, y describe los servicios y prestaciones básicas que ofrece la plataforma .NET. Describe también las características y ventajas de los servicios Web XML y los clientes con los que es compatible la plataforma .NET. Los estudiantes aprenderán las ventajas y los componentes de .NET Framework. Al final de este módulo, los estudiantes serán capaces de: • Identificar los requisitos de empresa que satisface la iniciativa .NET. • Describir las características y servicios básicos de la plataforma .NET. • Identificar las características y ventajas de los servicios Web XML. • Identificar clientes válidos para la plataforma .NET y los distintos tipos de dispositivos inteligentes compatibles con .NET. • Identificar las ventajas de .NET Framework. • Describir los componentes de .NET Framework. • Describir el proceso de compilación y ejecución en .NET. • Identificar las formas en que .NET simplifica la programación con respecto a otras plataformas.

Introducción a Microsoft .NET

1

‹ Notas generales

Introducción

„

Introducción a la plataforma .NET

„

Introducción a servicios Web XML

„

Dentro de .NET Framework

„

Compilación y ejecución en .NET

„

Guía básica 2002-04 para Microsoft Developer Tools

Microsoft® .NET es una plataforma que le proporciona todas las herramientas y tecnologías necesarias para crear aplicaciones Web distribuidas que utilizan protocolos Web estándar. Estas aplicaciones pueden comunicarse con una gran variedad de clientes, como teléfonos móviles y PCs de bolsillo. La plataforma .NET ofrece también un nivel de integración sin precedentes entre lenguajes de programación, además de distintos servicios en tiempo de ejecución. En este módulo conocerá la plataforma .NET de Microsoft para servicios Web con lenguaje de marcado extensible (XML).

Objetivos

Al final de este módulo, usted será capaz de: • Identificar los requisitos de empresa que satisface la iniciativa .NET. • Describir las características y servicios básicos de la plataforma .NET. • Identificar las características y ventajas de los servicios Web XML. • Identificar clientes válidos para la plataforma .NET y los distintos tipos de dispositivos inteligentes compatibles con .NET. • Identificar las ventajas de .NET Framework. • Describir los componentes de .NET Framework. • Describir el proceso de compilación y ejecución en .NET. • Identificar las formas en que .NET simplifica la programación con respecto a otras plataformas.

Introducción a Microsoft .NET

2

‹ Lección: Introducción a la plataforma .NET

„

Por qué necesita .NET

„

La plataforma .NET

„

.NET Framework

„

.NET Enterprise Servers

„

Servicios de base (Building Block Services)

„

Clientes para la plataforma .NET

Introducción

Esta lección presenta los componentes de la plataforma Microsoft .NET, que está pensada para simplificar el desarrollo Web.

Objetivos de la lección

Al final de esta lección, usted será capaz de: • Identificar problemas de las tecnologías actuales que se pueden resolver con la iniciativa .NET. • Describir los.NET Enterprise Servers. • Definir los servicios de base (building block services) de .NET Framework. • Identificar los clientes que se pueden utilizar en la plataforma .NET.

Introducción a Microsoft .NET

3

Por qué necesita .NET

„

Microsoft .NET: z z

z

Resuelve muchos problemas de la tecnología actual Proporciona aplicaciones compatibles con servicios Web XML interoperables Proporciona aplicaciones compatibles con clientes inteligentes

Introducción

Microsoft .NET está pensado para facilitar el trabajo con la Internet mediante la integración de estándares de Internet y la compatibilidad con servicios Web XML. La plataforma .NET también le permite acceder más fácilmente a sus datos y escribir aplicaciones Web que se pueden ejecutar en una gran variedad de exploradores y dispositivos. El tiempo de ejecución de .NET simplifica los procesos de instalación y actualización, aumentando la facilidad de uso y la fiabilidad.

Problemas de las tecnologías actuales

Las aplicaciones Web de hoy en día tienen interfaces de usuario interactivas creadas con HTML dinámico (DHTML) y tecnología Microsoft ActiveX®. El uso de servicios COM+ proporciona escalabilidad de los servicios de fondo. Aunque la mayor parte de estas aplicaciones se comunican de forma eficaz, muchas de ellas pueden presentar los siguientes problemas: • Cada aplicación es un código diferenciado en un gran número de dispositivos. • Las soluciones están formadas por grandes grupos de aplicaciones, dispositivos y servicios. • La integración, si se consigue, resulta demasiado complicada, demasiado cara, demasiado lenta y demasiado rígida.

Servicios Web XML interoperables

La interoperabilidad es la clave para la próxima generación de aplicaciones. Las organizaciones virtuales necesitan aplicaciones Web que sean capaces de interactuar con otras aplicaciones, presentando una interfaz programable que reaccione ante otros servicios en la Web. Líneas aéreas, hoteles y empresas de alquiler de coches, por ejemplo, pueden ofrecer sus servicios como servicios Web XML, de manera que una agencia de viajes pueda emplearlos para encontrar la mejor combinación de precios y servicios para sus clientes.

Introducción a Microsoft .NET

Compatibilidad con clientes inteligentes

4

La tecnología también ha avanzado con gran rapidez, lo que ha provocado una reducción en el coste de hardware informático y mejores conexiones con la Internet. La necesidad de acceso instantáneo a datos por parte de las empresas ha extendido el uso de dispositivos como teléfonos móviles, asistentes digitales personales (PDAs) y PCs portátiles. Las aplicaciones desarrolladas para .NET aprovechan los últimos avances tecnológicos porque son compatibles con clientes inteligentes y se pueden ejecutar sobre distintos sistemas operativos.

Introducción a Microsoft .NET

5

La plataforma .NET

Internet Visual Studio .NET

.NET Framework

Introducción

.NET Enterprise Servers

.NET Building Block Services

Microsoft .NET está formado por las siguientes tecnologías básicas: • .NET Framework • .NET Enterprise Servers • Servicios de base (Building Block Services) Microsoft Visual Studio® .NET ofrece un entorno de desarrollo de alto nivel para la creación de aplicaciones en .NET Framework. Utiliza tecnologías fundamentales para simplificar la creación, instalación y evolución continua de aplicaciones Web y servicios Web XML que son seguros, escalables y tienen una gran disponibilidad. Estas aplicaciones se pueden instalar en distintas plataformas, incluyendo .NET Enterprise Servers, y pueden hacer uso de servicios de base .NET.

Introducción a Microsoft .NET

6

.NET Framework .NET Framework Windows UI

ASP.NET

ADO.NET: Datos y XML Biblioteca de clases de .NET Framework Runtime de lenguaje común (Common Language Runtime)

Introducción

.NET Framework es un entorno de ejecución y biblioteca de componentes independiente del lenguaje de programación utilizado. Le permite crear aplicaciones integradas y orientadas a servicios que satisfacen las necesidades actuales de las empresas de Internet reuniendo información de una gran variedad de fuentes con las que además interactúa, independientemente de las plataformas o lenguajes que se empleen. .NET Framework está formado por los siguientes componentes: • Entorno común de ejecución (Common Language Runtime) • Biblioteca de clases de .NET Framework • Microsoft ADO.NET (datos y XML) • Microsoft ASP.NET

Runtime de lenguaje común (Common Language Runtime)

Common Language Runtime (CLR) simplifica el desarrollo de aplicaciones, proporciona un entorno de ejecución robusto y seguro, es compatible con gran variedad de lenguajes y simplifica la instalación y gestión de aplicaciones. También se conoce como un entorno gestionado que proporciona automáticamente servicios comunes como seguridad y recolección de elementos no utilizados.

Biblioteca de clases de .NET Framework

.NET Framework proporciona un conjunto unificado, orientado a objetos, jerárquico y extensible de bibliotecas de clases para desarrolladores. Hasta ahora, los desarrolladores de C++ empleaban MFC (Microsoft Foundation Classes) y los de Microsoft Visual Basic® usaban clases del runtime de Visual Basic, mientras que para otros lenguajes se utilizaban sus propias bibliotecas de clases y frameworks. Básicamente, .NET Framework unifica los distintos frameworks ofrecidos anteriormente por Microsoft. El resultado es que los desarrolladores ya no necesitan conocer distintos frameworks para hacer su trabajo.

Introducción a Microsoft .NET

7

Por otra parte, la creación de un conjunto de interfaces de programación de aplicaciones (API) común para todos los lenguajes de programación en .NET Framework permite la depuración, el tratamiento de errores y la herencia de un lenguaje a otro. De esta forma todos los lenguajes de programación, desde Microsoft JScript® hasta Visual C++®, son iguales en la práctica y los desarrolladores tienen libertad para elegir el lenguaje que quieren usar.

Introducción a Microsoft .NET

8

ADO.NET: Datos y XML

ADO.NET es la próxima generación de la tecnología ActiveX Data Object (ADO). El elevado nivel de integración de ADO.NET en XML permite a los desarrolladores transferir conjuntos de datos (cachés de datos en memoria) entre los distintos componentes de una solución de empresa.

ASP.NET

ASP.NET se basa en las clases de programación de .NET Framework para proporcionar un modelo de aplicaciones Web en la forma de un conjunto de controles e infraestructura que facilita la creación de aplicaciones Web. Los desarrolladores pueden acceder a un conjunto de controles Web de ASP.NET con funciones comunes de interfaces de usuario en lenguaje de marcado de hipertexto (HTML), como cuadros de texto y menús desplegables. Estos controles se ejecutan en el servidor Web y proyectan su interfaz de usuario a un navegador como HTML. En el servidor, los controles muestran un modelo de programación orientada a objetos que pone su potencia a disposición de los desarrolladores de Web. ASP.NET proporciona además servicios de infraestructura, como gestión de estados de sesión y reciclaje de procesos, lo que reduce aún más la cantidad de código que debe escribir el desarrollador y aumenta la fiabilidad de las aplicaciones. ASP.NET utiliza también estos mismos conceptos para hacer que los desarrolladores puedan ofrecer el software como un servicio. Utilizando servicios Web XML, los desarrolladores pueden simplemente escribir su lógica de empresa (business logic) y dejar que la infraestructura de ASP.NET se encargue de ofrecer el servicio mediante el protocolo simple de acceso a objetos (Simple Object Access Protocol, SOAP).

Introducción a Microsoft .NET

9

.NET Enterprise Servers

„

Los .NET Enterprise Servers incluyen: z

Application Center

z

BizTalk Server

z

Commerce Server

z

Exchange Server

z

Host Integration Server

z

Internet Security and Acceleration Server

z

SQL Server

Introducción

Los .NET Enterprise Servers forman la completa gama de aplicaciones de servidor de Microsoft para la creación, instalación y gestión de soluciones Web escalables e integradas. Diseñados para ofrecer las más altas prestaciones, los .NET Enterprise Servers ofrecen escalabilidad, fiabilidad y facilidad de uso para las empresas globales que trabajan en la Web. Están pensados específicamente para que sean interoperables, ya que utilizan estándares abiertos de Web como XML. Esto permite a Microsoft ofrecer la infraestructura de una nueva plataforma de desarrollo que ayudará a los desarrolladores a crear e instalar rápidamente aplicaciones distribuidas en tiempo de Internet.

Enterprise Servers

A continuación se ofrece una descripción de los distintos .NET Enterprise Servers: • Microsoft Windows® 2000 Server: Windows 2000 Server aprovecha las posibilidades de la tecnología Microsoft Windows NT® para integrar servicios basados en estándares de directorios, aplicaciones Web, comunicaciones, archivos e impresión con alta fiabilidad, gestión eficaz y compatibilidad con los últimos adelantos en hardware de red. El sistema operativo para servidores de próxima generación, Windows .NET Server, ofrecerá un nivel de integración con .NET todavía más alto. • Microsoft Application Center: Application Center hace que las aplicaciones Web creadas en Microsoft Windows 2000 tengan la máxima disponibilidad (99,999 por ciento de tiempo activo) mediante adaptación de software, al tiempo que reduce la complejidad y los costes de operación. • Microsoft BizTalk® Server: BizTalk Server es una plataforma basada en estándares que utiliza XML como formato común de documentos para desarrollar y gestionar la integración de aplicaciones en y entre organizaciones. • Microsoft Commerce Server: Commerce Server es un sistema completo que permite crear rápidamente soluciones escalables y personalizadas de

Introducción a Microsoft .NET

10

comercio electrónico Business-to-Consumer (B2C) y Business-to-Business (B2B) en Windows 2000. • Exchange Server: Esta completa aplicación de mensajería y colaboración para organizaciones de todos los tamaños ofrece los mejores niveles de interoperabilidad, facilidad de uso y gestión a bajo coste.

Introducción a Microsoft .NET

11

• Microsoft Host Integration Server: Esta completa plataforma de integración es el mejor sistema para adoptar rápidamente tecnologías de Internet, intranet y cliente/servidor y rentabilizar al máximo las inversiones realizadas en sistemas heredados. • Microsoft Internet Security and Acceleration Server: Internet Security and Acceleration (ISA) Server le ofrece conectividad a Internet segura y fácil de administrar y acelera la presentación de contenido Web por medio de una caché Web escalable y fiable. • Microsoft SQL Server™: La conocida base de datos de Microsoft para Windows le ofrece la posibilidad de tomar decisiones más informadas a todos los niveles de su empresa con soluciones de empresa escalables, gran capacidad de almacenamiento de datos e integración en Microsoft Office. • Microsoft Mobile Information Server 2002: Este servidor de aplicaciones extiende a los usuarios móviles el alcance de los Microsoft .NET Enterprise Servers, los datos de empresa y los contenidos de intranet. Lleva la intranet de empresa a la última generación de dispositivos móviles, lo que permite a los usuarios acceder de forma segura y en tiempo real a su correo electrónico, contactos, calendarios, tareas o a cualquier aplicación de intranet para unidades de negocio desde cualquier lugar. • Microsoft Windows .NET Server: Windows .NET Server es la próxima generación de productos para servidores Windows. Estará incluido en .NET Framework y aprovecha las ventajas que ofrece la compatibilidad con XML y la escalabilidad de la actual generación de servidores Windows para aumentar el nivel de integración de Microsoft Active Directory® Directory Service y el sistema de autenticación Microsoft Passport. La siguiente versión de Windows .NET Server es Windows .NET Server 2003, un sistema operativo polivalente con capacidad para una gran variedad de servidores según las necesidades, tanto de forma centralizada como distribuida. • Supplier Accelerator: Es una parte muy importante de la iniciativa EBusiness Acceleration que resuelve el problema de la conexión a múltiples e-marketplaces. Ofrece un modelo inteligente para gestionar la publicación de catálogos y el procesamiento de pedidos en los principales emarketplaces directamente con aplicaciones de compradores, y es ampliable para poder incluir nuevos canales de ventas en e-business. Supplier Accelerator está basado en Commerce Server 2000, BizTalk Server 2000 y SQL Server 2000 y es una excelente base para el comercio electrónico.

Introducción a Microsoft .NET

12

Servicios de base (Building Block Services)

„

Introducción

Servicios de base (Building Block Services) z

Permiten que el usuario controle los datos

z

Utilizan Microsoft Passport

Los servicios de base son un conjunto de servicios Web XML que traspasan de las aplicaciones a los usuarios el control sobre los datos de los usuarios. Estos servicios permiten la personalización y garantizan la coherencia en aplicaciones, servicios y dispositivos. Microsoft ha desarrollado en torno a la identidad, la notificación y el almacenamiento servicios privados y seguros que pueden servir de base para otros servicios Web XML y experiencias .NET. Microsoft Passport es la iniciativa de Microsoft .NET para facilitar la integración de distintas aplicaciones.

Microsoft Passport

Passport es un componente básico de la iniciativa Microsoft .NET. Permite a las empresas desarrollar y ofrecer servicios Web XML distribuidos en una amplia gama de aplicaciones, dispositivos y servicios complementarios, todos ellos basados en una experiencia de Internet común. El servicio de inicio de sesión único (Single Sign-In, SSI) de Microsoft Passport permite a las empresas ofrecer a sus clientes un sistema rápido y práctico de iniciar una sesión y realizar transacciones de forma segura, ya que pueden emplear un solo nombre y contraseña en todos los sitios Web a los que accedan. Además, los nombres de inicio de sesión de Passport se asignan a personas y no a sistemas, lo que significa que los miembros pueden acceder a sitios Passport en cualquier momento y desde muchos tipos de dispositivos. El uso de Passport en su sitio Web le permitirá: • Aumentar el tráfico al simplificar el proceso de inicio de sesión y registro. • Aumentar el nivel de retención de clientes al ofrecer contenidos personalizados a partir de datos de perfiles en Passport. • Aumentar las ventas al simplificar el proceso de compra. • Ofrecer a millones de miembros de Passport un sistema más fácil y seguro de inicio de sesión y compra.

Introducción a Microsoft .NET

13

Clientes para la plataforma .NET

„

La plataforma .NET es compatible con los siguientes dispositivos inteligentes: z

PCs portátiles

z

Estaciones de trabajo

z

PCs de bolsillo

z

PDAs

z

Teléfonos móviles inteligentes

z

Consolas de juegos

z

Tablet PCs

Introducción

Como apoyo para la plataforma .NET, Microsoft esta creando software de dispositivos que permitirá a los clientes utilizar distintos dispositivos complementarios en lugar de un solo dispositivo o cliente. Microsoft está desarrollando software para todo tipo de aparatos, desde teléfonos y PDAs hasta otros dispositivos y clientes, como PCs portátiles, estaciones de trabajo, PCs de bolsillo, teléfonos móviles inteligentes, consolas de juegos (Microsoft Xbox™) y Tablet PCs. Microsoft está trabajando actualmente en los siguientes productos de software para estos dispositivos: Embedded Windows XP, Windows CE 4.0, .NET Framework y .NET Compact Framework.

Dispositivos inteligentes

Todos ellos reciben el nombre de dispositivos inteligentes porque pueden recordar quién es el usuario y utilizan la Web en lugar del servidor como plataforma para computación. Los dispositivos inteligentes permiten acceder a datos, analizarlos y actuar sobre ellos en cualquier momento y en cualquier lugar. Utilizan la red de forma inteligente y reaccionan ante limitaciones del ancho de banda, permiten el uso de aplicaciones con o sin conexión, y saben qué servicios están disponibles. Estos dispositivos son programables y personalizables, realizan actualizaciones automáticamente y no requieren ninguna administración. Los dispositivos inteligentes presentan y reúnen información de la forma más adecuada para cada dispositivo, desde la conversión de texto en voz en un teléfono móvil hasta el reconocimiento de escritura a mano en un Tablet PC. Pueden utilizar servicios Web XML y descubrir qué servicios están disponibles, ya que emplean XML, SOAP y UDDI. Los dispositivos inteligentes crecerán de forma explosiva en los próximos cinco años, a medida que se vayan integrando en el dispositivo inteligente por excelencia para Internet: el PC.

Introducción a Microsoft .NET

14

‹ Lección: Introducción a servicios Web XML

„

Notas generales sobre servicios Web XML

„

Características de los servicios Web XML

„

Ventajas de los servicios Web XML

Introducción

Uno de los principales desafíos a los que se enfrentan hoy en día los desarrolladores es la integración de aplicaciones; es decir, el proceso de tomar un grupo de aplicaciones y convertirlas en aplicaciones Web fáciles de usar, aunque se ejecuten en distintos sistemas operativos, estén escritas en distintos lenguajes de programación y hayan sido creadas con distintos modelos de objetos.

Objetivos de la lección

Los servicios Web XML permiten crear aplicaciones Web de forma que distintos usuarios con diferentes plataformas puedan acceder a ellas y utilizarlas. Al final de esta lección, usted será capaz de: • Comprender los servicios Web XML. • Describir las características de los servicios Web XML. • Describir las ventajas de los servicios Web XML.

Introducción a Microsoft .NET

15

Notas generales sobre servicios Web XML

„

Introducción

Los servicios Web XML utilizan los siguientes estándares: z

XML

z

HTTP

z

SOAP

Los servicios Web XML proporcionan un mecanismo intrínseco para crear un servicio o sitio Web de manera que colabore perfectamente con otros servicios y sitios Web. XML Aprovechan la infraestructura y las aplicaciones existentes para ofrecer un modelo simple, flexible y basado en estándares para la vinculación de aplicaciones Web en la Internet. Las aplicaciones Web se pueden ensamblar fácilmente empleando servicios desarrollados de forma local y servicios ya existentes, independientemente de las plataformas, lenguajes de programación o modelos de objetos que se hayan utilizado para crear cada servicio o aplicación. Si, por ejemplo, su empresa está especializada en la creación de sistemas muy precisos de conversión de moneda para prácticamente todos los países del mundo, usted puede dedicarse a desarrollar servicios Web XML a los que acceden otros sitios Web para ofrecer conversiones de precios a sus usuarios. De esta forma combina distintos servicios y la experiencia del usuario en la Web es mucho más rica.

Estándares

Los servicios Web XML utilizan lo siguientes estándares: • XML fue diseñado para documentos Web y permite a los desarrolladores crear sus propias etiquetas personalizadas, lo que hace posible la definición, transmisión, validación e interpretación de datos entre aplicaciones y entre organizaciones. • HTTP define el formato y el modo de transmisión de mensajes y las acciones que los servidores y exploradores Web deben realizar en respuesta a distintos comandos. • SOAP permite la interoperabilidad de una gran variedad de programas y plataformas, y hace que las aplicaciones existentes sean accesibles a un mayor número de usuarios.

Introducción a Microsoft .NET

16

La especificación UDDI se utiliza para publicar y descubrir información sobre servicios Web XML. UDDI es la base que permite a las empresas buscar y hacer negocios entre sí de forma rápida, sencilla y dinámica utilizando las aplicaciones que prefieran.

Introducción a Microsoft .NET

17

Características de los servicios Web XML

„

Los servicios Web XML se caracterizan por: z

Elementos programables

z

Datos compartidos

z

Interoperabilidad

z

Independencia de lenguaje y plataforma

z

Disponibilidad universal

Introducción

Los servicios Web XML llevan a un nuevo nivel el desarrollo de aplicaciones distribuidas.

Características de los servicios Web XML

Los servicios Web XML se pueden emplear para: • Colocar elementos programables en sitios Web donde otros pueden acceder a comportamientos distribuidos. • Invocar funciones de otras aplicaciones, además de hacer que las aplicaciones puedan compartir datos independientemente de las herramientas empleadas para crear esas aplicaciones. • Ofrecer como un servicio Web XML las funciones y datos de cada una de las aplicaciones existentes. De esta forma se podría crear una aplicación compuesta que utilizara ese grupo de servicios Web XML para lograr la interoperabilidad de las aplicaciones que la forman. El resultado es que los servicios Web XML resuelven varios problemas básicos, como interoperabilidad, integración y extensibilidad de aplicaciones. • Ser utilizados por aplicaciones creadas en cualquier lenguaje y para cualquier plataforma. Es posible invocar un servicio Web XML desde cualquier aplicación Web, incluyendo otro servicio Web XML. El cliente de un servicio Web XML no tiene que ser necesariamente una aplicación basada en clientes; en realidad, casi todos los clientes son aplicaciones basadas en servidores, como Web Forms y servicios Web XML. • Promover la comunicación universal. Un sistema operativo que se desarrolle ahora o en el futuro incluirá sin duda la posibilidad de conectar a la Internet. Esto significa que la capacidad de los servicios Web XML para conectar prácticamente cualquier sistema o dispositivo a la Internet garantizará la disponibilidad universal de esos sistemas operativos para cualquier otro sistema o dispositivo que esté conectado a la Internet.

Introducción a Microsoft .NET

18

Ventajas de los servicios Web XML

„

El uso de servicios Web XML presenta las siguientes ventajas: z

Una colaboración más sencilla para los usuarios

z

Integración de aplicaciones de empresa externas

z

Mayor productividad de los desarrolladores

Introducción

Los servicios Web XML son un elemento integral del modelo de programación .NET. La integración Best-of-Breed (lo mejor de lo mejor) permite a Microsoft .NET convertir en una ventaja competitiva las infraestructuras existentes de tecnologías de la información. El objetivo de la iniciativa Microsoft .NET es conseguir que desarrolladores, empresas y usuarios puedan aprovechar la tecnología para acceder a información en cualquier momento, en cualquier lugar y en cualquier dispositivo.

Ventajas

El uso de servicios Web XML presenta las siguientes ventajas: • Da más posibilidades a los usuarios • Permite la integración de aplicaciones de otras empresas • Ofrece nuevas oportunidades de desarrollo

Una colaboración más sencilla para los usuarios

La plataforma .NET utiliza XML para situar en primer plano la experiencia del usuario y dejar la tecnología en un segundo plano. Los servicios Web XML: • Permiten a los usuarios interactuar con sus datos a través de tecnologías de visión, voz y escritura a mano. • Datos seguros de los usuarios en la Internet para que puedan acceder a ellos desde el trabajo con sus PCs y desde casa con sus teléfonos móviles, localizadores o PDAs. Esto da a los usuarios un mayor control, capacidad para tomar mejores decisiones y una colaboración más sencilla. • Permite ejecutar aplicaciones en una gran variedad de dispositivos. Esto hace que los usuarios puedan realizar transacciones fácilmente desde teléfonos inteligentes, PDAs y muchos otros dispositivos inteligentes.

Ejemplo

Por ejemplo, un paciente podría usar una aplicación basada en .NET para buscar clínicas cercanas que utilicen servicios Web XML para ofrecer sus

Introducción a Microsoft .NET

19

calendarios de citas. El paciente puede encontrar de forma rápida y sencilla un servicio sanitario que satisfaga sus necesidades, mientras que las empresas que ofrecen sus principales procesos como servicios Web XML crean experiencias de usuario más personales e inteligentes y amplían las posibles interacciones de los clientes con la empresa. Integración de aplicaciones de empresa

Los servicios Web XML ofrecen importantes ventajas a organizaciones y empresas, ya que aumentan sus posibilidades de alcance y exposición y crean nuevas oportunidades de negocio. Esto puede producir un ahorro considerable en los costes de desarrollo, además de generar nuevos ingresos. Las organizaciones pueden integrar más fácilmente sus aplicaciones internas, así como acceder a servicios ofrecidos por otras empresas. La combinación de servicios Web XML ofrecidos en la Internet permite a las empresas crear para la Web una gran variedad de aplicaciones con valor añadido. En el ejemplo anterior, una clínica que intenta ofrecer un mejor servicio convierte su calendario de citas en un servicio Web XML y lo ofrece en la Web. Otras empresas, como organizaciones de gestión sanitaria, directorios de empresas y clínicas, podrían crear sistemas que utilizaran o “consumieran” el servicio, lo que permitiría a los posibles clientes reservar una cita más eficazmente. Por otra parte, esa misma clínica puede usar servicios Web XML creados por empresas de seguros y organizaciones de gestión sanitaria para enviar facturas directamente. También podría contratar un sistema de contabilidad con una tercera empresa para integrarlo en sus propios sistemas, ahorrando tiempo y recursos.

Mayor productividad de los desarrolladores

Desde el punto de vista técnico, Microsoft .NET cambiará la forma en que los desarrolladores crean aplicaciones. • Visual Studio .NET y .NET Framework permite a los desarrolladores aprovechar su experiencia y conocimientos para crear de forma rápida y sencilla avanzados servicios Web XML y aplicaciones. Estas herramientas ayudarán a los desarrolladores a transformar la Web de un sistema de presentación estática de información en un mundo rico en servicios Web XML interactivos. • La aplicación de técnicas de desarrollo rápido de aplicaciones (Rapid Application Development, RAD) a servicios y aplicaciones Web aumentan la productividad de los desarrolladores y ahorra tiempo y dinero. Al ser compatibles con cualquier lenguaje de programación, estas herramientas aprovechan los conocimientos de los desarrolladores y les permiten utilizar la herramienta más adecuada para cada tarea. • A los desarrolladores independientes de software, .NET les ofrece la oportunidad de crear nuevos servicios avanzados para la era de la Internet. Los desarrolladores pueden crear servicios que accedan automáticamente a información y hagan uso de ella de forma local o remota, trabajando con cualquier dispositivo o lenguaje sin tener que reescribir el código para cada entorno.

Introducción a Microsoft .NET

20

‹ Lección: Dentro de .NET

Introducción

„

Runtime de lenguaje común (Common Language Runtime)

„

La biblioteca de clases de .NET Framework

„

Espacios de nombres de ADO.NET

„

Espacios de nombres de ASP.NET

.NET Framework consta de los siguientes componentes: • Runtime de lenguaje común (Common Language Runtime, CLR) • Biblioteca de clases de .NET Framework

Objetivos de la lección

Al final de esta lección, usted será capaz de: • Comprender la función del CLR en el desarrollo y la simplificación de aplicaciones Web mediante .NET. • Identificar los espacios de nombres en la biblioteca de clases de .NET Framework..

Introducción a Microsoft .NET

21

Runtime de lenguaje común (Common Language Runtime)

Soporte de biblioteca de clases de .NET Framework Soporte de subprocesos

COM Marshaler

Corrector de tipos

Administrador de excepciones

Motor de seguridad

Motor de depuración

MSIL para compiladores nativos

Gestor de código

Recolector de elementos no utilizados

Cargador de clases

Introducción

Los runtimes no son nada nuevo en programación. Muchos otros lenguajes de programación han empleado runtimes, incluyendo Microsoft Visual Basic (VBRUN hasta la versión 4.0 y MSVBVM hasta la versión 6.0), Visual C++ (MSVCRT), Visual FoxPro® y JScript, además de lenguajes de otras empresas como SmallTalk, Perl y Java. La función más importante de .NET Framework, y lo que realmente lo diferencia de otros runtimes, es que proporciona un entorno unificado para todos los lenguajes de programación. Este entorno se conoce también como entorno gestionado.

CLR simplifica el proceso de desarrollo

A pesar de su nombre, el CLR no sólo actúa en tiempo de ejecución, sino también durante el desarrollo de un componente. Mientras se ejecuta el componente, el CLR es responsable de administrar la asignación de memoria, iniciar y terminar subprocesos y procesos, aplicar las directivas de seguridad y satisfacer las dependencias del componente respecto a otros componentes. La función del runtime cambia ligeramente durante el desarrollo. Debido a que automatiza muchas funciones (como la administración de memoria), el CLR facilita el trabajo de los desarrolladores. En particular, el CLR garantiza la corrección del código y la seguridad de tipos. El CLR también reduce drásticamente la cantidad de código que tiene que escribir un desarrollador para transformar lógica de empresa en un componente reutilizable.

Introducción a Microsoft .NET

22

A continuación se indican algunas de las funciones de programación que hasta ahora necesitaban los sistemas operativos pero que el CLR hace innecesarias: • No se necesita registrar el sistema, ya que las aplicaciones se describen por sí mismas. • No se necesitan identificadores únicos globales (GUID), ya que las clases se organizan utilizando un sistema jerárquico con nombres que pueden leer las personas. • No se necesitan archivos de lenguaje de definición de interfaz (IDL), ya que el sistema y los lenguajes utilizan las mismas representaciones. • No se utilizan HRESULTs, ya que el CLR utiliza control estructurado de excepciones. • No se necesita IUnknown, ya que sus funciones las realiza el System.Object raíz. • No se necesita añadir y liberar referencias a objetos, ya que el CLR sabe qué objetos se están usando y si es necesario pueden limpiar los objetos no utilizados. • El método COM CoCreateInstance se convierte en un operador más.

Introducción a Microsoft .NET

23

La biblioteca de clases de .NET Framework

System

Collections

IO

Security

Runtime

Configuration

Net

ServiceProcess

InteropServices

Diagnostics

Reflection

Text

Remoting

Globalization

Resources

Threading

Serialization

Introducción

La biblioteca de clases de .NET Framework es una colección de clases reutilizables, o tipos, con un alto grado de integración en el CLR. La biblioteca contiene varios espacios de nombres. A modo de ejemplo examinaremos el espacio de nombres System.

Espacio de nombres System

El espacio de nombres System.IO se encuentra bajo el espacio de nombres System y contiene servicios de entrada/salida (I/O). El espacio de nombres System.Collections proporciona listas ordenadas, tablas hash y otros grupos de datos. El espacio de nombres System.Net da soporte para TCP/IP y sockets. La biblioteca de clases de .NET Framework se diseñó para: • Habilitar la factorización y extensibilidad. • Activar como base prácticas y estándares Web. • Unificar modelos de aplicaciones. • Aumentar la productividad de los desarrolladores ofreciendo un solo modelo de programación jerárquico e intuitivo. • Permitir la herencia y depuración entre lenguajes. • Facilitar la adición y modificación de funciones de .NET Framework. • Permitir la creación de aplicaciones seguras.

Funcionalidad

La biblioteca de clases de .NET Framework proporciona una gran cantidad de funciones, incluyendo las siguientes: • Gestión de colecciones de objetos • Acceso a bases de datos • Salida a pantalla

Introducción a Microsoft .NET

24

• Seguridad y cifrado

Introducción a Microsoft .NET

25

‹ Lección: Compilación y ejecución en .NET

„

El modelo de ejecución CLR

„

Demostración: Uso de MSIL Disassembler

„

Examen de código: Programación en .NET

Introducción

Esta lección describe los procesos de ejecución y compilación empleados en .NET.

Objetivos de la lección

Al final de esta lección, usted será capaz de: • Comprender el modelo de ejecución CLR. • Definir un ensamblado y cómo se utiliza en .NET. • Comprender la compilación y ejecución de aplicaciones .NET. • Usar el MSIL Disassembler para ver un archivo portátil ejecutable.

Introducción a Microsoft .NET

26

El modelo de ejecución CLR

Introducción

Esta lección los procesos de ejecución y compilación empleados en .NET.

Ensambles y metadatos

La unidad básica de una aplicación basada en .NET recibe el nombre de ensamblado. Un ensamblado es la unidad de versión e instalación. En general, el código fuente se puede compilar en un archivo .exe o un DLL (también es posible crear módulos para vincularlos posteriormente a un archivo .exe o un DLL), que son las formas más sencillas de un ensamblado. Los compiladores generan ensamblados que contienen lenguaje intermedio de Microsoft (Microsoft Intermediate Language, MSIL). Pero además del código MSIL, el compilador también inserta metadatos en el ensamblado. Un metadato es una colección de información que describe todos los tipos, clases, métodos, campos y eventos contenidos en el ensamblado, de forma similar a una biblioteca de tipos. Pero al contrario de un servidor COM, que puede o no incluir una biblioteca de tipos, un ensamblado y sus metadatos son inseparables. Esto significa que el ensamblado se describe por sí mismo.

Ensamblados de un archivo y multiarchivo

En muchos casos es posible considerar un ensamblado como un solo archivo .exe o DLL. En algunas situaciones, un solo ensamblado puede hacer que la instalación sea mucho más simple, ya que todos los componentes necesarios están juntos. Sin embargo, algunos ensamblados (por ejemplo, DLLs) se pueden vincular en un ensamblado que recibe el nombre de ensamblado multiarchivo. Para ello se utiliza el vinculador de ensamblados, AL.exe. En algunos casos, como en aplicaciones basadas en Web, el hecho de que los ensamblados estén contenidos en archivos separados puede resultar muy ventajoso, porque es posible descargar únicamente los módulos que se necesitan.

Introducción a Microsoft .NET

El modelo de ejecución CLR

27

Antes de ejecutar el código MSIL, es preciso convertirlo en instrucciones binarias nativas. La compilación se realiza normalmente con un compilador Just-in-Time (JIT). El código fuente escrito en C#, Visual Basic .NET u otro lenguaje apropiado para el CLR se transforma primero en MSIL usando el compilador del lenguaje correspondiente. Antes de la ejecución, este código MSIL se compila en código nativo con un compilador JIT para el procesador en que se vaya a ejecutar el código. El compilador JIT no compila todo el código a la vez. La opción por defecto es hacer una compilación JIT de cada método la primera vez que se invoca, pero también es posible hacer una “compilación JIT previa” del código IL empleando Native Image Generator (NGEN.exe). Con esta opción todos los métodos se compilan antes de que se cargue la aplicación, lo que evita la compilación JIT cada vez que se invoca un método por primera vez. Hay que tener en cuenta que todos los lenguajes para el CLR deben tener unas prestaciones similares. Aunque algunos compiladores pueden crear mejor código MSIL que otros, es poco probable que haya grandes diferencias en la velocidad de ejecución.

Herencia en C#

Contenido Descripción general Derivación de clases

1 3

Implementación de métodos

11

Uso de clases selladas

22

Uso de interfaces

24

Uso de clases abstractas

31

Herencia en C#

i

Notas para el instructor Este módulo proporciona a los estudiantes información detallada sobre la herencia de clases en C# y explica cómo derivar nuevas clases a partir de otras ya existentes. También discute el uso de los tipos de métodos virtual, override y new. Explica brevemente las clases selladas y describe conceptos de interfaces. Los estudiantes aprenderán a declarar una interfaz y a implementar los dos tipos de métodos de interfaz. Finalmente, el método discute las clases abstractas y explica cómo implementar métodos y clases abstractas en una jerarquía de clases. Al final de este módulo, los estudiantes serán capaces de: • Derivar una clase nueva a partir de una clase base y hacer llamadas a miembros y constructores de la clase base desde la clase derivada. • Declarar métodos como virtuales y sustituirlos (override) u ocultarlos, según las necesidades. • Sellar una clase para que de ella no pueda derivar ninguna otra. • Implementar interfaces de forma implícita y explícita. • Describir el uso de clases abstractas y su implementación de interfaces.

Herencia en C#

1

Descripción general Objetivo del tema

Ofrecer una introducción a los contenidos y objetivos del módulo.

Explicación previa

En este módulo estudiaremos la herencia de clases en C#.

„

Derivación de clases

„

Implementación de métodos

„

Uso de clases selladas

„

Uso de interfaces

„

Uso de clases abstractas

En un sistema orientado a objetos, la herencia es la capacidad de un objeto de heredar datos y funcionalidad de su objeto padre. De esta forma, el objeto padre puede ser sustituido por un objeto hijo. La herencia también permite crear nuevas clases a partir de otras ya existentes, en lugar de crearlas partiendo de cero, y añadir luego el código que sea necesario para la nueva clase. La clase padre en la que está basada la nueva clase se llama clase base, mientras que la clase hija se conoce como clase derivada. Cuando se crea una clase derivada hay que tener en cuenta que puede sustituir al tipo de clase base. Esto significa que la herencia no sólo es un mecanismo para la reutilización de código, sino también un mecanismo de clasificación de tipos. Este último aspecto es más importante que el primero. En este módulo aprenderemos a derivar una clase de una clase base. También veremos cómo implementar métodos en una clase derivada, definiéndolos como métodos virtuales en la clase base y sustituyéndolos u ocultándolos, según el caso, en la clase derivada. Aprenderemos a sellar una clase para que no pueda derivar de ella ninguna otra. Finalmente, estudiaremos cómo implementar interfaces y clases abstractas, que definen las condiciones de un contrato al que están sujetas las clases derivadas. Al final de este módulo, usted será capaz de: • Derivar una clase nueva a partir de una clase base y hacer llamadas a miembros y constructores de la clase base desde la clase derivada. • Declarar métodos como virtuales y sustituirlos (override) u ocultarlos, según las necesidades. • Sellar una clase para que de ella no pueda derivar ninguna otra. • Implementar interfaces de forma implícita y explícita.

Herencia en C#

2

• Describir el uso de clases abstractas y su implementación de interfaces.

Herencia en C#

3

‹ Derivación de clases Objetivo del tema

Ofrecer una introducción a los temas tratados en esta sección.

Explicación previa

En esta sección discutiremos cómo derivar una clase de una clase base.

„

Extensión de clases base

„

Acceso a miembros de la clase base

„

Llamadas a constructores de la clase base

Sólo es posible derivar una clase a partir de una clase base si ésta ha sido diseñada para permitir la herencia. Esto se debe a que los objetos deben tener la estructura adecuada, ya que de lo contrario la herencia no resultará eficaz. Este hecho tiene que quedar claro en una clase base que esté diseñada para herencia. Si se deriva una nueva clase de una clase base que no está bien diseñada, cualquier cambio futuro en la clase base podría hacer que la clase derivada fuese inutilizable. Al final de esta lección, usted será capaz de: • Derivar una clase nueva a partir de una clase base. • Acceder a los miembros y constructores de la clase base desde la clase derivada.

Herencia en C#

4

Extensión de clases base Objetivo del tema

Explicar el procedimiento para extender una clase base.

Explicación previa

Es fácil entender la sintaxis de C# para derivar una clase de otra.

„

Sintaxis para derivar una clase desde una clase base

class class Token Token Clase Clase {{ Clasederivada derivada Clasebase base ... ... }} class class ComentToken: ComentToken: Token Token {{ 22puntos ... puntos ... }}

Token Token «« concrete concrete »»

ComentToken ComentToken «« concrete concrete »»

„

Una clase derivada hereda la mayor parte de los elementos de su clase base

„

Una clase derivada no puede ser más accesible que su clase base

La derivación de una clase desde una clase base se conoce también como extensión de la clase base. Una clase C# se puede extender como máximo una clase.

Sintaxis para la derivación de una clase Para indicar que una clase deriva de otra se emplea la siguiente sintaxis: class Derived: Base { ... }

Los elementos de esta sintaxis se indican en la transparencia. Cuando se declara una clase derivada, la clase base se especifica después de dos puntos. Los blancos antes y después de los dos puntos no tienen importancia. El estilo recomendado para esta sintaxis es no poner espacios antes de los dos puntos y poner un espacio después de ellos.

Herencia de la clase derivada Una clase derivada hereda todo de su clase base, salvo los constructores y destructores. Los miembros públicos de la clase base se convierten implícitamente en miembros públicos de la clase derivada. Sólo los miembros de la clase base tienen acceso a los miembros privados de esta clase, aunque la clase derivada también los hereda.

Herencia en C#

5

Accesibilidad de una clase derivada Una clase derivada no puede ser más accesible que su clase base. Por ejemplo, no es posible derivar una clase pública de una clase privada, como se ve en el siguiente código: class Example { private class NestedBase { } public class NestedDerived: NestedBase { } // Error }

La sintaxis de C# para derivar una clase de otra también está permitida en C++, donde indica implícitamente una relación de herencia privada a entre la clase base y la derivada. C# no incluye herencia privada; toda la herencia es pública.

Herencia en C#

6

Acceso a miembros de la clase base Objetivo del tema

Explicar la herencia con protección.

Explicación previa

Al igual que otros lenguajes de programación orientados a objetos, C# tiene modificador de acceso protected (protegido), además de public y private.

class class Token Token {{ ... class ... class Outside Outside protected string name; { protected string name; { }} void void Fails(Token Fails(Token t) t) class ComentToken: Token { class ComentToken: Token { {{ ... ... ... ... public string Name( ) t.name public string Name( ) t.name {{ ... ... return name; } return name; } }} }} }}

8

9

„

Los miembros heredados con protección están implícitamente protegidos en la clase derivada

„

Los miembros de una clase derivada sólo pueden acceder a sus miembros heredados con protección

„

En una struct no se usa el modificador de acceso protected

El significado del modificador de acceso protected depende de la relación entre la clase que tiene el modificador y la clase que intenta acceder a los miembros que usan el modificador. Los miembros de una clase derivada pueden acceder a todos los miembros protegidos de su clase base. Para una clase derivada, la palabra reservada protected es equivalente a la palabra public. En el fragmento de código de la transparencia, el método Name de ComentToken puede acceder a la cadena nombre, que está protegida dentro de Token, porque Token es la clase base de ComentToken. Entre dos clases que no tengan una relación base-derivada, por el contrario, los miembros protegidos de una clase se comportan como miembros privados para la otra clase. En el otro fragmento de código de la transparencia, el método Fails de Outside no puede acceder a la cadena nombre, que está protegida dentro de Token, porque Token no está especificada como clase base de Outside.

Herencia en C#

7

Miembros heredados con protección Cuando una clase derivada hereda un miembro con protección, ese miembro también es implícitamente un miembro protegido de la clase derivada. Esto significa que todas clases que deriven directa o indirectamente de la clase base pueden acceder a los miembros protegidos, como se muestra en el siguiente ejemplo: class Base { protected string name; } class Derived: Base { } class FurtherDerived: Derived { void Compiles( ) { Console.WriteLine(name); // Okay } }

Miembros protegidos y métodos Los métodos de una clase derivada sólo tienen acceso a sus propios miembros heredados con protección. No pueden acceder a los miembros protegidos de la clase base a través de referencias a ésta. Por ejemplo, el siguiente código generará un error: class ComentToken: Token { void Fails (Token t) { Console.WriteLine(t.name); // Error al compilar } }

Consejo Muchas guías de programación recomiendan mantener todos los datos privados y usar acceso protegido sólo para métodos.

Miembros protegidos y structs Una struct no permite la herencia. Como consecuencia no se puede derivar de una struct y, por lo tanto, no es posible usar el modificador de acceso protected en una struct. Por ejemplo, el siguiente código generará un error: struct Base { protected string name; // Error al compilar }

Herencia en C#

8

Llamadas a constructores de la clase base Objetivo del tema

Explicar cómo hacer llamadas a los constructores de la clase base.

Explicación previa

C# tiene una palabra reservada para llamar a un constructor de la clase base.

„

Las declaraciones de constructores deben usar la palabra base

class class Token Token {{ protected protected Token(string Token(string name) name) {{ ... ... }} ... ... }} class class ComentToken: ComentToken: Token Token {{ public public ComentToken(string ComentToken(string name) name) :: base(name) base(name) {{ }} ... ... }} „

Una clase derivada no puede acceder a un constructor privado de la clase base

„

Se usa la palabra base para habilitar el ámbito del identificador

Para hacer una llamada a un constructor de la clase base desde un constructor de la clase derivada se usa la palabra reservada base, que tiene la siguiente sintaxis: C(...): base( ) {...}

El conjunto formado por los dos puntos y la llamada al constructor de la clase base recibe el nombre de inicializador del constructor.

Declaraciones de constructores Si la clase derivada no hace una llamada explícita a un constructor de la clase base, el compilador de C# usará implícitamente un inicializador de constructor de la forma :base( ). Esto implica que una declaración de constructor de la forma C(...) {...}

es equivalente a C(...): base( ) {...}

Este comportamiento implícito es válido en muchos casos porque: • Una clase sin clases base explícitas extiende implícitamente la clase System.Object, que contiene un constructor público sin parámetros. • Si una clase no contiene ningún constructor, el compilador utilizará inmediatamente un constructor público sin parámetros llamado constructor por defecto.

Herencia en C#

9

El compilador no creará un constructor por defecto si una clase tiene su propio constructor explícito. No obstante, el compilador generará un mensaje de error si el constructor indicado no coincide con ningún constructor de la clase base, como se ve en el siguiente código: class Token { protected Token(string name) { ... } } class ComentToken: Token { public ComentToken(string name) { ... } // Error aquí }

El error se debe a que el constructor ComentToken contiene de forma implícita un inicializador de constructor :base( ), pero la clase base Token no contiene ningún constructor sin parámetros. El código mostrado en la transparencia permite corregir este error.

Reglas de acceso a constructores Las reglas de acceso de un constructor derivado a un constructor de la clase base son exactamente las mismas que para los métodos normales. Por ejemplo, si el constructor de la clase base es privado, la clase derivada no tendrá acceso a él: class NoDerivable { private NoDerivable( ) { ... } } class Imposible: NoDerivable { public Impossible( ) { ... } // Error al compilar }

En este caso, es imposible que una clase derivada pueda hacer una llamada al constructor de la clase base.

Herencia en C#

10

Ámbito de un identificador También es posible utilizar la palabra reservada base para habilitar el ámbito de un identificador. Esto puede resultar útil, puesto que una clase derivada puede declarar miembros con los mismos nombres que miembros de la clase base. El siguiente código muestra un ejemplo: class Token { protected string name; } class ComentToken: Token { public void Method(string name) { base. name = name; } }

Nota Al contrario de lo que ocurre en C++, no se utiliza el nombre de la clase base (como Token en el ejemplo de la transparencia). La palabra reservada base hace referencia claramente a la clase base porque, en C#, una clase puede extender como máximo una clase.

Herencia en C#

11

‹ Implementación de métodos Objetivo del tema

Ofrecer una introducción a los temas tratados en esta sección.

Explicación previa

En esta lección veremos cómo implementar métodos en clases derivadas.

„

Definición de métodos virtuales

„

Uso de métodos virtuales

„

Sustitución de métodos (override)

„

Uso de métodos override

„

Uso de new para ocultar métodos

„

Uso de la palabra reservada new

Los métodos de una clase base se pueden redefinir en una clase derivada si han sido diseñados para permitir la sustitución (override). Al final de esta lección, usted será capaz de: • Usar el tipo de método virtual. • Usar el tipo de método override. • Usar el tipo de método hide.

Herencia en C#

12

Definición de métodos virtuales Objetivo del tema

Explicar cómo implementar métodos virtuales.

Explicación previa

Los métodos virtuales se pueden emplear para hacer que las clases sean polimórficas.

„

Sintaxis: Se declara como virtual

class class Token Token {{ ... ... public public int int LineNumber( LineNumber( )) {{ ... ... }} public public virtual virtual string string Name( Name( )) {{ ... ... }} }} „

Los métodos virtuales son polimórficos

Un método virtual especifica una implementación de un método que puede ser sustituida por polimorfismo en una clase derivada. Del mismo modo, un método no virtual especifica la única implementación de un método. No es posible sustituir por polimorfismo un método no virtual en una clase derivada. Nota En C#, el hecho de que una clase contenga o no un método virtual es una buena indicación de si el autor la ha diseñado para que sea utilizada como clase base.

Sintaxis de la palabra reservada Para declarar un método virtual se usa la palabra clave virtual, cuya sintaxis se muestra en la transparencia. Recomendación al profesor

El ejercicio de la práctica combinará el contenido de los tres temas sobre las palabras reservadas virtual, override y new.

Un método virtual debe contener un cuerpo cuando se declara. De lo contrario, el compilador generará un error: class Token { public virtual string Name( ); // Error al compilar }

Herencia en C#

13

Uso de métodos virtuales Objetivo del tema

Describir las restricciones de los métodos virtuales.

Explicación previa

Vamos a estudiar con más detalle los métodos virtuales.

„

Para usar métodos virtuales: z

No se puede declarar métodos virtuales como estáticos

z

No se puede declarar métodos virtuales como privados

Para usar eficazmente los métodos virtuales hay que tener en cuenta lo siguiente: • No se puede declarar métodos virtuales como estáticos. Los métodos virtuales no pueden ser estáticos porque en ese caso serían métodos de clase y el polimorfismo se aplica a objetos, no a clases. • No se puede declarar métodos virtuales como privados. Los métodos virtuales no pueden ser privados porque en ese caso no podrían ser sustituidos por polimorfismo en una clase derivada. A continuación se muestra un ejemplo: class Token { private virtual string Name( ) { ... } // Error al compilar }

Herencia en C#

14

Sustitución de métodos (override) Objetivo del tema

Explicar cómo sustituir métodos.

Explicación previa

Se pueden sustituir los métodos que estén declarados como virtuales en la clase base.

„

Sintaxis: Se usa la palabra reservada override

class class Token Token {{ ... ... public public virtual virtual string string Name( Name( )) {{ ... ... }} }} class class ComentToken: ComentToken: Token Token {{ ... ... public public override override string string Name( Name( )) {{ ... ... }} }}

Un método override especifica otra implementación de un método virtual. Los métodos virtuales definidos en una clase base pueden ser sustituidos por polimorfismo en una clase derivada.

Sintaxis de la palabra reservada Para declarar un método override se usa la palabra clave override, como se ve en el siguiente código: class Token { ... public virtual string Name( ) { ... } } class ComentToken: Token { ... public override string Name( ) { ... } }

Como ocurre con los métodos virtuales, un método override debe contener un cuerpo cuando se declara, ya que de lo contrario el compilador genera un error: class Token { public virtual string Name( ) { ... } } class ComentToken: Token { public override string Nombre( ); // Error al compilar }

Herencia en C#

15

Uso de métodos override Objetivo del tema

Describir las restricciones de los métodos override.

Explicación previa

El uso de los métodos override si rige por ciertas reglas.

„

Sólo se sustituyen métodos virtuales heredados idénticos

class class Token Token {{ ... ... public public int int LineNumber( LineNumber( )) {{ ... ... }} public public virtual virtual string string Name( Name( )) {{ ... ... }} }} class class ComentToken: ComentToken: Token Token {{ ... ... public public override override int int LineNumber( LineNumber( )) {{ ... ... }} public public override override string string Name( Name( )) {{ ... ... }} }}

8 9

„

Un método override debe coincidir con su método virtual asociado

„

Se puede sustituir un método override

„

No se puede declarar explícitamente un override como virtual

„

No se puede declarar un método override como static o private

Para usar eficazmente los métodos override hay que tener en cuenta las siguientes restricciones importantes: • Sólo se pueden sustituir métodos virtuales heredados idénticos. • Un método override debe coincidir con su método virtual asociado. • Se puede sustituir un método override. • No se puede declarar explícitamente un método override como virtual. • No se puede declarar un método override como static o private. A continuación se describe con más detalle cada una de estas restricciones.

Sólo se pueden sustituir métodos virtuales heredados idénticos Un método override se puede emplear para sustituir únicamente un método virtual heredado idéntico. En el código de la transparencia, el método LineNumber en la clase derivada ComentToken causa un error de compilación porque el método heredado Token.LineNumber no está marcado como virtual.

Herencia en C#

Recomendación al profesor

Las palabras aquí empleadas han sido elegidas cuidadosamente: Un método override debe sustituir a un método virtual heredado idéntico.

16

Un método override debe coincidir con su método virtual asociado Una declaración de override debe ser en todo punto idéntica al método virtual al que sustituye. Deben tener el mismo nivel de acceso, el mismo tipo de retorno, el mismo nombre y los mismos parámetros. Por ejemplo, en el siguiente ejemplo la sustitución falla porque los niveles de acceso son diferentes (protected frente a public), los tipos de retorno cambian (string frente a void) y los parámetros son distintos (none frente a int): class Token { protected virtual string Name( ) { ... } } class ComentToken: Token { public override void Name(int i) { ... } // Errores }

Se puede sustituir un método override Un método override es virtual de forma implícita y por tanto se puede sustituir, como se ve en el siguiente ejemplo: class Token { public virtual string Name( ) { ... } } class ComentToken: Token { public override string Name( ) { ... } } class OneLineCommentToken: ComentToken { public override string Name( ) { ... } }

// Okay

Herencia en C#

17

No se puede declarar explícitamente un método override como virtual Un método override es virtual de forma implícita, pero no puede estar declarado explícitamente como virtual, como se ve en el siguiente ejemplo: class Token { public virtual string Name( ) { ... } } class ComentToken: Token { public virtual override string Name( ) { ... } // Error }

No se puede declarar un método override como static o private Un método override nunca puede estar declarado como static porque en ese caso sería un método de clase y el polimorfismo se aplica a objetos, no a clases. Del mismo modo, un método override nunca puede ser private, ya que debe sustituir a un método virtual y éste no puede ser privado.

Herencia en C#

18

Uso de new para ocultar métodos Objetivo del tema

Explicar cómo ocultar métodos heredados.

Explicación previa

„

Si se declara un método que tiene la misma signatura que un método de una clase base, es posible ocultar el método base sin utilizar override.

Sintaxis: Para ocultar un método se usa la palabra reservada new

class class Token Token {{ ... ... public public int int LineNumber( LineNumber( )) {{ ... ... }} }} class class ComentToken: ComentToken: Token Token {{ ... ... new new public public int int LineNumber( LineNumber( )) {{ ... ... }} }}

Es posible ocultar un método heredado idéntico introduciendo un nuevo método en la jerarquía de clases. De esta forma, el método original heredado por la clase derivada desde la clase base es sustituido por un método totalmente distinto.

Sintaxis de la palabra reservada La palabra reservada new se emplea para ocultar un método y tiene la siguiente sintaxis: class Token { ... public int LineNumber( )

{ ... }

} class ComentToken: Token { ... new public int LineNumber( ) { ... } }

Herencia en C#

19

Uso de la palabra reservada new Objetivo del tema

Explicar cómo usar la palabra reservada new para ocultar métodos de forma eficaz.

Explicación previa

Para hacer un buen uso de la palabra reservada new hay que tener en cuenta sus características y las restricciones que impone.

„

Ocultar tanto métodos virtuales como no virtuales

class class Token Token {{ ... ... public public int int LineNumber( LineNumber( )) {{ ... ... }} public public virtual virtual string string Name( Name( )) {{ ... ... }} }} class class ComentToken: ComentToken: Token Token {{ ... ... new new public public int int LineNumber( LineNumber( )) {{ ... ... }} public public override override string string Name( Name( )) {{ ... ... }} }}

„

Resolver conflictos de nombre en el código

„

Ocultar métodos que tengan signaturas idénticas

El uso de la palabra reservada new permite: • Ocultar tanto métodos virtuales como no virtuales. • Resolver conflictos de nombre en el código. • Ocultar métodos que tengan signaturas idénticas. A continuación se describe con más detalle cada una de estas tareas.

Herencia en C#

20

Ocultar tanto métodos virtuales como no virtuales Emplear la palabra reservada new para ocultar un método tiene implicaciones si se hace uso del polimorfismo. En el código de la transparencia, por ejemplo, ComentToken.NumeroLinea es un método new que no tiene ninguna relación con el método Token. LineNumber. Aunque Token. LineNumber fuera un método virtual, ComentToken. LineNumber seguiría siendo un método new sin ninguna relación. En este ejemplo, ComentToken. LineNumber no es virtual. Esto significa que otra clase derivada no puede sustituir ComentToken. LineNumber. Sin embargo, el método new ComentToken. LineNumber se podría declarar como virtual, en cuyo caso otras clases derivadas podrían sustituirlo, como se ve: Recomendación al profesor

En gran parte, el punto más importante de este tema es el consejo, que hace hincapié en el significado ortogonal del new. Este tema incluye muchos otros detalles, aunque no es necesario discutir todos ellos en la clase.

class ComentToken: Token { ... new public virtual int LineNumber ( ) { ... } } class OneLineCommentToken: ComentToken { public override int LineNumber ( ) { ... } }

Consejo El estilo recomendado para métodos virtuales con new es new public virtual int LineNumber ( ) { ... }

mejor que public new virtual int LineNumber ( ) { ... }

Resolver conflictos de nombre en el código Los conflictos de nombre suelen generar avisos durante la compilación. Consideremos por ejemplo el siguiente código: class Token { public virtual int LineNumber ( ) { ... } } class ComentToken: Token { public int LineNumber( ) { ... } }

Al compilar, se recibe un aviso que indica que ComentToken. LineNumber oculta Token. LineNumber. Este aviso revela el conflicto de nombres. Se puede elegir entre tres opciones: 1. Añadir un calificador override a ComentToken. LineNumber. 2. Añadir un calificador new a ComentToken. LineNumber. En este caso, el método continúa ocultando el método idéntico en la clase base, pero el new explícito comunica al compilador y al personal de mantenimiento del código que el conflicto de nombres es intencionado. 3. Cambiar el nombre del método.

Herencia en C#

21

Ocultar métodos que tengan signaturas idénticas El modificador new sólo es necesario si un método de una clase derivada oculta un método visible de la clase base que tiene una signatura idéntica. En el siguiente ejemplo, el compilador avisa de que new no es necesario porque los métodos reciben parámetros diferentes y por tanto sus signaturas no son idénticas: class Token { public int LineNumber(short s) { ... } } class ComentToken: Token { new public int LineNumber(int i) { ... } // Warning }

Del mismo modo, si dos métodos tienen signaturas idénticas el compilador avisará sobre la posibilidad de usar new porque el método de la clase base está oculto. En el siguiente ejemplo, los dos métodos tienen signaturas idénticas porque los tipos de retorno no forman parte de la signatura de un método: class Token { public virtual int LineNumber( ) { ... } } class ComentToken: Token { public void LineNumber( ) { ... } // Warning }

Nota La palabra reservada new se puede emplear también para ocultar campos y clases anidadas.

Herencia en C#

22

‹ Uso de clases selladas Objetivo del tema

Explicar cómo prevenir la herencia accidental.

„

Ninguna clase puede derivar de una clase sellada

„

Las clases selladas sirven para optimizar operaciones en tiempo de ejecución

„

Muchas clases de .NET Framework son selladas: String, StringBuilder, etc.

„

Sintaxis: Se usa la palabra reservada sealed

Explicación previa

No siempre es conveniente permitir que una clase sea heredada por otra.

namespace namespace System System {{ public public sealed sealed class class String String {{ ... ... }} }} namespace namespace Mine Mine {{ class class FancyString: FancyString: String String {{ ... ... }} }}

8

No es fácil crear una jerarquía de herencia flexible. La mayor parte de las clases son autónomas y no están diseñadas para que otras clases deriven de ellas. En términos de sintaxis, sin embargo, el procedimiento para la derivación de una clase es muy sencillo y se puede escribir en muy poco tiempo. Esto hace que los programadores puedan caer a veces en la tentación de derivar desde una clase que no está pensada para funcionar como clase base. Para prevenir este problema, y para que el programador pueda comunicar mejor sus intenciones al compilador y a otros programadores, C# permite declarar una clase como sealed (sellada). La derivación de una clase sellada no está permitida.

Herencia en C#

23

Sintaxis de la palabra reservada Para sellar una clase se utiliza la palabra reservada sealed, cuya sintaxis es la siguiente: namespace System { public sealed class String { ... } }

Microsoft® .NET Framework contiene muchos ejemplos de clases selladas. La transparencia muestra la clase System.String, cuyo alias es la palabra reservada string. Esta clase está sellada y, por tanto, ninguna otra clase puede derivar de ella.

Optimización de operaciones en tiempo de ejecución El modificador sealed permite hacer ciertas optimizaciones en tiempo de ejecución. En particular, el hecho de que una clase sellada nunca tenga clases derivadas hace posible transformar llamadas a miembros virtuales de clases selladas en llamadas a miembros no virtuales.

Herencia en C#

24

‹ Uso de interfaces Objetivo del tema

Ofrecer una introducción a los temas tratados en esta sección.

Explicación previa

En esta lección aprenderemos el procedimiento para definir y usar interfaces en C#.

„

Declaración de interfaces

„

Implementación de varias interfaces

„

Implementación de métodos de interfaz

Una interfaz especifica un contrato sintáctico y semántico al que están sujetas todas las clases derivadas. Más concretamente, en ese contrato la interfaz describe el qué, mientras que las clases que implementan la interfaz describen el cómo. Al final de esta lección, usted será capaz de: • Usar la sintaxis para declarar interfaces. • Usar las dos técnicas de implementación de métodos de interfaz en clases derivadas.

Herencia en C#

25

Declaración de interfaces Objetivo del tema

Explicar cómo declarar interfaces.

Explicación previa

Las interfaces son similares a las clases.

„

Sintaxis: Para declarar métodos se usa la palabra reservada interface

Los Losnombres nombresde deinterfaces interfaces empiezan empiezancon con“I”mayúscula “I”mayúscula

interface interface IToken IToken {{ int int LineNumber( LineNumber( ); ); string string Name( Name( ); ); }} Sin Sinespec. espec.de deacceso acceso

Para su información

No está permitido declarar tipos (como enums) dentro de una interfaz.

IToken IToken «« interface interface »» LineNumber( LineNumber( )) Name( Name( ))

Métodos Métodossin sincuerpo cuerpo

Una interfaz en C# se parece a una clase que no tiene código y se declara de forma similar, pero se usa la palabra reservada interface en vez de class. La sintaxis de esta palabra reservada está explicada en la transparencia. Nota Se recomienda que todos los nombres de interfaces comiencen con una "I" mayúscula. Por ejemplo, IToken es mejor que Token.

Características de las interfaces Las interfaces tienen las dos siguientes características importantes.

Los métodos de interfaz son implícitamente públicos Los métodos que se declaran en una interfaz son públicos de forma implícita. Como consecuencia no se permite el uso de modificadores de acceso public explícitos, como se ve en el siguiente ejemplo: interface IToken { public int LineNumber ( ); // Error al compilar }

Herencia en C#

26

Los métodos de interfaz no contienen cuerpo Los métodos que se declaran en una interfaz no pueden contener cuerpo. Por ejemplo, el siguiente código no estaría permitido: interface IToken { int LineNumber ( ) { ... } // Error al compilar }

Estrictamente hablando, las interfaces pueden contener declaraciones de propiedades de interfaz (que son declaraciones de propiedades sin cuerpo), declaraciones de eventos de interfaz (que son declaraciones de eventos sin cuerpo) y declaraciones de indizadores de interfaz (que son declaraciones de indizadores sin cuerpo).

Herencia en C#

27

Implementación de varias interfaces Objetivo del tema

Explicar cómo se puede heredar de varias interfaces.

Explicación previa

Una clase implementa una interfaz.

„

Una clase puede implementar cero o más interfaces

interface interface IToken IToken {{ IToken IVisitable IVisitable IToken string string Name( Name( ); ); «« interface »» «« interface interface »» interface }} interface interface IVisitable IVisitable {{ void void Accept(IVisitante Accept(IVisitante v); v); }} Token class Token class Token: Token: IToken, IToken, IVisitable IVisitable {{ ... «« concrete ... concrete »» }} „

Una interfaz puede extender cero o más interfaces

„

Una clase puede ser más accesible que sus interfaces base

„

Una interfaz no puede ser más accesible que su interfaz base

„

Una clase implementa todos los métodos de interfaz heredados

Aunque C# permite únicamente la herencia sencilla, es posible implementar varias interfaces en una sola clase. Este tema discute las diferencias entre una clase y una interfaz con respecto a la implementación y extensión de interfaces, respectivamente, además de su accesibilidad en comparación con sus interfaces base.

Implementación de interfaces Una clase puede implementar cero o más interfaces, pero no puede extender más de una clase de forma explícita. La transparencia muestra un ejemplo de este punto. Nota Estrictamente hablando, una clase extiende siempre una clase. Si no se especifica la clase base, una clase heredará de object implícitamente.

Herencia en C#

Recomendación al profesor

28

Por el contrario, una interfaz puede extender cero o más interfaces. Por ejemplo, el código de la transparencia se podría reescribir de la siguiente manera:

Asegúrese de que los delegados usan la terminología correcta. Una clase extiende otra clase e implementa una interfaz.

interface IToken { ... } interface IVisitable { ... } interface IVisitableToken: IVisitable, IToken { ... } class Token: IVisitableToken { ... }

En la transparencia se han dejado intencionadamente en blanco los métodos de Token. Las dos formas de implementar una interfaz se discutirán en las dos transparencias siguientes.

Accesibilidad

Un aspecto importante en este tema es que una clase debe implementar todos los métodos de interfaz heredados. Probablemente también sea conveniente mencionar que una interfaz puede heredar de otras interfaces. Dé un ejemplo.

Una clase puede ser más accesible que sus interfaces base. Por ejemplo, es posible declarar una clase pública que implemente una interfaz privada, como se ve: class Example { private interface INested { } public class Anidada: INested { } // Okay }

Sin embargo, una interfaz no puede ser más accesible que sus interfaces base. Es un error declarar una interfaz pública que extiende una interfaz privada, como se muestra en el siguiente ejemplo: class Example { private interface INested { } public interface IAlsoNested: INested { } // Error al compilar }

Métodos de interfaz Una clase debe implementar todos los métodos de todas las interfaces que extienda, independientemente de que las interfaces se hereden directa o indirectamente.

Herencia en C#

29

Implementación de métodos de interfaz Objetivo del tema

Discutir la implementación de interfaces.

Explicación previa

Hay una serie de reglas que se deben cumplir cuando se implementa una interfaz en una clase.

„

El método que implementa debe ser igual que el método de interfaz

„

El método que implementa puede ser virtual o no virtual

class class Token: Token: IToken, IToken, IVisitable IVisitable {{ public public virtual virtual string string Name( Name( )) {{ ... ... }} public public void void Accept(IVisitante Accept(IVisitante v) v) {{ ... ... }} }}

Mismo Mismoacceso acceso Mismo Mismoretorno retorno Mismo Mismonombre nombre Mismos ámetros par Mismospará parámetros

Si una clase implementa una interfaz, tiene que implementar todos los métodos declarados en esa interfaz. Este requisito es muy conveniente, ya que las interfaces no pueden definir los cuerpos de sus propios métodos. El método que la clase implementa debe ser absolutamente idéntico al método de la interfaz. Tiene que ser igual en: • Acceso Un método de interfaz es público de forma implícita, lo que significa que el método que lo implementa debe estar declarado explícitamente como público. Si se omitiera el modificador de acceso, el método sería privado por defecto. • Tipo de retorno Si el tipo de retorno en la interfaz está declarado como T, el tipo de retorno en la clase que la implementa no puede estar declarado como un tipo derivado de T, sino que debe ser T. En otras palabras, C# no permite la covarianza de tipos de retorno. • Nombre No hay que olvidar que C# distingue mayúsculas y minúsculas en los nombres. • Lista de parámetros

Herencia en C#

30

El siguiente código cumple todos estos requisitos: interface IToken { string Name( ); } interface IVisitable { void Accept(IVisitante v); } class Token: IToken, IVisitable { public virtual string Name( ) { ... } public void Accept(IVisitante v) { ... } }

El método que implementa puede ser virtual, como Name en el código anterior. En ese caso, es posible sustituir el método en otras clases derivadas. Por otro lado, el método que implementa también puede ser no virtual, como Accept en el mismo código. En este último caso, no es posible sustituir el método en otras clases derivadas.

Herencia en C#

31

‹ Uso de clases abstractas Objetivo del tema

Ofrecer una introducción a los temas tratados en esta sección.

Explicación previa

En esta lección aprenderemos a usar clases abstractas.

„

Declaración de clases abstractas

„

Uso de clases abstractas en una jerarquía de clases

„

Comparación de clases abstractas e interfaces

„

Implementación de métodos abstractos

„

Uso de métodos abstractos

Las clases abstractas se emplean para proporcionar implementaciones parciales de clases que se completan con clases derivadas concretas. Las clases abstractas son especialmente útiles para la implementación parcial de una interfaz que puede ser reutilizada por varias clases derivadas. Al final de esta lección, usted será capaz de: • Usar la sintaxis para la declaración de una clase abstracta. • Explicar el uso de clases abstractas en una jerarquía de clases.

Herencia en C#

32

Declaración de clases abstractas Objetivo del tema

Describir la sintaxis para declarar una clase abstracta.

Explicación previa

Una clase abstracta es una clase de la que no se pueden crear instancias.

„

Se usa la palabra reservada abstract

abstract abstract class class Token Token {{ ... ... }} class class Test Test {{ static static void void Main( Main( )) {{ new new Token( Token( ); ); }} }}

8

Token Token {{ abstract abstract }} No Nose sepueden puedencrear crearinstancias instancias de deuna unaclase claseabstracta abstracta

Para declarar una clase abstracta se utiliza la palabra reservada abstract, como se muestra en la transparencia. Las reglas que rigen el uso de una clase abstracta son prácticamente las mismas que se aplican a una clase no abstracta. Las únicas diferencias entre usar clases abstractas y no abstractas son: • No está permitido crear una instancia de una clase abstracta. En este sentido, las clases abstractas son como interfaces. • Se puede crear un método abstracto en una clase abstracta. Se puede declarar un método abstracto en una clase abstracta, pero no en una que no lo sea. Las clases abstractas comparten las siguientes características con las clases no abstractas: • Extensibilidad limitada Una clase abstracta puede extender como máximo otra clase o clase abstracta. Obsérvese que una clase abstracta puede extender una clase que no sea abstracta • Múltiples interfaces Una clase abstracta puede implementar varias interfaces • Métodos de interfaz heredados • Una clase abstracta debe implementar todos los métodos de interfaz heredados

Herencia en C#

33

Uso de clases abstractas en una jerarquía de clases Objetivo del tema

Ilustrar el uso de clases abstractas en la implementación de interfaces.

Explicación previa

Las clases abstractas se emplean a menudo para la implementación parcial de interfaces.

„

Ejemplo 1

interface interface IToken IToken {{ string string Name( Name( ); ); }}

IToken IToken «« interface interface »»

abstract abstract class class Token: Token: IToken IToken {{ string string IToken.Name( IToken.Name( )) {{ ... ... }} ... ... }} class class ComentToken: ComentToken: Token Token {{ ... ... }} class class KeywordToken: KeywordToken: Token Token {{ ... ... }}

Token Token {{ abstract abstract }}

Coment Coment Token Token «« concrete concrete »»

Keyword Keyword

Token Token «« concrete concrete »»

La función de las clases abstractas en una jerarquía clásica de tres niveles, formada por una interfaz, una clase abstracta y una clase concreta, es proporcionar una implementación completa o parcial de una interfaz.

Una clase abstracta que implementa una interfaz Consideremos el Ejemplo 1 en la transparencia, en el que la clase abstracta implementa una interfaz. Es una implementación explícita del método de interfaz. La implementación explícita no es virtual y por tanto no se puede sustituir en las demás clases derivadas, como ComentToken. Sin embargo, CommentToken puede reimplementar la interfaz IToken de la siguiente manera: interface IToken { string Name( ); } abstract class Token: IToken { string IToken.Name( ) { ... } } class ComentToken: Token, IToken { public virtual string Name( ) { ... } }

Como se ve, en este caso no es necesario marcar ComentToken.Name como método new. Esto se debe a que una clase derivada sólo puede ocultar un método de clase base visible, pero la implementación explícita de Name en Token no es directamente visible en ComentToken.

Herencia en C#

34

Uso de clases abstractas en una jerarquía de clases (cont.) Objetivo del tema

Ilustrar el uso de clases abstractas en la implementación de interfaces.

Explicación previa

Aquí se da otro ejemplo del uso de clases abstractas para la implementación parcial de interfaces.

„

Ejemplo 2

interface interface IToken IToken {{ string string Name( Name( ); ); }} abstract abstract class class Token Token {{ public virtual public virtual string string Name( Name( )) {{ ... ... }} ... ... }}

IToken IToken «« interface interface »»

Token Token {{ abstract abstract }}

Coment Coment class class ComentToken: ComentToken: Token, Token, IToken IToken {{ ... Token Token ... }} « concrete »» « concrete class class KeywordToken: KeywordToken: Token, Token, IToken IToken {{ ... ... }}

Keyword Keyword

Token Token «« concrete concrete »»

Esta transparencia muestra otro ejemplo para continuar la discusión de la función de las clases abstractas en una jerarquía clásica de tres niveles.

Una clase abstracta que no implementa una interfaz Recomendación al profesor

La discusión del Ejemplo 2 tiene dos objetivos principales: 1. Mostrar la sintaxis que se utiliza para extender una clase e implementar una o más interfaces. 2. Explicar que una clase derivada puede heredar su implementación de una interfaz desde la clase base que extiende, incluso en caso de que esa clase base no implemente esa interfaz.

Consideremos el Ejemplo 2 en la transparencia, en el que la clase abstracta no implementa la interfaz. Esto significa que la única forma de que proporcione una implementación de la interfaz a otra clase derivada concreta es mediante un método público. Opcionalmente, el método puede estar declarado como virtual en la clase abstracta para que sea posible sustituirlo en las clases, como se muestra en el siguiente código: interface IToken { string Name( ); } abstract class Token { public virtual string Name( ) { ... } } class ComentToken: Token, IToken { public override string Name( ) { ... } // Okay }

Como se ve, una clase puede heredar su interfaz y su implementación de esa interfaz desde distintas ramas de la herencia.

Herencia en C#

35

Comparación de clases abstractas e interfaces Objetivo del tema

Comparar clases abstractas e interfaces. „

Explicación previa

Entre las clases abstractas y las interfaces existen algunos parecidos, pero también muchas diferencias.

„

Parecidos z

No se pueden crear instancias de ninguna de ellas

z

No se puede sellar ninguna de ellas

Diferencias z

Las interfaces no pueden contener implementaciones

z

Las interfaces no pueden declarar miembros no públicos

z

Las interfaces no pueden extender nada que no sea una interfaz

Tanto las clases abstractas como las interfaces existen para derivar otras clases de ellas (o ser implementadas). Sin embargo, una clase puede extender como máximo una clase abstracta, por lo que hay que tener más cuidado cuando se deriva de una clase abstracta que cuando se deriva de una interfaz. Las clases abstractas se deben utilizar solamente para implementar relaciones del tipo “es un”. Los parecidos entre clases abstractas e interfaces son: • No se pueden crear instancias de ellas. Esto significa que no es posible usarlas directamente para crear objetos. • No se pueden sellar. Esto es normal, ya que no es posible implementar una interfaz sellada. La siguiente tabla resume las diferencias entre clases abstractas e interfaces. Interfaces

Clases abstractas

No pueden contener implementación

Pueden contener implementación

No pueden declarar miembros no públicos

Pueden declarar miembros no públicos

Pueden extender sólo otras interfaces

Pueden extender otras clases, que pueden no ser abstractas

Cuando se comparan clases abstractas e interfaces, se puede pensar en las clases abstractas como clases sin terminar que contienen los planes para lo que falta por hacer.

Herencia en C#

36

Implementación de métodos abstractos Objetivo del tema

Explicar cómo se implementan métodos abstractos.

Explicación previa

Una clase derivada puede sustituir un método virtual, pero debe sustituir un método abstracto.

„

Sintaxis: Se usa la palabra reservada abstract

abstract abstract class class Token Token {{ public public virtual virtual string string Name( Name( )) {{ ... ... }} public public abstract abstract int int Longitud( Longitud( ); ); }} class class ComentToken: ComentToken: Token Token {{ public public override override string string Name( Name( )) {{ ... ... }} public override int Longitud( ) { public override int Longitud( ) { ... ... }} }} „

Sólo clases abstractas pueden declarar métodos abstractos

„

Los métodos abstractos no pueden tener cuerpo

Para declarar un método abstracto hay que añadir el modificador abstract a la declaración del método. La sintaxis del modificador abstract se muestra en la transparencia. Sólo clases abstractas pueden declarar métodos abstractos, como se ve en este ejemplo: interface IToken { abstract string Name( ); // Error al compilar } class CommentToken { abstract string Name( ); // Error al compilar }

Recomendación al profesor

Es obligatorio sustituir un método abstracto, pero no es necesario sustituir un método virtual.

Nota Los desarrolladores en C++ pueden considerar los métodos abstractos como equivalentes a los métodos virtuales puros de C++.

Los métodos abstractos no pueden tener cuerpo Los métodos abstractos no pueden contener ninguna implementación, como queda claro en el siguiente código: abstract class Token { public abstract string Name( ) { ... } // Error al compilar }

Herencia en C#

37

Uso de métodos abstractos Objetivo del tema

Describir las restricciones de los métodos abstractos.

Explicación previa

Antes de implementar un método abstracto hay que tener en cuenta sus características y las restricciones que impone.

„

Los métodos abstractos son virtuales

„

Los métodos override pueden sustituir a métodos abstractos en otras clases derivadas

„

Los métodos abstractos pueden sustituir a métodos de la clase base declarados como virtuales

„

Los métodos abstractos pueden sustituir a métodos de la clase base declarados como override

Al implementar métodos abstractos hay que tener en cuenta lo siguiente: • Los métodos abstractos son virtuales. • Los métodos override pueden sustituir a métodos abstractos en otras clases derivadas. • Los métodos abstractos pueden sustituir a métodos de la clase base declarados como virtuales. • Los métodos abstractos pueden sustituir a métodos de la clase base declarados como override. A continuación se describe en detalle cada uno de estos puntos.

Los métodos abstractos son virtuales Los métodos abstractos se consideran implícitamente virtuales pero no pueden estar marcados como virtuales de forma explícita, como se ve en el siguiente código: abstract class Token { public virtual abstract string Name( ) { ... } // Error al compilar }

Herencia en C#

38

Los métodos override pueden sustituir a métodos abstractos en otras clases derivadas Al ser implícitamente virtuales, es posible sustituir métodos abstractos en clases derivadas. A continuación se muestra un ejemplo: Recomendación al profesor

Puede utilizar el siguiente fragmento para ver hasta qué punto los estudiantes comprenden este aspecto: abstract class A { public abstract void M( ); } abstract class B: A { public abstract void M( ); }

Esto no está permitido. Una clase no podría implementar A.M y B.M.

class ComentToken: Token { public override string Name( ) {...} }

Los métodos abstractos pueden sustituir a métodos de la clase base declarados como virtuales La sustitución de un método de clase base declarado como virtual fuerza a otra clase derivada a tener su propia implementación del método, y hace que no se pueda utilizar la implementación original del método. A continuación se muestra un ejemplo: class Token { public virtual string Name( ) { ... } } abstract class Force: Token { public abstract override string Name( ); }

Los métodos abstractos pueden sustituir a métodos de la clase base declarados como override La sustitución de un método de clase base declarado como override fuerza a otra clase derivada a tener su propia implementación del método, y hace que no se pueda utilizar la implementación original del método. A continuación se muestra un ejemplo: class Token { public virtual string Name( ) { ... } } class AnotherToken: Token { public override string Name( ) { ... } } abstract class Force: AnotherToken { public abstract override string Name( ); }

Herencia en C#

1

Práctica : Uso de herencia para implementar una interfaz Objetivos Al final de esta práctica, usted será capaz de: • Definir y usa interfaces, clases abstractas y clases concretas. • Implementar una interfaz en una clase concreta. • Saber cómo y cuándo usar las palabras reservadas virtual y override. • Definir una clase abstracta y usarla en una jerarquía de clases. • Crear clases selladas para impedir la herencia.

Requisitos previos Antes de realizar la práctica debe estar familiarizado con los siguientes temas: • Creación de clases en C#. • Definición de métodos para clases.

Ejercicio 1 Conversión de un archivo fuente de C# en un archivo HTML con sintaxis en color La gran utilidad de los marcos de trabajo se debe a que proporcionan código flexible y fácil de utilizar. Al contrario de una biblioteca, que se usa mediante una llamada directa a un método, un marco de trabajo se emplea creando una nueva clase que implementa una interfaz. El código del marco de trabajo realiza entonces llamadas polimórficas a los métodos de la clase por medio de las operaciones de la interfaz. Esto hace que haya muchos usos posibles de un marco de trabajo bien diseñado, mientras que un método de biblioteca sólo se puede usar de una forma.

Resumen Este ejercicio emplea una jerarquía (ya escrita) de clases e interfaces que forman un marco de trabajo en miniatura. El marco de trabajo divide una archivo fuente de C# en unidades léxicas (lo “tokeniza”) y almacena los distintos tipos de tokens en una colección contenida en la clase SourceFile. También se dispone de una interfaz ITokenVisitor con operaciones Visit que, combinada con el método Accept de SourceFile, permite visitar y procesar secuencialmente cada token del archivo de origen. Cuando se visita un token, una clase puede utilizarlo para efectuar todo el procesamiento necesario. Se ha creado una clase abstracta llamada NullTokenVisitor, que implementa todos los métodos Visit de ITokenVisitor utilizando métodos vacíos. Si no se desea implementar todos los métodos de ITokenVisitor, es posible derivar una clase de NullTokenVisitor y sustituir sólo los métodos Visit que se elija. Este ejercicio derivará una clase HTMLTokenVisitor a partir de la interfaz ITokenVisitor. Implementará todos los métodos Visit sobrecargados en esta clase derivada para enviar a la consola el token entre corchetes por marcadores

Herencia en C#

2

y del lenguaje de marcado de hipertexto (HTML). Ejecutará un sencillo archivo de proceso por lotes (batch) que iniciará el ejecutable creado y redireccionará la salida de consola para crear una página HTML que use una hoja de estilos en cascada. Finalmente, abrirá la página HTML en Microsoft Internet Explorer para ver el archivo fuente original con sintaxis en color.

Herencia en C#

3

Cómo acceder a las interfaces 1. Abra el proyecto ColorTokeniser.sln en la carpeta carpeta de Starter\ColorTokeniser dentro del fichero lab10.zip. 2. Examine las clases e interfaces en los archivos Itoken.cs, Itoken_visitor.cs y source_file.cs. La jerarquía establecida es la siguiente:

Herencia en C#

4

Cómo crear una clase abstracta NullTokenVisitor 1. Abra el archivo null_token_visitor.cs. Observe que NullTokenVisitor deriva de la interfaz ITokenVisitor, pero no implementa ninguna de las operaciones especificadas en la interfaz. Para poder construir HTMLTokenVisitor tendrá que implementar todas las operaciones heredadas como métodos vacíos.

2. Añada a la clase NullTokenVisitor un método virtual público llamado Visit. Este método devolverá void y recibirá un solo parámetro ILineStartToken. El cuerpo del método tiene que estar vacío. El código del método será: public class NullTokenVisitor : ITokenVisitor { public virtual void Visit(ILineStartToken t) { } ... }

3. Repita el paso 2 para todos los demás métodos Visit sobrecargados que están declarados en la interfaz ITokenVisitor. Implemente todos los métodos Visit en NullTokenVisitor como métodos vacíos. 4. Guarde el trabajo realizado. 5. Compile null_token_visitor.cs. La compilación no dará ningún error si ha implementado todas las operaciones Visit de la interfaz ITokenVisitor. Si ha omitido alguna operación, el compilador mostrará un mensaje de error.

Herencia en C#

5

6. Añada a la clase NullTokenVisitor un método privado, estático y void llamado Test. Este método no recibirá ningún parámetro y contendrá una sola instrucción que cree un objeto new NullTokenVisitor. Esta instrucción comprobará que la clase NullTokenVisitor ha implementado todas las operaciones Visit y que es posible crear instancias de NullTokenVisitor. El código para este método será el siguiente: public class NullTokenVisitor : ITokenVisitor { ... static void Test( ) { new NullTokenVisitor( ); } }

7. Guarde el trabajo realizado. 8. Compile null_token_visitor.cs y corrija los posibles errores. 9. Cambie la definición de NullTokenVisitor. Puesto la clase NullTokenVisitor no se va a utilizar para crear instancias sino para derivar otra clase de ella, es preciso cambiar la definición para que sea una clase abstracta. 10. Vuelva a compilar null_token_visitor.cs. Compruebe también que ahora la instrucción new dentro del método Test causa un error, ya que no está permitido crear instancias de una clase abstracta. 11. Borre el método Test. 12. NullTokenVisitor tiene que quedar de esta forma: public abstract class NullTokenVisitor : ITokenVisitor { public virtual void Visit(ILineStartToken t) { } public virtual void Visit(ILineEndToken t) { } public public public public public

virtual virtual virtual virtual virtual

void void void void void

Visit(ICommentToken Visit(IDirectiveToken Visit(IIdentifierToken Visit(IKeywordToken Visit(IWhiteSpaceToken

t) t) t) t) t)

public virtual void Visit(IOtherToken t) { } }

{ { { { {

} } } } }

Herencia en C#

6

Cómo crear una clase HTMLTokenVisitor 1. Abra el archivo html_token_visitor.cs. 2. Modifique la clase HTMLTokenVisitor de forma que derive de la clase abstracta NullTokenVisitor.

3. Abra el archivo main.cs file y añada dos instrucciones al método estático InnerMain. a. La primera instrucción declarará una variable llamada visitor de tipo HTMLTokenVisitor y la inicializará con un objeto HTMLTokenVisitor de nueva creación. b. La segunda instrucción pasará visitor como parámetro al método Accept llamado en la variable ya declarada source. 4. Guarde el trabajo realizado. 5. Compile el programa y corrija los posibles errores. Ejecute el programa desde la línea de comandos, pasando como argumento el nombre de un archivo fuente .cs de la carpeta bin\debug del proyecto ColorTokeniser. ¡No ocurrirá nada, puesto que todavía no ha definido ningún método en la clase HTMLTokenVisitor!

Herencia en C#

7

6. Añada un método Visit público y no estático a la clase HTMLTokenVisitor. Este método devolverá void y recibirá un solo parámetro ILineStartToken llamado line. Implemente el cuerpo del método con una sola instrucción que llame a Write (no WriteLine) para mostrar el valor de line.Number( ) en la consola. Observe que Number es una operación declarada en la interfaz ILineStartToken. No utilice las palabras reservadas virtual ni override para declarar el método. El siguiente código muestra este método: public class HTMLTokenVisitor : NullTokenVisitor { public void Visit(ILineStartToken line) { Console.Write(line.Number( )); // No WriteLine } }

7. Guarde el trabajo realizado. 8. Compile el programa. Vuelva a ejecutar el programa igual que antes. No ocurrirá nada, ya que el método Visit en HTMLTokenVisitor está ocultando el método Visit en la clase base NullTokenVisitor. 9. Modifique HTMLTokenVisitor.Visit(ILineStartToken) de forma que sustituya a Visit de su clase base. Esto hará que HTMLTokenVisitor.Visit sea polimórfico, como se ve en el siguiente código: public class HTMLTokenVisitor : NullTokenVisitor { public override void Visit(ILineStartToken line) { Console.Write(line.Number( )); } }

10. Guarde el trabajo realizado. 11. Compile el programa y corrija los posibles errores. Ejecute el programa igual que antes. El resultado contendrá números en orden creciente y sin espacios intermedios (los números son los de las líneas generadas para el archivo indicado).

Herencia en C#

8

12. En HTMLTokenVisitor, defina un método sobrecargado Visit público y no estático que devuelva void y reciba un solo parámetro ILineEndToken. Esta revisión añade una nueva línea entre las líneas de tokens. Observe que esta operación está declarada en la interfaz ITokenVisitor. Implemente el cuerpo de este método para imprimir una sola nueva línea en la consola, como se muestra (este método usa WriteLine, no Write): public class HTMLTokenVisitor : NullTokenVisitor { ... public override void Visit(ILineEndToken t) { Console.WriteLine( ); // No Write } }

13. Guarde el trabajo realizado. 14. Compile el programa y corrija los posibles errores. Ejecute el programa igual que antes. Cada número de línea terminará esta vez con una línea aparte. Cómo usar HTMLTokenVisitor para mostrar tokens del archivo fuente de C# 1. Añada a la clase HTMLTokenVisitor un método Visit público y no estático. Este método devolverá void y recibirá un solo parámetro IIdentifierToken llamado token. Debe sustituir al método correspondiente en la clase base NullTokenVisitor. 2. Implemente el cuerpo del método con una sola instrucción que llame a Write para mostrar token en la consola como string: public class HTMLTokenVisitor : NullTokenVisitor { ... public override void Visit(IIdentifierToken token) { Console.Write(token.ToString( )); } }

Nota Abra el archivo IToken.cs y observe que IIdentifierToken deriva de IToken y que IToken declara un método ToString. 3. Guarde el trabajo realizado. 4. Compile el programa y corrija los posibles errores. Ejecute el programa igual que antes. Esta vez la salida incluirá todos los identificadores. 5. Repita los pasos 1 a 4, añadiendo a HTMLTokenVisitor otros cuatro métodos Visit sobrecargados. Cada uno de ellos recibirá un solo parámetro de tipo ICommentToken, IKeywordToken, IWhiteSpaceToken y IOtherToken, respectivamente. Los cuerpos de estos métodos serán iguales al descrito en el paso 2.

Herencia en C#

9

Cómo convertir un archivo fuente de C# en un archivo HTML 1. La carpeta bin\debug del proyecto ColorTokeniser contiene una secuencia de comandos llamada generate.bat, que ejecuta el programa ColorTokeniser usando el parámetro que se le indique en la línea de comandos. También efectúa algún procesamiento previo y posterior del archivo resultante, empleando una hoja de estilos en cascada (code_style.css) para convertir la salida en HTML. Ejecute el programa desde la línea de comandos utilizando el archivo generate.bat y pasando como parámetro el archivo token.cs (que es en realidad una copia de parte del código fuente para el programa, pero que usaremos como archivo .cs de ejemplo). Capture la salida en otro archivo que tenga la extensión .html. Por ejemplo: generate token.cs > token.html

2. Use Internet Explorer para ver el archivo .html que acaba de crear (token.html en el ejemplo del paso anterior). Puede hacerlo escribiendo token.html en la línea de comandos. El resultado tendrá muchos errores de formato. La indentación de las líneas posteriores a 9 es diferente a la de las anteriores. Esto se debe a que los números inferiores a 10 tienen un solo dígito, mientras que los números mayores que 9 tienen dos dígitos. Observe también que los números de línea aparecen con el mismo color que los tokens del archivo de origen, lo que no resulta demasiado útil. Cómo encontrar y corregir problemas de número de línea e indentación 1. Cambie la definición del método Visit(ILineStartToken) como se indica a continuación para corregir estos problemas en el resultado: public class HTMLTokenVisitor : NullTokenVisitor { public override void Visit(ILineStartToken line) { Console.Write(""); Console.Write("{0,3}", line.Number( )); Console.Write(""); } ... }

2. Guarde el trabajo realizado. 3. Compile el programa y corrija los posibles errores.

Herencia en C#

10

4. Vuelva a crear el archivo token.html a partir del archivo de origen token.cs desde la línea de comandos: generate token.cs > token.html

5. Abra token.html en Internet Explorer. Todavía hay un problema. Al comparar el aspecto de token.html en Internet Explorer con el archivo token.cs original, se observa que el primer comentario en token.cs (/// ) aparece en el explorador como “///”. Se ha perdido . El problema es que, en HTML, algunos caracteres tienen un significado especial. El código fuente en HTML para mostrar los paréntesis angulares de apertura () es, respectivamente < y >, mientras que para el ampersand (&) hay que escribir &. Cómo hacer los cambio necesarios para mostrar correctamente los caracteres de paréntesis angulares y ampersand 1. Añada a HTMLTokenVisitor un método privado y no estático llamado FilteredWrite que devuelva void y reciba un solo parámetro de tipo IToken llamado token. Este método creará una string llamada dst a partir de token y recorrerá uno por uno todos los caracteres de dst aplicando las transformaciones descritas anteriormente. El código será como éste: public class HTMLTokenVisitor : NullTokenVisitor { ... private void FilteredWrite(IToken token) { string src = token.ToString( ); for (int i = 0; i != src.Length; i++) { string dst; switch (src[i]) { case '' : dst = ">"; break; case '&' : dst = "&"; break; default : dst = new string(src[i], 1); break; } Console.Write(dst); } } }

Herencia en C#

11

2. Cambie la definición de HTMLTokenVisitor.Visit(ICommentToken) para usar el nuevo método FilteredWrite en lugar de Console.Write: public class HTMLTokenVisitor : NullTokenVisitor { public override void Visit(ICommentToken token) { FilteredWrite(token); } ... }

3. Cambie la definición de HTMLTokenVisitor.Visit(IOtherToken) para usar el nuevo método FilteredWrite en lugar de Console.Write: public class HTMLTokenVisitor : NullTokenVisitor { public override void Visit(IOtherToken token) { FilteredWrite(token); } ... }

4. Guarde el trabajo realizado. 5. Compile el programa y corrija los posibles errores. 6. Vuelva a crear el archivo token.html a partir del archivo de origen token.cs desde la línea de comandos: generate token.cs > token.html

7. Abra token.html en Internet Explorer y compruebe que ahora aparecen correctamente los caracteres de paréntesis angulares y ampersand.

Herencia en C#

12

Cómo añadir comentarios en color al archivo HTML 1. Use el Bloc de Notas para abrir la hoja de estilos code_style.css en la carpeta bin\debug del proyecto ColorTokeniser. Para añadir color al archivo HTML se usará el archivo de hoja de estilos en cascada code_style.css . Este archivo ha sido creado antes de la práctica y su contenido es como el que se muestra en el siguiente ejemplo: ... SPAN.LINE_NUMBER { background-color: white; color: gray; } ... SPAN.COMMENT { color: green; font-style: italic; }

El método HTMLTokenVisitor.Visit(ILineStartToken) ya utiliza esta hoja de estilos: public class HTMLTokenVisitor : NullTokenVisitor { public override void Visit(ILineStartToken line) { Console.Write(""); Console.Write("{0,3}", line.Number( )); Console.Write(""); } ... }

Observe que este método escribe las palabras “span” y “line_number”, y que la hoja de estilos contiene una entrada para SPAN.LINE_NUMBER. 2. Modifique el cuerpo de HTMLTokenVisitor.Visit(ICommentToken) para que reciba lo siguiente: public class HTMLTokenVisitor : NullTokenVisitor { public override void Visit(ICommentToken token) { Console.Write(""); FilteredWrite(token); Console.Write(""); } ... }

3. Guarde el trabajo realizado. 4. Compile el programa y corrija los posibles errores.

Herencia en C#

13

5. Vuelva a crear el archivo token.html a partir del archivo de origen token.cs desde la línea de comandos: generate token.cs > token.html

6. Abra token.html en Internet Explorer. Compruebe que los comentarios del archivo de origen aparecen ahora en verde y en cursiva. Cómo añadir palabras reservadas en color al archivo HTML 1. Observe que el archivo code_style.css file contiene la siguiente entrada: ... SPAN.KEYWORD { color: blue; } ...

2. Modifique el cuerpo de HTMLTokenVisitor.Visit(IKeywordToken) para que use el estilo indicado en la hoja de estilos: public class HTMLTokenVisitor : NullTokenVisitor { public override void Visit(IKeywordToken token) { Console.Write(""); FilteredWrite(token); Console.Write(""); } ... }

3. Guarde el trabajo realizado. 4. Compile el programa y corrija los posibles errores. 5. Vuelva a crear el archivo token.html a partir del archivo de origen token.cs desde la línea de comandos: generate token.cs > token.html

6. Abra token.html en Internet Explorer y compruebe que las palabras reservadas aparecen ahora en azul.

Herencia en C#

14

Cómo modificar los métodos Visit para eliminar repeticiones 1. Observe que en los dos métodos Visit anteriores hay repeticiones, ya que ambos escriben cadenas span en la consola. Es posible modificar los métodos Visit para evitar esta duplicación. Defina un nuevo método privado y no estático llamado SpannedFilteredWrite que devuelva void y reciba dos parámetros, uno string llamado spanName y un IToken llamado token. El cuerpo de este método contendrá tres instrucciones: la primera escribirá la cadena span en la consola usando el parámetro spanName, la segunda llamará al método FilteredWrite pasando token como argumento, y la tercera escribirá en la consola la cadena span de cierre. El código será como se indica a continuación: public class HTMLTokenVisitor : NullTokenVisitor { ... private void SpannedFilteredWrite(string spanName, ¬IToken token) { Console.Write("", spanName); FilteredWrite(token); Console.Write(""); } ... }

2. Modifique HTMLTokenVisitor.Visit(ICommentToken) para utilizar este nuevo método, como se indica: public class HTMLTokenVisitor : NullTokenVisitor { ... public override void Visit(ICommentToken token) { SpannedFilteredWrite("comment", token); } ... }

3. Modifique HTMLTokenVisitor.Visit(IKeywordToken) para utilizar este nuevo método, como se indica: public class HTMLTokenVisitor : NullTokenVisitor { ... public override void Visit(IKeywordToken token) { SpannedFilteredWrite("keyword", token); } ... }

Herencia en C#

15

4. Modifique el cuerpo del método HTMLTokenVisitor. Visit(IIdentifierToken) para que llame al método SpannedFilteredWrite. Esto es necesario porque el archivo code_style.css file también contiene una entrada para tokens de identificadores. public class HTMLTokenVisitor : NullTokenVisitor { ... public override void Visit(IIdentifierToken token) { SpannedFilteredWrite("identifier", token); } ... }

5. Guarde el trabajo realizado. 6. Compile el programa y corrija los posibles errores. 7. Vuelva a crear el archivo token.html a partir del archivo de origen token.cs desde la línea de comandos: generate token.cs > token.html

8. Abra token.html en Internet Explorer. Compruebe que los comentarios siguen apareciendo en verde y que las palabras reservadas aún están en azul. Cómo implementar HTMLTokenVisitor directamente desde ITokenVisitor 1. Abra el archivo html_token_visitor.cs. 2. Modifique el código de forma que la clase HTMLTokenVisitor derive de la interfaz ITokenVisitor. Puesto que ha implementado prácticamente todos los métodos Visit de HTMLTokenVisitor, ya no es necesario que herede de la clase abstracta NullTokenVisitor (que proporciona una implementación vacía por defecto para todos los métodos de ITokenVisitor) y puede derivar directamente de la interfaz ITokenVisitor.

Herencia en C#

16

La clase será como se indica: public class HTMLTokenVisitor : ITokenVisitor { ... }

3. Guarde el trabajo realizado. 4. Compile el programa. Habrá muchos errores. El problema es que los métodos Visit en HTMLTokenVisitor siguen estando declarados como override, pero no está permitido sustituir una operación en una interfaz. 5. Elimine la palabra reservada override de la definición de todos los métodos Visit. 6. Compile el programa. Todavía quedará un error. El problema en esta ocasión es que HTMLTokenVisitor no implementa la operación Visit(IDirectiveToken) heredada de su interfaz ITokenVisitor. Anteriormente, HTMLTokenVisitor heredaba desde NullTokenVisitor una implementación vacía de esta operación. 7. En HTMLTokenVisitor, defina un método público no estático llamado Visit que devuelva void y reciba un solo parámetro de tipo IDirectiveToken llamado token. Esto resolverá el problema de implementación. El cuerpo de este método contendrá una llamada al método SpannedFilteredWrite pasándole dos parámetros: la “directiva” literal string y la variable token. public class HTMLTokenVisitor : ITokenVisitor { ... public void Visit(IDirectiveToken token) { SpannedFilteredWrite("directive", token); } ... }

8. Guarde el trabajo realizado. 9. Compile el programa y corrija los posibles errores. 10. Vuelva a crear el archivo token.html a partir del archivo de origen token.cs desde la línea de comandos: generate token.cs > token.html

11. Abra token.html en Internet Explorer. Compruebe que los comentarios siguen apareciendo en verde y que las palabras reservadas aún están en azul.

Herencia en C#

17

Cómo impedir el uso de HTMLTokenVisitor como clase base 1. Declare HTMLTokenVisitor como clase sellada. Dado que los métodos de HTMLTokenVisitor ya no son virtuales, parece razonable declarar HTMLTokenVisitor como una clase sellada como se muestra en el siguiente código: public sealed class HTMLTokenVisitor : ITokenVisitor { ... }

2. Compile el programa y corrija los posibles errores. 3. Vuelva a crear el archivo token.html a partir del archivo de origen token.cs desde la línea de comandos: generate token.cs > token.html

4. Abra token.html en Internet Explorer y compruebe que los comentarios siguen apareciendo en verde y que las palabras reservadas aún están en azul.

Herencia en C#

18

Ejercicio 2 Conversión de un archivo fuente de C# en un archivo HTML con sintaxis en color En este ejercicio examinará otra aplicación que usa el mismo marco de trabajo empleado en el Ejercicio 1.

Resumen En esta aplicación, la clase ColorTokenVisitor deriva de la interfaz ITokenVisitor. Los métodos Visit de esta clase escriben tokens en color en un RichTextBox dentro de una aplicación de formularios de Microsoft Windows®. Las clases forman la siguiente jerarquía:

Cómo acceder a las interfaces: 1. Abra el proyecto ColorSyntaxApp.sln en la carpeta Solution\ColourSyntaxApp dentro del fichero lab10.zip. 2. Estudie los contenidos de los dos archivos .cs files. Observe que la clase ColorTokenVisitor es muy similar a la clase HTMLTokenVisitor creada en el Ejercicio 1. La diferencia más importante es que ColorTokenVisitor escribe los tokens en color en un componente de formulario RichTextBox en lugar de la consola. 3. Cree el proyecto. 4. Ejecute la aplicación. a. Pulse Open File (Abrir archivo). b. En el cuadro de diálogo que aparece, elija un archivo fuente .cs. c. Pulse Open (Abrir). Los contenidos del archivo .cs seleccionado aparecerán en color.

Introducción a C#

Contenido Descripción general

1

Estructura de un programa C#

2

Operaciones básicas de entrada/salida

9

Compilación, ejecución y depuración

18

Introducción a C#

i

Notas para el instructor ƒ Este módulo presenta a los estudiantes el lenguaje de programación C#. Los estudiantes aprenderán los elementos básicos de un programa C# elemental. También se discutirán buenas prácticas y estilo de programación. Finalmente, los estudiantes aprenderán a usar Microsoft® Visual Studio® para editar, compilar, ejecutar y depurar un programa C#. ƒ Al final de este módulo, los estudiantes serán capaces de: ƒ Explicar la estructura de un programa C# sencillo. ƒ Utilizar la clase Console del espacio de nombres System para realizar operaciones básicas de entrada/salida. ƒ Tratar excepciones en un programa C#. ƒ Generar documentación en lenguaje de marcado extensible (XML) para un programa C#. ƒ Compilar, vincular y ejecutar un programa C#. ƒ Utilizar el Visual Studio Debugger para seguir paso a paso un programa C#.

Introducción a C#

1

‹Notas generales Objetivo del tema

Ofrecer una introducción a los contenidos y objetivos del módulo.

Explicación previa

En este módulo aprenderá los elementos básicos de C# y cómo compilar, vincular y ejecutar un programa C#.

„

Estructura de un programa C#

„

Operaciones básicas de entrada/salida

„

Prácticas recomendadas

„

Compilación, ejecución y depuración

En este módulo estudiará la estructura básica de un programa C# analizando un ejemplo de trabajo sencillo. Aprenderá a usar la clase Console para realizar algunas operaciones básicas de entrada y salida. Aprenderá también algunas prácticas recomendadas para el tratamiento de errores y la documentación del código, y finalmente compilará, ejecutará y compilará un programa C#. Al final de este módulo, usted será capaz de: ƒ Explicar la estructura de un programa C# sencillo. ƒ Utilizar la clase Console del espacio de nombres System para realizar operaciones básicas de entrada/salida. ƒ Tratar excepciones en un programa C#. ƒ Generar documentación en lenguaje de marcado extensible (XML) para un programa C#. ƒ Compilar y ejecutar un programa C#. ƒ Utilizar el depurador para seguir paso a paso la ejecución de un programa.

Introducción a C#

2

‹ Estructura de un programa C# Objetivo del tema

Ofrecer una introducción a los temas tratados en esta sección.

Explicación previa

En esta sección estudiará la estructura básica de un programa C#.

Recomendación al profesor

En esta lección se hacen muchas comparaciones entre C# y otros lenguajes con los que los estudiantes pueden estar familiarizados. Es recomendable señalar las similitudes y las pequeñas (y no tan pequeñas) diferencias.

„

Hola, mundo

„

La clase

„

El método Main

„

La sentencia using y el espacio de nombres System

„

Demostración: Uso de Visual Studio para crear un programa C#

En esta lección estudiará la estructura básica de un programa C# analizando un programa simple que contiene todas las características esenciales. También aprenderá a usar Microsoft® Visual Studio® para crear y editar un programa C#.

Introducción a C#

3

Hola, mundo Objetivo del tema

Mostrar un programa C# que funciona.

Explicación previa

El primer programa que se suele escribir en un lenguaje nuevo es el inevitable Hola, mundo.

using using System; System; class class Hola Hello {{ public public static static void void Main() Main() {{ Console.WriteLine("Hola, Console.WriteLine("Hello mundo”); , World"); }} }}

Recomendación al profesor

Éste es el estilo, diseño y definición de Main que emplea Visual Studio para crear un nuevo programa C#. Puede escribir el código, compilarlo y ejecutarlo desde la línea de comandos.

El primer programa que se suele escribir cuando se aprende un lenguaje nuevo es el inevitable Hola, mundo. En este módulo tendrá la oportunidad de examinar la versión en C# de este primer programa. El código de ejemplo en la transparencia contiene todos los elementos esenciales de un programa C# y es muy fácil de probar. Lo único que hace cuando se ejecuta desde la línea de comandos es mostrar el siguiente mensaje: Hola, mundo

En los temas que siguen analizaremos este programa simple para aprender más sobre los componentes de un programa C#.

Introducción a C#

4

La clase Objetivo del tema

Destacar que todas las aplicaciones C# son una colección de clases.

Explicación previa

Una aplicación C# es una colección de una o más clases.

„ Una

aplicación C# es una colección de clases, estructuras y tipos

„ Una

clase es un conjunto de datos y métodos

„ Sintaxis

class name class nombre {{ ... ... }}

Recomendación al profesor

No inicie todavía una discusión completa sobre la definición de una clase. Limítese a la explicación sencilla que se da en las notas de los estudiantes.

„ Una

aplicación C# puede incluir muchos archivos

„ Una

clase no puede abarcar más de un archivo

En C#, una aplicación es una colección de una o más clases, estructuras de datos y otros tipos. En este módulo se define una clase como un conjunto de datos combinados con métodos (o funciones) que pueden manipular esos datos. En módulos posteriores aprenderemos más sobre clases y todo lo que pueden ofrecer al programador de C#. Un examen del código para la aplicación Hola, mundo revela que hay una sola clase llamada Hola. Esta clase se introduce con la palabra clave class. Después del nombre de la clase hay una llave de apertura ({). Todo lo que hay hasta la correspondiente llave de cierre (}) forma parte de la clase. Las clases para una aplicación C# se pueden extender a uno o más archivos. Es posible poner varias clases en un archivo, pero una sola clase no puede abarcar más de un archivo. Nota para programadores en Java No es necesario que el nombre del archivo de la aplicación coincida con el nombre de la clase. Nota para programadores en C++ C# no distingue entre la definición y el uso de una clase de la misma forma que C++. No existe el concepto de archivo de definición (.hpp). Todo el código para la clase se escribe en un solo archivo.

Introducción a C#

5

El método Main Objetivo del tema

Explicar dónde comienza una aplicación C# cuando se ejecuta.

Explicación previa

Cuando se ejecuta una aplicación C#, la ejecución se inicia con el método Main.

„ Al

escribir Main hay que:

z

Utilizar una “M” mayúscula, como en “Main”

z

Designar un Main como el punto de entrada al programa

z

Declarar Main como public static void Main

„ Un

Main puede pertenecer a múltiple clases

„ La

aplicación termina cuando Main acaba o ejecuta un return

Consejo para el profesor

Al tratar este tema, haga hincapié en que muchos de los puntos discutidos se tratarán en detalle más adelante. El objetivo de este tema es simplemente destacar las reglas básicas del método Main.

Recomendación al profesor

Es posible poner Main en una estructura en lugar de una clase. Las estructuras se tratarán más adelante en este módulo.

Todas las aplicaciones tienen que empezar por algún sitio. Cuando se ejecuta una aplicación C#, la ejecución se inicia en el método llamado Main. Si está acostumbrado a programar en C, C++ o incluso en Java, este concepto le resultará familiar. El lenguaje C# distingue entre mayúsculas y minúsculas. Main debe estar escrito con una “M” mayúscula y con las demás letras en minúsculas. Aunque en una aplicación C# puede haber muchas clases, no puede haber más que un punto de entrada. Es posible tener muchas clases con Main en la misma aplicación, pero se ejecutará sólo un Main. Al compilar la aplicación hay que especificar cuál se va a utilizar. También es importante la firma de Main. Si se emplea Visual Studio, se creará automáticamente como static void (como veremos más adelante en el curso). No se debe cambiar la firma si no hay una buena razón para hacerlo. Consejo Hasta cierto punto es posible cambiar la firma, pero debe ser siempre static, ya que de lo contrario es posible que el compilador no la reconozca como punto de entrada a la aplicación. La aplicación se ejecuta hasta llegar al final de Main o hasta que Main ejecuta una instrucción return.

Introducción a C#

6

La sentencia using y el espacio de nombres System Objetivo del tema

Explicar el empleo de la sentencia using para acceder a espacios de nombres.

Explicación previa

C# incluye muchas clases de utilidad que están organizadas en espacios de nombres.

„ .NET

Framework ofrece muchas clases de utilidad

z Organizadas „ System „ Se

en espacios de nombres

es el espacio de nombres más utilizado

hace referencia a clases por su espacio de nombres

System.Console.WriteLine("Hola, mundo”); , World"); „ La

sentencia using

using using System; System; …… Console.WriteLine("Hola, mundo”); Console.WriteLine("Hello , World");

Recomendación al profesor

Los espacios de nombres se tratarán con detalle en el módulo 11, “Agregación, espacios de nombres y ámbito avanzado”, del curso 2124C, Programación en C#. La información que se da aquí es suficiente para entender la sentencia using.

Como parte de Microsoft .NET Framework, C# incluye muchas clases de utilidad que realizan una gran variedad de operaciones útiles. Estas clases están organizadas en espacios de nombres, que son conjuntos de clases relacionadas. Un espacio de nombres también puede contener otros espacios de nombres. .NET Framework está compuesto por muchos espacios de nombres, el más importante de los cuales se llama System. El nombre de espacios System contiene las clases que emplean la mayor parte de las aplicaciones para interactuar con el sistema operativo. Las clases más utilizadas son las de entrada y salida (E/S). Como ocurre en muchos otros lenguajes, C# no tiene funciones propias de E/S y por tanto depende del sistema operativo para ofrecer una interfaz compatible con C#. Para hacer referencia a objetos en espacios de nombres se utiliza un prefijo explícito con el identificador del espacio de nombres. Por ejemplo, el espacio de nombres System contiene la clase Console, que a su vez contiene varios métodos, como WriteLine. Se puede acceder al método WriteLine de la clase Console de la siguiente manera: System.Console.WriteLine("Hola, mundo");

Sin embargo, el uso de un nombre completo para referirse a objetos puede resultar poco manejable y propicio a errores. Para hacerlo más sencillo, se puede especificar un espacio de nombres poniendo una sentencia using al comienzo de la aplicación, antes de la definición de la primera clase. Una sentencia using especifica el espacio de nombres que se examinara si una clase no está definida explícitamente en la aplicación. Es posible poner más de una sentencia using en el archivo de origen, pero todas tienen que ir al principio del archivo.

Introducción a C#

Recomendación al profesor

Asegúrese de que los programadores de C y C++ entienden la diferencia entre la sentencia using y la declaración #include. Los desarrolladores de Java estarán más familiarizados con este punto, ya que es similar a la sentencia import.

7

Con la sentencia using se puede escribir el código anterior de la siguiente manera: using System; ... Console.WriteLine("Hola, mundo");

En la aplicación Hola, mundo, la clase Console no está definida explícitamente. Cuando se compila la aplicación, el compilador busca Console en el espacio de nombres System y genera código que hace referencia al nombre completo System.Console. Nota Las clases del espacio de nombres System, así como las demás funciones básicas a las que se accede en tiempo de ejecución, residen en un ensamblado llamado mscorlib.dll que es el que se utiliza por defecto. Es posible referirse a clases de otros ensamblados, pero para ello hay que especificar las ubicaciones y los nombres de esos ensamblados al compilar la aplicación.

Introducción a C#

8

Uso de Visual Studio para crear un programa C# Cómo crear una aplicación C# 1. Inicie Visual Studio .NET. 2. En el menú File (Archivo), señale New (Nuevo) y pulse Project (Proyecto). 3. En el cuadro de diálogo New Project (Nuevo proyecto), escriba la información indicada en la siguiente tabla y pulse OK. Elemento

Valor

Tipo de proyecto (vista de árbol)

Visual C# Projects

Plantillas (icono)

Console Application

Nombre

Hola

Ubicación

C:\temp

4. Una vez generado el proyecto, señale y discuta las siguientes características de Visual Studio: • La ventana Solution Explorer (Explorador de soluciones) i. Cierre la ventana de código Class1.cs. ii. Cambie el nombre de Class1.cs a Hola.cs. iii. Haga doble clic en Hola.cs para volver a abrir la ventana de código. • La ventana Properties (Propiedades) • Las barras de herramientas • El menú View (Ver) • El menú Build (Compilar) • El menú Debug (Depurar) • El menú Help (Ayuda) 5. Utilizando la ventana de código Hola.cs, señale y discuta lo siguiente: • El espacio de nombres Hola Menciones que los espacios de nombres se discutirán más adelante. Podría borrar esta línea y las llaves correspondientes, pero por el momento déjelas como están. • La sentencia using • Los comentarios de XML Use esta sección para describir brevemente el programa. Los comentarios se discutirán en detalle más adelante. • La definición de clase El nombre por defecto de la clase es Class1. Cámbielo a Demonstrator. • El método Main Escriba el siguiente código: Console.WriteLine("Hola, mundo");

• Microsoft IntelliSense® 6. En el menú File, seleccione Save All (Guardar todo). 7. Cierre Visual Studio.

Introducción a C#

9

‹ Operaciones básicas de entrada/salida Objetivo del tema

Ofrecer una introducción a los temas tratados en esta sección.

Explicación previa

En esta lección aprenderá a realizar en C# operaciones básicas de E/S orientadas a la consola.

„ La

clase Console

„ Los

métodos Write y WriteLine

„ Los

métodos Read y ReaLine

En esta lección aprenderá a realizar en C# operaciones de entrada/salida basadas en comandos utilizando la clase Console. También aprenderá a mostrar información con los métodos Write y WriteLine, así como a obtener información introducida desde el teclado con los métodos Read y ReadLine.

Introducción a C#

10

La clase Console Objetivo del tema

Explicar el empleo de la clase Console.

Explicación previa

Puede emplear métodos de la clase Console para leer datos introducidos desde el teclado o para escribir datos en la pantalla.

„

Permite acceder a las secuencias estándar de entrada, salida y error

„

Sólo tiene sentido para aplicaciones de consola z Entrada z Salida z Error

„

Recomendación al profesor

Insista en que la clase Console se debe utilizar únicamente para aplicaciones de línea de comandos. Los desarrolladores que escriban aplicaciones de interfaz gráfica de usuario (GUI) tienen que usar clases del espacio de nombres System.Windows.Forms.

estándar: teclado

estándar: Pantalla

estándar: Pantalla

Es posible redireccionar todas las secuencias

La clase Console hace que una aplicación C# pueda acceder a las secuencias estándar de entrada, salida y error. La entrada estándar está asociada normalmente con el teclado, de forma que todo lo que el usuario escribe en el teclado se puede leer desde la secuencia de entrada estándar. Del mismo modo, la secuencia de salida estándar suele estar dirigida a la pantalla, al igual que la secuencia de error estándar. Nota Estas secuencias y la clase Console sólo tienen sentido para aplicaciones de consola, que son las que se ejecutan en una ventana Command (Comandos). Es posible direccionar cualquiera de las tres secuencias (entrada estándar, salida estándar, error estándar) a un archivo o dispositivo, tanto durante la programación como al ejecutar la aplicación.

Introducción a C#

11

Los métodos Write y WriteLine Objetivo del tema

Explicar los métodos Write y WriteLine de la clase Console.

Explicación previa

Los métodos Write y WriteLine permiten enviar información a la secuencia de salida estándar.

Recomendación al profesor

Puede ser conveniente buscar paralelismos con cout en C++, printf en C y System.out.print en Java, dependiendo de los estudiantes. En Visual Basic no hay ninguna función que sea realmente equivalente. Procure también que la discusión sobre sobrecarga de métodos sea corta y simple. Es posible que algunos estudiantes aún no la entiendan, y además se tratará con más detalle en un módulo posterior.

„

Console.Write y Console.WriteLine muestran información en la pantalla de la consola z WriteLine envía un fin de línea/retorno de carro

„

Ambos métodos son sobrecargados

„

Es posible emplear una cadena de formato y parámetros z

Formatos de texto

z

Formatos numéricos

Los métodos Console.Write y Console.WriteLine se pueden utilizar para mostrar información en la pantalla de la consola. Los dos métodos son muy similares; la diferencia más importante es que WriteLine añade un fin de línea/retorno de carro al final de la salida, mientras que Write no lo hace. Ambos métodos son sobrecargados. Puede explicarlo con números variables y tipos de parámetros. Por ejemplo, puede usar el siguiente código para escribir “99” en la pantalla: Console.WriteLine(99);

También puede usar el siguiente código para escribir “Hola, mundo” en la pantalla: Console.WriteLine("Hola, mundo");

Formatos de texto Existen formas de Write y WriteLine más potentes, que toman una cadena de formato y parámetros adicionales. La cadena de formato especifica cómo aparecen los datos y puede contener marcadores, que son sustituidos por los parámetros que siguen. Por ejemplo, puede usar el siguiente código para mostrar el mensaje “La suma de 100 y 130 es 230”: Console.WriteLine("La suma de {0} y {1} es {2}", 100, 130, 100+130);

Importante El primer parámetro que sigue a la cadena de formato se referencia como parámetro cero: {0}.

Introducción a C#

12

Se puede utilizar el parámetro de la cadena de formato para especificar anchuras de campos y para indicar si los valores en esos campos deben ir justificados a derecha o a izquierda, como se ve en el siguiente código: Console.WriteLine("\"Justificación a la izquierda en un campo de anchura 10: {0, -10}\"", 99); Console.WriteLine("\"Justificación a la derecha en un campo de anchura 10: {0,10}\"", 99);

Esto hará que en la consola aparezca lo siguiente: “Justificación a la izquierda en un campo de anchura 10: 99 “Justificación a la derecha en un campo de anchura 10:

” 99”

Nota Para desactivar el significado especial de un carácter en una cadena de formato se puede usar una barra diagonal inversa (\) antes de ese carácter. Por ejemplo, "\{" hará que aparezca un "{" literal y "\\" mostrará un "\" literal. También se puede emplear el carácter @ para representar al pie de la letra una cadena entera. Por ejemplo, @"\\server\share" dará como resultado "\\server\share."

Formatos numéricos Es posible utilizar la cadena de formato para especificar el formato de datos numéricos. La sintaxis completa para la cadena de formato es {N,M: FormatString}, donde N es el número del parámetro, M es la anchura y justificación del campo, y FormatString indica cómo se deben mostrar los datos numéricos. La tabla siguiente resume los valores que puede adoptar FormatString. Opcionalmente, en todos estos formatos se puede especificar el número de dígitos que se desea mostrar o al que se debe redondear. Valor

Significado

C

Muestra el número como una unidad monetaria, usando el símbolo y las convenciones de la moneda local.

D

Muestra el número como un entero decimal.

E

Muestra el número como usando notación exponencial (científica).

F

Muestra el número como un valor en coma fija.

G

Muestra el número como un valor entero o en coma fija, dependiendo del formato que sea más compacto.

N

Muestra el número con comas incorporadas.

X

Muestra el número utilizando notación hexadecimal.

Introducción a C#

13

El siguiente código muestra algunos ejemplos de formatos numéricos: Console.WriteLine("Formato ¬-888.8); Console.WriteLine("Formato Console.WriteLine("Formado Console.WriteLine("Formato ¬888.8888); Console.WriteLine("Formato Console.WriteLine("Formato Console.WriteLine("Formato

de moneda - {0:C}

{1:C4}", 88.8,

entero - {0:D5}", 88); exponencial - {0:E}", 888.8); de punto fijo - {0:F3}", general - {0:G}", 888.8888); de número - {0:N}", 8888888.8); hexadecimal - {0:X4}", 88);

El resultado de ejecutar este código es el siguiente: Formato Formato Formado Formato Formato Formato Formato

de moneda - $88.80 ($888.8000) entero - 00088 exponencial - 8.888000E+002 de punto fijo - 888.889 general - 888.8888 de número - 8,888,888.80 hexadecimal – 0058

Nota Para más información sobre formatos, busque “cadenas de formato” en la ayuda de Microsoft MSDN®.

Introducción a C#

14

Los métodos Read y ReadLine Objetivo del tema

Explicar los métodos Read y ReadLine de la clase Console.

Explicación previa

Los métodos Read y ReadLine permiten obtener información introducida por el usuario con el teclado.

„ Console.Read

y Console.ReadLine leen información introducida por el usuario z Read lee el siguiente carácter z

Recomendación al profesor

No se ofrece ningún ejemplo de Read porque, para tener algún sentido, el ejemplo tendría que mostrar cómo pasar de un entero (devuelto por Read) a un carácter: int i; char c; i = Console.Read( ); c = (char) i; Console.WriteLine(c);

ReadLine lee toda la línea introducida

Los métodos Console.Read y Console.ReadLine se pueden utilizar para mostrar información introducida por el usuario con el teclado.

El método Read Read lee el siguiente carácter desde el teclado. Devuelve el valor int –1 si ya no hay más información. De lo contrario, devuelve un int que representa el carácter leído.

El método ReadLine ReadLine lee todos los caracteres hasta el final de la línea introducida (el retorno de carácter de carro). La información introducida se devuelve como una cadena de caracteres. El siguiente código se puede utilizar para leer una línea de texto desde el teclado y mostrarla en la pantalla: string input = Console.ReadLine( ); Console.WriteLine("{0}", input);

Introducción a C#

15

Comentarios a aplicaciones Objetivo del tema

Explicar cómo hacer comentarios a aplicaciones.

Explicación previa

„

Todas las aplicaciones deben llevar comentarios adecuados.

Los comentarios son importantes z

„

Una aplicación con los comentarios adecuados permite a un desarrollador comprender perfectamente la estructura de la aplicación

Comentarios de una sola línea

// nombre del usuario // Obtener Get the el user’s name Console.WriteLine("¿Cómo llama? Console.WriteLine("What is se your name?"); "); name ); name ==Console.ReadLine( Console.ReadLine ( ); „

Comentarios de varias líneas

/* la mayor de la /* Encontrar Find the higher rootraíz of the ecuación cuadrática */ quadratic equation */ xx == (…); (…);

Recomendación al profesor

Los comentarios son importantes, pero su distribución y densidad dependen de las preferencias del desarrollador. Pregunte a los estudiantes cuáles son las normas sobre comentarios seguidas en sus organizaciones.

Es importante que todas las aplicaciones tengan una documentación adecuada. Siempre hay que incluir suficientes comentarios para que un desarrollador que no participara en la creación de la aplicación original pueda seguir y comprender su funcionamiento. Los comentarios deben ser exhaustivos y pertinentes. Unos buenos comentarios añaden información que no es fácil de expresar usando sólo las instrucciones del código, ya que explican el “porqué” en lugar del “qué.” Siga las normas de su organización para comentar código (si las tiene). C# ofrece varios mecanismos que permiten añadir comentarios al código de aplicaciones: comentarios de una sola línea, comentarios de varias líneas y documentación generada en XML. Para añadir un comentario de una sola línea se pueden utilizar los caracteres de barra diagonal (//). Al ejecutar la aplicación, se ignora todo lo que sigue a estos dos caracteres hasta el final de la línea. También es posible hacer comentarios en bloques de varias líneas. Un comentario en bloque empieza con el par de caracteres /* y continúa hasta llegar al el par de caracteres */ correspondiente. Los comentarios en bloques no pueden estar anidados.

Introducción a C#

16

Tratamiento de excepciones Objetivo del tema

Explicar cómo capturar excepciones de tiempo de ejecución en C#.

Explicación previa

Una buena aplicación C# debe tener capacidad para enfrentarse a lo inesperado.

Recomendación al profesor

En este tema se ofrecen comentarios generales sobre el tratamiento de excepciones. Se darán más detalles en el módulo 4, “Instrucciones y excepciones”, del curso 2124C, Programación en C#.

using using System; System; public public class class Hello Hello {{ public public static static void void Main(string Main(string[[ ]] args args)) {{ try{ try{ Console.WriteLine(args[0]); Console.WriteLine(args[0]); }} catch catch (Exception (Exception e) e) {{ Console.WriteLine("Excepción Console.WriteLine("Exception enat ¬ ¬{0}", {0}", e.StackTrace e.StackTrace ); ); }} }} }}

Una buena aplicación C# debe tener capacidad para enfrentarse a lo inesperado. Por muchas comprobaciones de error que se añadan al código, siempre habrá algo que pueda ir mal. El usuario puede dar una respuesta imprevista a una pregunta, por ejemplo, o tratar de escribir a un archivo en una carpeta que ha sido borrada. Las posibilidades son infinitas. Si se produce un error de tiempo de ejecución en una aplicación C#, el sistema operativo lanza una excepción. Las excepciones se pueden capturar con una combinación de las instrucciones try y catch, como se muestra en la transparencia. Si alguna de las instrucciones en la parte try de la aplicación hace que se produzca una excepción, la ejecución pasará al bloque catch. Para obtener información sobre la excepción producida se pueden emplear las propiedades StackTrace, Message y Source del objeto Exception. El tratamiento de excepciones se tratará con más detalle en un módulo posterior. Nota Si se imprime una excepción, utilizando por ejemplo Console.WriteLine, la excepción se dará formato automáticamente y mostrará las propiedades StackTrace, Message y Source.

Introducción a C#

17

Consejo Incluir el tratamiento de excepciones en aplicaciones C# desde el principio es mucho más sencillo que tratar de añadirlo después. Si no se utiliza tratamiento de excepciones se producirá una excepción en tiempo de ejecución. Si en lugar de ello se prefiere depurar un programa utilizando depuración Just-in-Time, es preciso activarla antes. Una vez activada, depuración Just-in-Time indicará el depurador que hay que utilizar dependiendo del entorno y de las herramientas instaladas.

Ejecute los siguientes pasos para activar la depuración Just-in-Time: 1. En el menú Tools (Herramientas), pulse Options (Opciones). 2. En el cuadro de diálogo Options, haga clic en la carpeta Debugging (Depuración). 3. En la carpeta Debugging, pulse Just-In-Time Debugging (Depuración Just-in-Time). 4. Active o desactive la depuración Just-in-Time (JIT) para distintos tipos de programas y pulse OK. El depurador se estudiará en detalle más adelante en este módulo.

Introducción a C#

18

‹ Compilación, ejecución y depuración Objetivo del tema

Ofrecer una introducción a los temas tratados en esta sección.

Explicación previa

En esta sección aprenderá a compilar, ejecutar y depurar programas C#.

„ Llamadas

al compilador

„ Ejecución

de la aplicación

„ Demostración:

Compilación y ejecución de un

„ Demostración:

Uso del depurador de Visual Studio

programa C# „ Depuración „ Las

herramientas del SDK

„ Demostración:

Uso del ILDASM

En esta lección aprenderá a compilar y depurar programas C#. Verá cómo se ejecuta el compilador desde la línea de comandos y desde el entorno Visual Studio. Aprenderá algunas opciones comunes de compilador y conocerá el Visual Studio Debugger. Finalmente, aprenderá a utilizar algunas de las otras herramientas del kit de desarrollo de software (SDK) de Microsoft .NET Framework..

Introducción a C#

19

Llamadas al compilador Objetivo del tema

Explicar cómo compilar una aplicación C# y las diferentes opciones de compilador disponibles.

Explicación previa

En preciso compilar las aplicaciones C# antes de ejecutarlas.

„

Conmutadores comunes del compilador

„

Compilación desde la línea de comandos

„

Compilación desde Visual Studio

„

Localización de errores

Antes de ejecutar una aplicación C# es necesario compilarla. El compilador convierte el código fuente escrito por usted en código máquina que puede entender el sistema. Se pueden hacer llamadas al compilador de C# desde la línea de comandos o desde Visual Studio. Nota Estrictamente hablando, las aplicaciones C# se compilan a lenguaje intermedio de Microsoft (MSIL) y no al código máquina nativo. El código MSIL se compila a su vez a código máquina con el compilador Just-in-Time (JIT) cuando se ejecuta la aplicación. No obstante, también es posible compilar directamente a código máquina y evitar el compilador JIT empleando la utilidad Native Image Generator (Ngen.exe), que crea una imagen nativa a partir de un ensamblado administrado y la instala en la caché de imagen nativa del sistema local. La ejecución de Ngen.exe sobre un ensamblado hace que éste se cargue más rápido, ya que restaura código y estructuras de datos desde la caché de imagen nativa en lugar de generarlas de forma dinámica.

Conmutadores comunes del compilador Es posible especificar distintos conmutadores para el compilador de C# usando el comando csc. La siguiente tabla describe los conmutadores más comunes. Conmutador

Significado

/?, /help

Muestra las opciones del compilador en la salida estándar.

/out

Especifica el nombre del ejecutable.

/main

Especifica la clase que contiene el método Main (si en la aplicación hay más de una clase que incluya un método Main).

/optimize

Activa y desactiva el optimizador de código.

Introducción a C#

20 (continúa) Conmutador

Significado

/warn

Fija el nivel de aviso del compilador.

/warnaserror

Trata todos los avisos como errores que interrumpen la compilación.

/target

Especifica el tipo de aplicación generada.

/checked

Indica si un desbordamiento aritmético genera una excepción en tiempo de ejecución.

/doc

Procesa comentarios de documentación para crear un archivo XML.

/debug

Genera información sobre la depuración.

Compilación desde la línea de comandos Para compilar una aplicación C# desde la línea de comandos se emplea el comando csc. Por ejemplo, para compilar la aplicación Hola, mundo (Hola.cs) desde la línea de comandos, generar información sobre la depuración y crear un ejecutable llamado Saludo.exe, el comando es: csc /debug+ /out:Saludo.exe Hola.cs

Importante El archivo de salida que contiene el código compilado debe incluir el sufijo .exe. Si se omite el sufijo, es necesario cambiar el nombre del archivo antes de ejecutarlo.

Compilación desde Visual Studio Para compilar una aplicación C# utilizando Visual Studio, abra el proyecto que contiene la aplicación C# y seleccione Build Solution (Compilar solución) en el menú Build. Nota Por defecto, Visual Studio abre la configuración de depuración (Debug) para el proyecto. Esto significa que lo que se compila es una versión de depuración de la aplicación. Si desea compilar una versión de lanzamiento que no contenga información sobre la depuración, cambie la configuración de la solución a lanzamiento (Release). Para cambiar las opciones empleadas por el compilador se puede modificar la configuración del proyecto: 1. En Solution Explorer, pulse con el botón derecho del ratón en el icono del proyecto. 2. Pulse Properties (Propiedades). 3. En el cuadro de diálogo Property Pages (Páginas de propiedades), pulse Configuration Properties (Propiedades de configuración) seguido de Build. 4. Especifique las opciones que desee del compilador y pulse OK.

Introducción a C#

21

Localización de errores El compilador de C# informará de los errores sintácticos o semánticos que detecte. Si la llamada al compilador se hizo desde la línea de comandos, el compilador mostrará mensajes en los que indicará los números de línea y el carácter dentro de cada línea donde se encontraran errores. Si la llamada al compilador se hizo desde Visual Studio, la ventana Task List (Lista de tareas) mostrará todas las líneas que incluyan errores. Haga doble clic sobre una línea de esta ventana para ir al error correspondiente en la aplicación. Consejo Es frecuente que un solo error de programación varios errores de compilación. Lo mejor es repasar todos los errores a partir de los que se encontraron primero, ya que corregir un error al principio del código puede hacer que desaparezcan automáticamente varios errores posteriores.

Introducción a C#

22

Ejecución de la aplicación Objetivo del tema

Explicar cómo se ejecuta una aplicación compilada.

Explicación previa

Una aplicación C# se puede ejecutar desde la línea de comandos o desde Visual Studio.

„ Ejecución z Escribir

el nombre de la aplicación

„ Ejecución z Pulsar

desde la línea de comandos

desde Visual Studio

Start Without Debugging en el menú Debug

Una aplicación C# se puede ejecutar desde la línea de comandos o desde el entorno Visual Studio.

Ejecución desde la línea de comandos Cuando la aplicación se compila sin problemas se genera un archivo ejecutable (un archivo cuyo sufijo es .exe). Para ejecutarlo desde la línea de comandos, escriba el nombre de la aplicación (con o sin el sufijo .exe).

Ejecución desde Visual Studio Para ejecutar la aplicación desde Visual Studio, pulse Start Without Debugging (Iniciar sin depuración) en el menú Debug (Depurar) o pulse CTRL+F5. Si se trata de una aplicación de consola, se abrirá inmediatamente una ventana de consola y la aplicación se ejecutará. Una vez finalizada la aplicación, el sistema le pedirá que pulse cualquier tecla para continuar y la ventana de consola se cerrará.

Introducción a C#

23

Depuración Objetivo del tema

Explicar el uso de Visual Studio para depurar una aplicación.

Explicación previa

Visual Studio contiene muchas herramientas prácticas que le permitirán depurar y corregir aplicaciones.

„

Excepciones y depuración JIT

„

El Visual Studio Debugger z Configuración z Seguimiento z Examen

de puntos de interrupción e inspecciones

del código paso a paso

y modificación de variables

Excepciones y depuración JIT Si una aplicación lanza una excepción y no se ha escrito el código necesario para ese caso, el runtime de lenguaje común hará que se inicie una depuración JIT (no hay que confundir la depuración JIT con el compilador JIT). Suponiendo que se ha instalado Visual Studio, se abrirá un cuadro de diálogo que dará a elegir entre depurar la aplicación con el Visual Studio Debugger (entorno de desarrollo de Microsoft) o con el depurador del SDK de .NET Framework. Si se dispone de Visual Studio, lo más recomendable es elegir el depurador del entorno de desarrollo de Microsoft. Nota El SDK de .NET Framework ofrece otro depurador llamado cordbg.exe, que es un depurador para línea de comandos. Incluye la mayor parte de las funciones ofrecidas por el entorno de desarrollo de Microsoft, salvo la interfaz gráfica de usuario. En este curso no se discutirá este depurador. Recomendación al profesor

Abra Visual Studio y muestre a los estudiantes las opciones de menú y las barras de herramientas durante la discusión. Después de este tema encontrará una demostración más completa.

Configuración de puntos de interrupción e inspecciones en Visual Studio Se puede utilizar el Visual Studio Debugger para fijar puntos de interrupción en el código y examinar los valores de variables. Al pulsar con el botón derecho del ratón sobre una línea de código se abre un menú con muchas opciones útiles. Seleccione Insert Breakpoint para insertar un punto de interrupción en esa línea. También puede insertar un punto de interrupción pulsando en el margen izquierdo. Vuelva a pulsar para borrar el punto. Al ejecutar la aplicación en modo de depuración, la ejecución se detendrá en esta línea y será posible examinar el contenido de variables.

Introducción a C#

24

La ventana Watch (Inspección) resulta útil para supervisar los valores de variables seleccionadas mientras se ejecuta la aplicación. Si escribe el nombre de una variable en la columna Name (Nombre), su valor aparecerá en la columna Value (Valor), por lo que podrá ver todos los cambios que se produzcan durante la ejecución. También es posible sobrescribir el valor de una variable inspeccionada para modificarla. Importante Antes de utilizar el depurador, asegúrese de que la configuración de la solución es Debug y no Release.

Seguimiento del código paso a paso Una vez fijados los puntos de interrupción necesarios, se puede ejecutar la aplicación seleccionando Start (Inicio) en el menú Debug o pulsando F5. La ejecución se detendrá al llegar al primer punto de interrupción. La ejecución se reanudará al seleccionar Continue (Continuar) en el menú Debug, aunque también se pueden emplear las opciones de avance paso a paso del menú Debug para avanzar en el código línea por línea. Consejo Las opciones de punto de interrupción, avance paso a paso e inspección de variables se encuentran también en la barra de herramientas Debug.

Examen y modificación de variables Para ver las variables definidas en un método se puede pulsar Locals (Locales) en la barra de herramientas Debug o bien utilizar la ventana Watch. También es posible sobrescribir el valor de una variable para modificarla (como en la ventana Watch).

Introducción a C#

25

Uso del Visual Studio Debugger Este programa C#, que convierte temperaturas de Fahrenheit a Celsius, contiene un error que en algunos casos produce resultados incorrectos en la conversión de temperaturas. Encuentre y corrija el problema. Cómo ejecutar el programa C# 1. Abra el proyecto Converter, que se encuentra en la carpeta Converter dentro del archivo demo02.zip. 2. Ejecute el programa seleccionando Start Without Debugging en el menú Debug o pulsando CTRL+F5. Explique que el programa pide al usuario una temperatura en grados Fahrenheit. A continuación convierte ese valor en un entero y lo almacena en la variable degreesFahrenheit. Luego calcula la temperatura Celsius equivalente con la fórmula de conversión estándar y almacena el resultado en la variable degreesCelsius. Finalmente, el programa muestra la temperatura Fahrenheit original junto con el valor calculado en Celsius. 3. Escriba 32 cuando el sistema le pida una temperatura. Haga notar a los estudiantes que programa convierte esta temperatura en 0 grados Celsius, que es correcto. 4. Vuelva a ejecutar el programa y escriba 212 cuando el sistema le pida un valor. Esta temperatura es el punto de ebullición del agua. Haga notar a los estudiantes que el programa da un resultado de 100 grados Celsius, que también es correcto. 5. Ejecute el programa por tercera vez y escriba una temperatura de 75 grados Fahrenheit. Haga notar a los estudiantes que el resultado mostrado es 23 grados Celsius. Esto es incorrecto, ya que 75 grados Fahrenheit son 23,8889 grados Celsius. Explique que, aparentemente, el programa está truncando el resultado a un entero. Cómo identificar el error en el programa C# estableciendo un punto de interrupción y usando la ventana Watch (Inspección) 1. Coloque un punto de interrupción justo después de que programa lee la temperatura Fahrenheit. 2. Ejecute el programa en modo de depuración seleccionando Start en el menú Debug o pulsando. Escriba 75 y pulse INTRO. El programa llega hasta el punto de interrupción y se detiene. 3. Abra la ventana Watch y añada las variables degreesFahrenheit y degreesCelsius a la lista de variables inspeccionadas. Explique que es posible supervisar los valores de variables en la ventana Watch.

Introducción a C#

26

4. Seleccione Step Over (Salto) en el menú Debug o pulse F10 para ejecutar el programa línea por línea a partir del punto de interrupción. En esto consiste el avance paso a paso. Se ejecuta la siguiente línea de código y el programa se detiene, lo que permite ver en la ventana Watch los cambios sufridos por las variables. Por ejemplo, el valor de degreesFahrenheit es ahora 75. Al saltar a la siguiente línea, la variable degreesCelsius cambia cuando se calcula un valor de 23.0. Ésta es la línea que contiene el error. El problema es que se realiza un cálculo entero sobre un dato entero antes de asignarlo a una variable de punto flotante. Así se acumulan errores de redondeo y se obtiene un resultado incorrecto. 5. Pulse F5 para finalizar la ejecución del programa. Cómo corregir el error en el programa C# y comprobar el resultado 1. Cambie una constante a un valor de punto flotante cambiando 32 a 32F, lo que obliga al compilador a efectuar un cálculo de punto flotante. 2. Vuelva a compilar y ejecutar el programa. 3. Seleccione Step Over en el menú Debug para ver los resultados del cambio. Verá que ahora la variable degreesCelsius tiene un valor de 23.8889 en la ventana Watch. 4. Pulse F10 para continuar ejecutando el programa paso a paso. 5. Seleccione Continue en el menú Debug para que el programa se ejecute hasta el final.

Introducción a C#

1

Práctica: Creación de un programa C# sencillo Objetivos Al final de esta práctica, usted será capaz de: • Crear un programa C#. • Compilar y ejecutar un programa C#. • Usar el Visual Studio Debugger. • Añadir tratamiento de excepciones a un programa C#. Los archivos solución de esta práctica se pueden encontrar en la carpeta Solution del fichero lab02.zip

Ejercicio 1 Creación de un programa C# sencillo En este ejercicio utilizará Visual Studio para escribir un programa C#. El programa le preguntará cómo se llama y luego le saludará por su nombre. Cómo crear una nueva aplicación C# de consola 1. Inicie Microsoft Visual Studio .NET. 2. En el menú File (Archivo), señale New (Nuevo) y pulse Project (Proyecto). 3. Pulse Visual C# Projects en el cuadro Project Types (Tipos de proyecto). 4. Pulse Console Application (Aplicación de consola) en el cuadro Templates (Plantillas). 5. Escriba Saludos en el cuadro Name (Nombre). 6. Escriba la ubicación deseada para el proyecto en el cuadro Location (Ubicación) y pulse OK. 7. Escriba un comentario adecuado para el resumen. 8. Cambie el nombre de la clase a Saludar. 9. Guarde el proyecto seleccionando Save All (Guardar todo) en el menú File. Cómo escribir instrucciones para preguntar y saludar al usuario 1. Inserte la siguiente línea en el método Main después de los comentarios TODO: string miNombre;

2. Escriba una instrucción que pregunte el nombre a los usuarios. 3. Escriba otra instrucción que lea la respuesta del usuario desde el teclado y la asigne a la cadena miNombre. 4. Añada una instrucción más que imprima “Hola, miNombre” en pantalla (donde miNombre es el nombre escrito por el usuario). 5. Una vez terminado, el método Main debe contener lo siguiente:

Introducción a C#

2 static void Main(string[ ] args) { string miNombre; Console.WriteLine("Por favor, escriba su nombre"); miNombre = Console.ReadLine( ); Console.WriteLine("Hola {0}", miNombre); }

6. Guarde el trabajo realizado. Cómo compilar y ejecutar el programa 1. En el menú Build, seleccione Build Solution (o pulse CTRL+SHIFT+B). 2. Corrija los posibles errores de compilación y vuelva a compilar si es necesario. 3. En el menú Debug, seleccione Start Without Debugging (o pulse CTRL+F5). 4. En la ventana de consola que se abrirá, escriba su nombre cuando se lo pida el programa y pulse INTRO. 5. Después de ver el saludo, pulse una tecla cuando aparezca el mensaje “Pulse cualquier tecla para continuar”.

Introducción a C#

3

Ejercicio 2 Compilación y ejecución del programa C# desde la línea de comandos En este ejercicio compilará y ejecutará su programa desde la línea de comandos. Cómo compilar y ejecutar la aplicación desde la línea de comandos 1. Desde el botón de Inicio de Windows, entre en Todos los programas y luego pulse Visual Studio .NET, seguido de Visual Studio .NET Tools y finalmente Visual Studio .NET Command Prompt. 2. Vaya a la carpeta Saludos, donde se encuentra el proyecto del apartado anterior. 3. Compile el programa con el siguiente comando: 4. csc /out:Saludo.exe Class1.cs 5. Ejecute el programa escribiendo: Saludo 6. Cierre la ventana Command (Comandos).

Introducción a C#

4

Ejercicio 3 Uso del depurador En este ejercicio utilizará el Visual Studio Debugger para ejecutar su programa paso a paso y examinar el valor de una variable. Para configurar un punto de interrupción e iniciar la depuración con Visual Studio 7. Inicie Visual Studio .NET si aún no se está ejecutando. 8. En el menú File, señale Open (Abrir) y pulse Project. 9. Abra el proyecto Saludos.sln en la carpeta Saludos del proyecto del apartado anterior. También se puede encontrar dentro del fichero lab02.zip. 10. Pulse en el margen derecho sobre la línea en que aparece por primera vez Console.WriteLine en la clase Saludar. En el margen aparecerá un punto de interrupción (u punto grande y rojo). 11. En el menú Debug, seleccione Start (o pulse F5). Al iniciarse la ejecución del programa, se abrirá una ventana de consola y luego el programa se detendrá en el punto de interrupción. Cómo inspeccionar el valor de una variable 12. En el menú Debug, pulse Windows, luego Watch y finalmente Watch 1. 13. En la ventana Watch, añada la variable miNombre a la lista de variables inspeccionadas. 14. La variable miNombre aparecerá en la ventana Watch con un valor de null. Cómo ejecutar el código paso a paso 1. En el menú Debug, seleccione Step Over (o pulse F10) para ejecutar la primera instrucción Console.WriteLine. 2. Pulse F10 para saltar a la siguiente línea que contiene la instrucción Console.ReadLine. 3. Vuelva a la ventana de consola y escriba su nombre, y a continuación pulse la tecla INTRO. Regrese a Visual Studio. Su nombre será el valor de la variable miNombre en la ventana Watch. 4. Pulse F10 para saltar a la siguiente línea que contiene la instrucción Console.WriteLine. 5. Ponga en primer plano la ventana de consola. Aparecerá el saludo. 6. Regrese a Visual Studio. En el menú Debug, seleccione Continue (o pulse F5) para ejecutar el programa hasta el final.

Introducción a C#

5

Ejercicio 4 Adición de tratamiento de excepciones a un programa C# En este ejercicio escribirá un programa que utiliza tratamiento de excepciones para capturar errores inesperados en tiempo de ejecución. El programa pide al usuario dos valores enteros, divide el primero por el segundo y muestra el resultado. Para crear un programa C# nuevo 1. Inicie Visual Studio .NET si aún no se está ejecutando. 2. En el menú File, señale New y pulse Project. 3. Pulse Visual C# Projects en el cuadro Project Types. 4. Pulse Console Application en el cuadro Templates. 5. Escriba Divisor en el cuadro Name. 6. Escriba la ubicación deseada para el proyecto en el cuadro Location (Ubicación) y pulse OK. 7. Escriba un comentario adecuado para el resumen. 8. Cambie el nombre de la clase a Dividir. 9. Guarde el proyecto seleccionando Save All en el menú File. Cómo escribir instrucciones para pedir dos enteros al usuario 1. En el método Main, escriba una instrucción que pida al usuario el primer entero. 2. Escriba otra instrucción que lea la respuesta del usuario desde el teclado y la asigne a una variable llamada temp de tipo string. 3. Añada la siguiente instrucción para convertir el valor de la cadena de temp en un entero y almacenar el resultado en i: int i = Int32.Parse(temp);

4. Añada al código instrucciones para: a. Pedir al usuario el segundo entero. b. Leer la respuesta del usuario desde el teclado y asignarla a temp. c. Convertir el valor de temp en un entero y almacenar el resultado en j. El código debería ser parecido al siguiente: Console.WriteLine("Escriba el primer entero"); string temp = Console.ReadLine( ); int i = Int32.Parse(temp); Console.WriteLine("Escriba el segundo entero"); temp = Console.ReadLine( ); int j = Int32.Parse(temp);

5. Guarde el trabajo realizado.

Introducción a C#

6

Cómo dividir el primer entero por el segundo y mostrar el resultado 1. Cree una nueva variable entera k que reciba el valor resultante de dividir i entre j, e insértelo al final del procedimiento anterior. El código debería ser como esto: int k = i / j;

2. Añada una instrucción para mostrar el valor de k. 3. Guarde el trabajo realizado. Cómo probar el programa 1. En el menú Debug, seleccione Start Without Debugging (o pulse CTRL+F5). 2. Escriba 10 como valor del primer entero y pulse INTRO. 3. Escriba 5 como valor del segundo entero y pulse INTRO. 4. Compruebe que el valor de k que aparece es 2. 5. Pulse CTRL+F5 para volver a ejecutar el programa. 6. Escriba 10 como valor del primer entero y pulse INTRO. 7. Escriba 0 como valor del segundo entero y pulse INTRO. 8. El programa provoca el lanzamiento de una excepción (división por cero). 9. Pulse No para que desaparezca el cuadro de diálogo de la depuración Justin-Time. Cómo añadir tratamiento de excepciones al programa 1. Ponga el código del método Main dentro de un bloque try, como se indica a continuación: try {

Console.WriteLine (...); ... int k = i / j; Console.WriteLine(...); }

2. Añada a Main una instrucción catch después del bloque try. La instrucción catch tiene que imprimir un mensaje corto, como se ve en este código: catch(Exception e) { Console.WriteLine("Excepción lanzada: {0}" , e); } ...

3. Guarde el trabajo realizado.

Introducción a C#

7

4. El método Main completo será similar al siguiente: public static void Main(string[ ] args) { try { Console.WriteLine ("Escriba el primer entero"); string temp = Console.ReadLine( ); int i = Int32.Parse(temp); Console.WriteLine ("Escriba el segundo entero"); temp = Console.ReadLine( ); int j = Int32.Parse(temp); int k = i / j; Console.WriteLine("El resultado de dividir {0} por {1} ¬es {2}", i, j, k); } catch(Exception e) { Console.WriteLine("Excepción lanzada: {0}", e); } }

Cómo probar el código para tratamiento de excepciones 1. Pulse CTRL+F5 para volver a ejecutar el programa. 2. Escriba 10 como valor del primer entero y pulse INTRO. 3. Escriba 0 como valor del segundo entero y pulse INTRO. El programa sigue provocando el lanzamiento de una excepción (división por cero), pero esta vez el error es capturado y aparece su mensaje.

Uso de variables de tipo valor

1

Práctica : Creación y uso de tipos Objetivos Al final de esta práctica, usted será capaz de: • Crear nuevos tipos de datos. • Definir y utilizar variables.

Requisitos previos Antes de realizar la práctica debe estar familiarizado con los siguientes temas: • El sistema de tipos comunes (Common Type System, CTS). • Variables de tipo valor en C#.

Sumario En el Ejercicio 1 escribirá un programa que crea un tipo enum simple y a continuación asigna e imprime los valores utilizando la instrucción Console.WriteLine. En el Ejercicio 2 escribirá un programa que utiliza en una struct el tipo enum declarado en el Ejercicio 1. Si le queda tiempo, también añadirá funcionalidad de entrada/salida al programa escrito en el Ejercicio 2.

Archivos de inicio y solución Existen archivos de inicio y solución para esta práctica. Los archivos de inicio están en la carpeta Starter, mientras que los archivos de solución se encentran en Solution. Estas dos carpetas se encuentran dentro del archivo lab03.zip

Uso de variables de tipo valor

2

Ejercicio 1 Creación de un tipo enum En este ejercicio creará un tipo enumerado para representar distintos tipos de cuentas bancarias (cuentas corrientes y de ahorro). Utilizará este tipo enum para crear dos variables a las que asignará los valores Corriente y Ahorro. Finalmente empleará la función System.Console.WriteLine para imprimir los valores de las variables. Cómo crear un tipo enum 1. Abra el proyecto BankAccount.sln en la carpeta Starter\BankAccount dentro del fichero lab03.zip. 2. Abra el archivo Enum.cs y añada un enum llamado TipoCuenta antes de la definición de clase: public enum TipoCuenta { Corriente, Ahorro }

Este enum contendrá los tipos Corriente y Ahorro. 3. Declare en Main dos variables de tipo TipoCuenta: TipoCuenta goldCuenta; TipoCuenta platinumCuenta;

4. Asigne a la primera variable el valor Corriente y a la segunda el valor Ahorro: goldCuenta = TipoCuenta.Corriente; platinumCuenta = TipoCuenta.Ahorro;

5. Añada dos instrucciones Console.WriteLine que impriman el valor de cada variable: Console.WriteLine("El tipo de cuenta del cliente es {0}" ¬, goldCuenta); Console.WriteLine("El tipo de cuenta del cliente es {0}" ¬, platinumCuenta);

6. Compile y ejecute el programa.

Uso de variables de tipo valor

3

Ejercicio 2 Creación y uso de un tipo struct En este ejercicio definirá una struct que se puede usar para representar una cuenta bancaria. Empleará variables para el número de cuenta (long), el saldo de la cuenta (decimal) y el tipo de cuenta (el enum creado en el Ejercicio 1). Creará una variable de tipo struct, le asignará algunos datos de ejemplo e imprimirá el resultado. Cómo crear un tipo struct 1. Abra el proyecto StructType.sln en la carpeta Starter\StructType dentro del fichero lab03.zip. 2. Abra el archivo Struct.cs y añada una public struct llamada CuentaBancaria que contenga los siguientes campos. Tipo

Variable

public long

cuentaNum

public decimal

cuentaSaldo

public TipoCuenta

cuentaTipo

3. Declare en Main una variable goldCuenta de tipo TipoCuenta. CuentaBancaria goldCuenta;

4. Asigne valores a los campos cuentaTipo, cuentaSaldo y cuentaNum de la variable goldCuenta. goldCuenta.cuentaTipo = TipoCuenta.Corriente; goldCuenta.CuentaSaldo = (decimal)3200.00; goldCuenta.cuentaNum = 123;

5. Añada instrucciones Console.WriteLine que impriman el valor de cada elemento en la variable struct. Console.WriteLine("Número de cuenta {0}", goldCuenta.cuentaNum); Console.WriteLine("Tipo de cuenta {0}", goldCuenta.cuentaTipo); Console.WriteLine("Saldo de la cuenta ${0}", goldCuenta.CuentaSaldo);

6. Compile y ejecute el programa.

Uso de variables de tipo valor

4

Si el tiempo lo permite Adición de funcionalidad de entrada/salida En este ejercicio tendrá que modificar el código escrito en el Ejercicio 2. En lugar de usar el número de cuenta 123, pedirá que sea el usuario quien lo introduzca el número y usará ese número para imprimir el resumen de la cuenta. Cómo añadir funcionalidad de entrada/salida 1. Abra el proyecto StructType.sln en la carpeta Starter\Optional dentro del fichero lab03.zip. 2. Abra el archivo Struct.cs y cambie la línea siguiente: goldCuenta.cuentaNum = 123; //borre esta línea y escriba el siguiente código

por una instrucción Console.Write que pregunte el número de cuenta al usuario: Console.Write("Introduzca el número de cuenta: ");

3. Utilice una instrucción Console.ReadLine para leer el número de cuenta y asigne este valor a goldCuenta.cuentaNum. goldCuenta.cuentaNum = long.Parse(Console.ReadLine());

Nota Hay que utilizar el método long.Parse para convertir la cadena leída por la instrucción Console.ReadLine en un valor decimal antes de asignarlo a goldCuenta.cuentaNum. 4. Compile y ejecute el programa. Escriba un número de cuenta cuando se lo pida el programa.

Uso de variables de tipo valor

Contenido Descripción general

1

Sistema de tipos comunes (CTS)

2

Nombres de variables Uso de tipos de datos predefinidos

8 12

Creación de tipos de datos definidos por el usuario 21 Conversión de tipos de datos

25

Uso de variables de tipo valor

Notas para el instructor Este módulo ofrece a los estudiantes una introducción al sistema de tipos comunes (Common Type System, CTS). Los estudiantes conocerán las variables de tipo valor y también crearán y utilizarán tipos de datos definidos por el usuario. Al final de este módulo, los estudiantes serán capaces de: Describir los tipos de variables que se pueden emplear en aplicaciones C#. Nombrar variables según las convenciones de nomenclatura estándar de C#. Declarar variables utilizando tipos de datos predefinidos. Asignar valores a variables. Convertir variables existentes de un tipo de dato a otro. Crear y utilizar sus propios tipos de datos.

i

Uso de variables de tipo valor

1

‹ Descripción general Objetivo del tema

Ofrecer una introducción a los contenidos y objetivos del módulo.

Explicación previa

En este módulo aprenderá a usar variables de tipo valor en C#.

Recomendación al profesor

Si desea más información sobre los temas tratados en este módulo, consulte la documentación de la biblioteca de clases de .NET Framework y la especificación del lenguaje C# en los documentos de ayuda de Visual Studio .NET.

„

Sistema de tipos comunes (CTS)

„

Nombres de variables

„

Uso de tipos de datos predefinidos

„

Creación de tipos de datos definidos por el usuario

„

Conversión de tipos de datos

Todas las aplicaciones manipulan datos de alguna manera. Como desarrollador de C#, necesitará aprender a almacenar y procesar datos en sus aplicaciones. Cada vez que una aplicación tiene que almacenar datos temporalmente para usarlos durante la ejecución, esos datos se almacenan en una variable. Antes de utilizar una variable hay que definirla, y cuando se define una variable lo que se hace en realidad es reservar espacio de almacenamiento para ella, identificando su tipo de datos y dándole un nombre. Una vez definida, ya es posible asignar valores a esa variable. En este módulo aprenderá a usar variables de tipo valor en C#. Estudiará cómo especificar el tipo de datos de las variables, cómo nombrar variables según las convenciones de nomenclatura estándar y cómo asignar valores a variables. Aprenderá también a convertir variables existentes de un tipo de dato a otro y a crear sus propias variables. Al final de este módulo, los estudiantes serán capaces de: Describir los tipos de variables que puede emplear en aplicaciones C#. Nombrar variables según las convenciones de nomenclatura estándar de C#. Declarar una variable utilizando tipos de datos predefinidos. Asignar valores a variables. Convertir variables existentes de un tipo de dato a otro. Crear y utilizar sus propios tipos de datos.

Uso de variables de tipo valor

2

‹ Sistema de tipos comunes (CTS) Objetivo del tema

Ofrecer una introducción a los temas tratados en esta sección.

Explicación previa

En esta sección conocerá algunos de los tipos de datos de C#, así como el sistema de tipos comunes.

„

Aspectos generales del CTS

„

Comparación de tipos de valor y de referencia

„

Comparación de tipos de valor predefinidos y definidos por el usuario

„

Tipos simples

Cada variable tiene un tipo de datos que determina los valores que se pueden almacenar en ella. C# es un lenguaje de especificaciones seguras (type-safe), lo que significa que el compilador de C# garantiza que los valores almacenados en variables son siempre del tipo adecuado. El runtime de lenguaje común incluye un sistema de tipos comunes (Common Type System, CTS) que define un conjunto de tipos de datos predefinidos que se pueden utilizar para definir variables. Al final de esta lección, usted será capaz de: Explicar cómo funciona el CTS. Elegir los tipos de datos más adecuados para sus variables.

Uso de variables de tipo valor

3

Aspectos generales del CTS Objetivo del tema Describir el CTS.

Explicación previa

El CTS es compatible con estilos de programación procedurales y orientados a objetos. Además, el CTS admite tipos de valor y de referencia.

„

El CTS admite tanto tipos de valor como de referencia

Tipo Tipo

Tipo Tipo de de valor valor

Tipo Tipo de de referencia referencia

Al definir una variable es necesario elegir el tipo de datos correcto para ella. El tipo de datos determina los valores permitidos para esa variable, los cuales a su vez determinan las operaciones que se pueden efectuar sobre ella.

CTS El CTS es una parte integral del runtime de lenguaje común y es compartido por los compiladores, las herramientas y el propio runtime. Es el modelo que define las reglas que sigue el runtime a la hora de declarar, usar y gestionar tipos. El CTS establece un marco que permite la integración entre lenguajes, la seguridad de tipos y la ejecución de código con altas prestaciones. En este módulo estudiará dos tipos de variables: Variables de tipos de valor. Variables de tipos de referencia.

Uso de variables de tipo valor

4

Comparación de tipos de valor y de referencia Objetivo del tema

Describir las diferencias entre tipos de valor y de referencia.

Explicación previa

Este módulo se concentra en los tipos de valor. Entre los tipos de valor y los tipos de referencia existen considerables diferencias que los desarrolladores deben comprender.

„

Tipos de valor: „

Contienen sus datos directamente

„

„

„

Tipos de referencia: „

Cada una tiene su propia copia de datos

Almacenan referencias a sus datos (conocidos como objetos)

„

Las operaciones sobre una no afectan a otra

Dos variables de referencia pueden apuntar al mismo objeto

„

Las operaciones sobre una pueden afectar a otra

Tipos de valor Las variables de tipos de valor contienen sus datos directamente. Cada una de ellas tiene su propia copia de los datos, por lo que las operaciones efectuadas sobre una variable no pueden afectar a otra.

Tipos de referencia Las variables de tipos de referencia contienen referencias a sus datos. Los datos para estas variables se almacenan en un objeto. Es posible que dos variables de tipos de referencia apunten al mismo objeto, por lo que las operaciones efectuadas sobre una variable pueden afectar al objeto apuntado por otra variable de referencia. Nota Todos los tipos de datos básicos están definidos en el espacio de nombres System y, en último término, se derivan de System.Object. Los tipos de valor se derivan de System.ValueType.

Uso de variables de tipo valor

5

Comparación de tipos de valor predefinidos y definidos por el usuario Objetivo del tema

Comparar tipos de valor predefinidos y definidos por el usuario.

Tipos de valor

Explicación previa

Los tipos de valor incluyen tipos predefinidos y definidos por el usuario. En este tema veremos algunos ejemplos de cada tipo.

Predefinido „

Ejemplos de tipos de valor predefinidos:

Del usuario „

Ejemplos de tipos de valor definidos por el usuario:

„

int

„

enum

„

float

„

struct

Los tipos de valor incluyen tipos de datos predefinidos y definidos por el usuario. La diferencia entre los dos tipos en C# es mínima, puesto que los tipos definidos por el usuario se pueden usar de la misma forma que los predefinidos. La única diferencia real entre tipos de datos predefinidos y tipos de datos definidos por el usuario es que para los primeros se pueden escribir valores literales. Todos los tipos de valor contienen datos directamente y no pueden ser null. En este módulo aprenderá a crear tipos de datos definidos por el usuario, como tipos de enumeraciones y tipos de estructuras.

Uso de variables de tipo valor

6

Tipos simples Objetivo del tema

Describir los tipos simples.

Explicación previa

C# ofrece un conjunto de tipos de estructura predefinidos llamados tipos simples.

„

Se identifican mediante palabras reservadas z

int // Palabra reservada

-oz

System.Int32

Los tipos de valor predefinidos también reciben el nombre de tipos de datos básicos o tipos simples. Los tipos simples se identifican por medio de palabras reservadas que son alias para tipos de estructura predefinidos. Un tipo simple y el tipo de estructura correspondiente son completamente indistinguibles. En el código se puede utilizar la palabra reservada o el tipo de estructura. Los ejemplos que siguen ilustran ambas posibilidades: byte // Palabra reservada

–O– System.Byte // tipo de estructura

int // Palabra reservada

–O– System.Int32 // tipo de estructura

Para más información sobre los tamaños e intervalos de tipos de valor predefinidos, busque “tipos de valor” en los documentos de ayuda de Microsoft® Visual Studio® .NET.

Uso de variables de tipo valor

7

La siguiente tabla muestra las palabras reservadas y el tipo de estructura equivalente. Palabras reservadas

Alias para tipo de estructura

sbyte byte short ushort int uint long ulong char float double bool decimal

System.SByte System.Byte System.Int16 System.UInt16 System.Int32 System.UInt32 System.Int64 System.UInt64 System.Char System.Single System.Double System.Boolean System.Decimal

Uso de variables de tipo valor

8

‹ Nombres de variables Objetivo del tema

Ofrecer una introducción a los temas tratados en esta sección.

Explicación previa

En esta sección aprenderá a asignar y utilizar nombres de variables significativos en una aplicación C#.

„

Reglas y recomendaciones para nombrar variables

„

Palabras clave de C#

„

Problema: ¿Puede encontrar nombres de variables no permitidos?

Para usar una variable hay que elegir primero un nombre apropiado y significativo para ella. Cada variable tiene un nombre al que se conoce también por identificador de variable. En el momento de nombrar variables se deben seguir las recomendaciones de nomenclatura estándar recomendadas para C#. También hay que conocer las palabras reservadas de C# que no se pueden utilizar para nombres de variables. Al final de esta lección, usted será capaz de: Identificar las palabras reservadas de C#. Nombrar sus variables según las convenciones de nomenclatura estándar de C#.

Uso de variables de tipo valor

9

Reglas y recomendaciones para nombrar variables Objetivo del tema

Aprender las reglas para nombrar variables.

„

Explicación previa

Reglas z

Hay reglas y recomendaciones que se deben seguir al elegir el nombre de una variable.

„

Recomendaciones z

z

z z

Recomendación al profesor

Insista en que C# distingue mayúsculas y minúsculas, como C y C++.

Use letras, el signo de subrayado y dígitos Evite poner todas las letras en mayúsculas Evite empezar con un signo de subrayado Evite el uso de abreviaturas Use PascalCasing para nombres con varias palabras

9 8

Respuesta42 Respuesta42 42Respuesta 42Respuesta

diferente diferente Diferente Diferente

9 9

Mal Mal _regular _regular Bien Bien

8 8 9

Msj Msj Mensaje Mensaje

8 9

Al nombrar variables hay que respetar las siguientes reglas y recomendaciones.

Reglas Las siguientes son reglas de nomenclatura para variables de C#: Comience todos los nombres de variables con una letra o un signo de subrayado. Después del primer carácter, use letras, dígitos o el signo de subrayado. No utilice palabras reservadas. Si usa un nombre de variable no permitido, se producirá un error en tiempo de compilación.

Recomendación al profesor

Anime a los estudiantes a seguir estas recomendaciones. Explíqueles que el uso de convenciones de nomenclatura estándar les ayudará a desarrollar código coherente y de sencillo mantenimiento.

Recomendaciones Es aconsejable seguir estas recomendaciones a la hora de nombrar variables: Evite poner todas las letras en mayúsculas. Evite empezar con un signo de subrayado. Evite el uso de abreviaturas. Use PascalCasing para nombres con varias palabras.

Uso de variables de tipo valor

10

Convención de nomenclatura PascalCasing La convención de nomenclatura PascalCasing consiste en poner en mayúscula el primer carácter de todas las palabras. Utilice PascalCasing para clases, métodos, propiedades, enumeraciones, interfaces, campos constantes y de sólo lectura, espacios de nombres y propiedades, como se muestra en el siguiente ejemplo: void InicializarDatos( );

Convención de nomenclatura camelCasing La convención de nomenclatura camelCasing consiste en poner en mayúscula el primer carácter de todas las palabras excepto la primera. Utilice camelCasing para variables que definan campos y parámetros, como se muestra en el siguiente ejemplo: int bucleNumMax;

Para más información sobre convenciones de nomenclatura, busque “instrucciones de nomenclatura” en los documentos de ayuda del kit de desarrollo de software (SDK) de .NET.

Uso de variables de tipo valor

11

Palabras clave de C# Objetivo del tema

Dar una lista de algunas de las palabras reservadas más comunes.

„

Las palabras clave son identificadores reservados

Explicación previa

Las palabras clave son identificadores reservados para el lenguaje y no se pueden utilizar como nombres de variables.

abstract, abstract, base, base, bool, bool, default, default, if, if, finally finally

„

No utilice palabras clave como nombres de variables z

„

Produce errores en tiempo de compilación

Procure no usar palabras clave cambiando mayúsculas y minúsculas int int INT; INT; // // Mal Mal estilo estilo

Las palabras clave están reservadas, lo que significa que no se puede utilizar ninguna de ellas como nombre de variable en C#. El uso de una palabra clave como nombre de variable produce un error en tiempo de compilación.

Palabras clave en C# A continuación se ofrece una lista de palabras clave en C#. Recuerde que ninguna de estas palabras se puede emplear como nombre de variable. abstract byte class delegate event fixed if internal new override readonly short struct try unsafe volatile

as case const do explicit float implicit is null params ref sizeof switch typeof ushort while

base catch continue double extern for in lock object private return stackalloc this uint using

bool char decimal else false foreach int long operator protected sbyte static throw ulong virtual

break checked default enum finally goto interface namespace out public sealed string true unchecked void

Uso de variables de tipo valor

12

‹ Uso de tipos de datos predefinidos Objetivo del tema

Ofrecer una introducción a los temas tratados en esta sección.

Explicación previa

Es importante comprender qué tipos de valor contienen datos directamente y no pueden contener valores null.

„

Declaración de variables locales

„

Asignación de valores a variables

„

Asignación compuesta

„

Operadores comunes

„

Incremento y decremento

„

Precedencia de operadores

Para crear una variable hay que elegir un nombre, declarar la variable y asignarle un valor, salvo si C# ya le ha asignado un valor automáticamente. Al final de esta lección, usted será capaz de: Crear una variable local utilizando tipos de datos predefinidos. Usar operadores para asignar valores a variables. Definir constantes y variables de sólo lectura.

Uso de variables de tipo valor

13

Declaración de variables locales Objetivo del tema

Explicar cómo declarar variables locales.

Explicación previa

En C# es muy importante saber usar variables locales.

„

Se suelen declarar por tipo de dato y nombre de variable:

int int objetoCuenta; objetoCuenta; „

Es posible declarar múltiples variables en una declaración:

int int objetoCuenta, objetoCuenta, empleadoNúmero; empleadoNúmero; --o-int int objetoCuenta, objetoCuenta, empleadoNúmero; empleadoNúmero;

Recomendación al profesor

Es posible que los estudiantes no estén familiarizados con métodos, propiedades e indizadores. Ésta es la primera vez en el curso en que aparecen estos términos. Explique que un método es como una función. Mencione que estos temas se tratarán en otros módulos del curso.

Las variables declaradas en métodos, propiedades o indizadores se llaman variables locales. Una variable local se declara normalmente especificando el tipo de dato seguido por el nombre de la variable, como se ve en el siguiente ejemplo: int objetoCuenta;

Es posible declarar múltiples variables en una sola declaración separándolas con una coma, como en este ejemplo: int objetoCuenta, empleadoNumero;

En C# no se pueden usar variables sin inicializar. Este código produciría un error en tiempo de compilación porque no se ha asignado un valor inicial a la variable bucleCuenta: int bucleCuenta; Console.WriteLine ("{0}", bucleCuenta);

Uso de variables de tipo valor

14

Asignación de valores a variables Objetivo del tema

Aprender a asignar valores a variables.

Explicación previa

Antes de poder usar variables sin inicializar hay que asignarles valores. En este tema veremos algunas instrucciones sencillas de asignación.

„

Asignar valores a variables ya declaradas:

int int empleadoNumero; empleadoNumero; empleadoNumero empleadoNumero == 23; 23; „

Inicializar una variable cuando se declara:

int int empleadoNumero empleadoNumero == 23; 23;

„

También es posible inicializar valores de caracteres:

char char inicialNombre inicialNombre == 'J'; 'J';

Para asignar un nuevo valor a una variable se utilizan operadores de asignación. En el caso de una variable ya declarada se usa el operador de asignación (=), como se ve en el siguiente ejemplo: int empleadoNumero; empleadoNumero = 23;

También es posible inicializar una variable al declararla, como en este ejemplo: int empleadoNumero = 23;

Se puede usar el operador de asignación para asignar valores a variables de tipo carácter, como en este caso: char inicialNombre = 'J';

Uso de variables de tipo valor

15

Asignación compuesta Objetivo del tema

Describir la unión de operadores para asignación compuesta.

Explicación previa

Muchas veces se necesita sumar o restar un valor a una variable en lugar de asignarle un valor totalmente nuevo.

„

Es muy habitual sumar un valor a una variable

itemCount itemCount == itemCount itemCount ++ 40; 40; „

Se puede usar una expresión más práctica

itemCount itemCount += += 40; 40; „

Esta abreviatura es válida para todos los operadores aritméticos:

itemCount itemCount -= -= 24; 24;

Recomendación al profesor

Los programadores de Microsoft Visual Basic® no estarán familiarizados con la asignación compuesta.

Es muy habitual sumar u valor a una variable El siguiente código declara una variable int llamada objetoCuenta, le asigna el valor 2 y posteriormente la incrementa en 40: int objetoCuenta; objetoCuenta = 2; objetoCuenta = objetoCuenta + 40;

Se puede usar una expresión más práctica Este código funciona para incrementar una variable, pero es un poco farragoso porque hay que escribir dos veces el identificador que se desea incrementar. Esto no suele ser un problema para identificadores simples, salvo que haya muchos identificadores con nombres similares. No obstante, es posible utilizar expresiones tan complejas como se quiera para designar el valor que se incrementa, como en este ejemplo: items[(index + 1) % 32] = items[(index + 1) % 32] + 40;

En estos casos es muy fácil cometer algún pequeño error al escribir dos veces la expresión. Afortunadamente, existe una forma abreviada que evita la duplicación:

Uso de variables de tipo valor

16 objetoCuenta += 40; items[(index + 1) % 32] += 40;

Esta abreviatura es válida para todos los operadores aritméticos var var var var var

+= -= *= /= %=

expresion; expresion; expresion; expresion; expresion;

// // // // //

var var var var var

= = = = =

var var var var var

+ expresión - expresión * expresión / expresión % expresión

Uso de variables de tipo valor

17

Operadores comunes Objetivo del tema

Describir operadores comunes que se pueden emplear en C#.

Operadores Operadores comunes comunes

Explicación previa

Los operadores de asignación se usan para asignar valores a variables, descriptores de acceso a propiedades y descriptotes de acceso a índices. Aquí veremos algunos de los operadores comunes que se pueden usar para asignar un valor a una variable.

Ejemplo



Operadores de igualdad == !=



Operadores relacionales < > = is



Operadores condicionales && || ?:



Operador de incremento ++



Operador de decremento - -



Operadores aritméticos



Operadores de asignación = *= /= %= += -= = &= ^= |=

+ - * / %

Las expresiones están formadas por operandos y operadores. Los operadores de una expresión indican las operaciones que se aplican a los operandos. Algunos ejemplos de operadores son el operador de concatenación y suma (+), el operador de resta (-), el operador de multiplicación (*) y el operador de división (/). Literales, campos, variables locales y expresiones son ejemplos de operandos.

Operadores comunes La siguiente tabla describe algunos de los operadores más comunes que se utilizan en C#. Tipo

Descripción

Operadores de asignación

Asignan valores a variables usando una asignación simple. Para ello es necesario que el valor en el lado derecho de la asignación sea de un tipo que se pueda convertir implícitamente al tipo de la variable en el lado izquierdo de la asignación.

Operadores lógicos relacionales

Comparan dos valores.

Operadores lógicos

Realizan operaciones bit a bit sobre valores.

Operador condicional

Selecciona entre dos expresiones, dependiendo de una expresión booleana.

Operador de incremento

Aumenta en uno el valor de una variable.

Operador de decremento

Reduce en uno el valor de una variable.

Operadores aritméticos

Realizan operaciones aritméticas estándar.

Para más información sobre los operadores de C#, busque “expresiones” en los documentos de ayuda de Visual Studio .NET sobre el lenguaje C#.

Uso de variables de tipo valor

18

Incremento y decremento Objetivo del tema

Describir los operadores de incremento y decremento y, en particular, explicar la diferencia entre las versiones de prefijo y sufijo.

„

objetoCuenta objetoCuenta += += 1; 1; objetoCuenta objetoCuenta -= -= 1; 1;

Explicación previa

Muchas veces (cuando se cuenta algo, por ejemplo) se necesita sumar o restar uno a una variable.

Es muy habitual cambiar un valor en una unidad

„

Se puede usar una expresión más práctica objetoCuenta++; objetoCuenta++; objetoCuenta--; objetoCuenta--;

„

Existen dos formas de esta abreviatura ++objetoCuenta; ++objetoCuenta; --objetoCuenta; --objetoCuenta;

Es muy habitual cambiar un valor en una unidad A menudo hay que escribir instrucciones que incrementan o decrementan valores en una unidad. Se podría hacer así, por ejemplo: objetoCuenta = objetoCuenta + 1; objetoCuenta = objetoCuenta – 1;

Pero también se puede usar una expresión más práctica, como acabamos de ver: objetoCuenta += 1; objetoCuenta -= 1;

Expresión práctica Los incrementos y decrementos unitarios de un valor son tan comunes que existe una expresión aún más abreviada: objetoCuenta++; // objetoCuenta += 1; objetoCuenta--; // objetoCuenta -= 1;

El operador ++ recibe el nombre de operador de incremento, mientras que -- es el operador de decremento. Se puede pensar en ++ como un operador que cambia un valor por su posterior y en -- como un operador que cambia un valor por su anterior. La abreviatura es, también en este caso, la forma preferida por los programadores de C# para incrementar o decrementar un valor en una unidad. Nota: ¡C++ se llamó C++ porque era el sucesor de C!

Uso de variables de tipo valor

19

Existen dos formas de esta abreviatura Los operadores ++ y -- se pueden usar de dos maneras. 1. Se puede colocar el símbolo del operador antes del identificador, como en los siguientes ejemplos. A esto se le llama notación de prefijo. ++objetoCuenta; --objetoCuenta;

2. Se puede colocar el símbolo del operador después del identificador, como en los siguientes ejemplos. A esto se le llama notación de sufijo. objetoCuenta++; objetoCuenta--;

En ambos casos se incrementa (para ++) o decrementa (para --) objetoCuenta en una unidad. Pero entonces, ¿por qué hay dos notaciones? Para responder a esta pregunta es necesario saber más sobre la asignación: Una característica importante de C# es que la asignación es un operador. Esto quiere decir que, además de asignar un valor a una variable, una expresión de asignación tiene en sí misma un valor, o resultado, que es el valor de la variable después de que se realice la asignación. En la mayor parte de las instrucciones se descarta el valor de la expresión de asignación, pero es posible usarlo en una expresión mayor, como en el siguiente ejemplo: int objetoCuenta = 0; Console.WriteLine(objetoCuenta = 2); // Imprime 2 Console.WriteLine(objetoCuenta = objetoCuenta + 40); // Imprime 42

Una asignación compuesta también es una asignación. Esto significa que una expresión de asignación compuesta, además de asignar un valor a una variable, tiene también un valor o resultado. También en este caso se descarta el valor de la expresión de asignación compuesta en la mayor parte de las instrucciones, pero es posible usarlo en una expresión mayor, como en el siguiente ejemplo: int objetoCuenta = 0; Console.WriteLine(objetoCuenta += 2); // Imprime 2 Console.WriteLine(objetoCuenta -= 2); // Imprime 0

El incremento y el decremento también son asignaciones. Esto significa, por ejemplo, que una expresión de incremento, además de incrementar una variable en uno, tiene también un valor o resultado. También en este caso se descarta el valor de la expresión de incremento en la mayor parte de las instrucciones, pero es posible usarlo en una expresión mayor, como en el siguiente ejemplo: int objetoCuenta = 42; int prefijoValor = ++objetoCuenta; // prefijoValor == 43 int sufijoValor = objetoCuenta++; // sufijoValor = 43

El valor de la expresión de incremento varía dependiendo de que se use la versión de prefijo o de sufijo. objetoCuenta se incrementa en los dos casos. La diferencia no está ahí, sino en el valor de la expresión de incremento. El valor de la expresión de incremento/decremento como prefijo es el valor de la variable después de realizar el incremento/decremento, mientras que el valor de un incremento/decremento como sufijo es el valor de la variable antes del incremento/decremento.

Uso de variables de tipo valor

20

Precedencia de operadores Objetivo del tema

Explicar la precedencia de operadores.

Explicación previa

Para entender cómo funcionan los programas en C#, es preciso conocer el orden en que C# evalúa los operadores empleados.

Recomendación al profesor

Puede ser conveniente repasar los distintos tipos de operadores. Operadores monarios. Los operadores monarios se aplican a un operando y usan notación de prefijo (como --x) o de sufijo (como x++). Operadores binarios. Los operadores monarios se aplican a dos operandos y usan notación de prefijo (como x + y). El operador ternario. Existe sólo un operador ternario (?:). El operador ternario se aplica a tres operandos y usan notación de infijo (como c? x: y).

„

Precedencia y asociatividad de operadores z

z

Todos los operadores binarios, salvo los de asignación, son asociativos por la izquierda Los operadores de asignación y el operador condicional son asociativos por la derecha

Precedencia de operadores Si una expresión contiene varios operadores, la precedencia de estos controla el orden en que se evalúa cada uno de ellos. Por ejemplo, la expresión x + y * z se evalúa como x + (y * z) porque el operador de multiplicación tiene una precedencia mayor que el de suma. Una expresión aditiva, por ejemplo, consta de una secuencia de expresiones multiplicativas separadas por operadores + o -, por lo que los operadores + y – tienen una precedencia menor que los operadores *, /, y %.

Asociatividad Si un operando está entre dos operadores con la misma precedencia, la asociatividad de los operadores controla el orden en que se efectúan las operaciones. Por ejemplo, x + y + z se evalúa como (x + y) + z. Esto tiene especial importancia para operadores de asignación. Por ejemplo, x = y = z se evalúa como x = (y = z). Todos los operadores binarios, salvo los de asignación, son asociativos por la izquierda, lo que quiere decir que las operaciones se realizan de izquierda a derecha. Los operadores de asignación y el operador condicional (?:)son asociativos por la derecha, lo que quiere decir que las operaciones se realizan de derecha a izquierda. Es posible controlar la precedencia y la asociatividad utilizando paréntesis. Por ejemplo, x + y * z multiplica primero y por z y luego suma el resultado a x, pero (x + y) * z suma primero x más y, y luego multiplica el resultado por z.

Uso de variables de tipo valor

21

‹ Creación de tipos de datos definidos por el usuario Objetivo del tema

Ofrecer una introducción a los temas tratados en esta sección.

Explicación previa

En esta sección aprenderá a crear tipos de datos enum y struct.

„

Enumeraciones

„

Estructuras

En las aplicaciones es necesario saber cómo crear tipos de datos de enumeración (enum) y estructura (struct) definidos por el usuario. Al final de esta lección, usted será capaz de: Crear tipos de datos enum definidos por el usuario. Crear tipos de datos struct definidos por el usuario.

Uso de variables de tipo valor

22

Enumeraciones Objetivo del tema

Explicar cómo se crea una variable del tipo enum en C#.

Explicación previa

Una enumeración crea un conjunto único de valores constantes relacionados.

„

Definición de una enumeración

enum enum Color Color {{ Rojo, Rojo, Verde, Verde, Azul Azul }} „

Uso de una enumeración

Color Color colorPaleta colorPaleta == Color.Rojo; Color.Rojo; „

Visualización de una variable de enumeración

Console.WriteLine(“{0}”, Console.WriteLine(“{0}”, colorPaletta); colorPaletta); // // Muestra Muestra Rojo Rojo

Los enumeradores son útiles cuando una variable sólo puede tener un conjunto de valores concreto.

Definición de enumeraciones Para declarar una enumeración se usa la palabra clave enum seguida de un nombre de variable enum y los valores iniciales. Por ejemplo, esta enumeración define tres constantes enteras, llamadas valores del enumerador. enum Color { Rojo, Verde, Azul }

Por defecto, los valores de enumeradores empiezan en 0. En el ejemplo anterior, Rojo tiene el valor 0, Verde tiene el valor 1 y Azul tiene el valor 2. Es posible inicializar una enumeración especificando literales enteros.

Uso de variables de tipo valor

23

Uso de una enumeración Se puede declarar una variable colorPaleta de tipo Color empleando la siguiente sintaxis: Color colorPaleta; // Declara la variable colorPaleta = Color.Rojo; // Asigna el valor

-OcolorPaleta = (Color)0;

// Tipo int a Color

Visualización de un valor de enumeración Para ver un valor de enumeración en un formato legible se puede usar la siguiente instrucción: Console.WriteLine("{0}", colorPaleta);

Uso de variables de tipo valor

24

Estructuras Objetivo del tema

Explicar cómo se crean estructuras definidas por el usuario (structs) en C#.

Explicación previa

Una estructura es una agrupación de tipos arbitrarios.

„

Definición de una estructura

public public struct struct Empleado Empleado {{ public public string string pilaNombre; pilaNombre; public int public int age; age; }}

„

Uso de una estructura

Employee Employee empresaEmpleado; empresaEmpleado; empresaEmpleado.pilaNombre empresaEmpleado.pilaNombre == "Juan"; "Juan"; empresaEmpleado.age empresaEmpleado.age == 23; 23;

Las estructuras se pueden emplear para crear objetos que se comportan como tipos de valor predefinidos. Las estructuras se almacenan en línea y no se asignan por montones, por lo que la necesidad de eliminar elementos no utilizados en el sistema es menor que en el caso de las clases. Todos los tipos de datos simples, como int, float y double, son estructuras predefinidas en .NET Framework.

Definición de una estructura Recomendación al profesor

Nota: Las estructuras no permiten la herencia. Presente un ejemplo sencillo de estructura, como una estructura de Punto. Algunos ejemplos de estructura son punto, rectángulo y número complejo.

Se puede utilizar una estructura para agrupar varios tipos arbitrarios, como muestra el siguiente ejemplo: public struct Empleado { public string pilaNombre; public int edad; }

Este código define un nuevo tipo, llamado Empleado, que consta de dos elementos: el nombre de pila y la edad.

Uso de una estructura Para acceder a los elementos de una estructura se puede emplear la siguiente sintaxis: Empleado empresaEmpleado; empresaEmpleado.pilaNombre = empresaEmpleado.edad = 23;

// Declara la variable "Juan"; // Asigna el valor

Uso de variables de tipo valor

25

‹ Conversión de tipos de datos Objetivo del tema

Ofrecer una introducción a los temas tratados en esta sección.

Explicación previa

En C# hay dos tipos de conversión de datos: implícita y explícita.

„

Conversión implícita de tipos de datos

„

Conversión explícita de tipos de datos

En C# hay dos tipos de conversión: Conversión implícita de tipos de datos. Conversión explícita de tipos de datos. Al final de esta lección, usted será capaz de: Realizar una conversión implícita de datos. Realizar una conversión explícita de datos.

Uso de variables de tipo valor

26

Conversión implícita de tipos de datos Objetivo del tema

Explicar como hacer una conversión implícita de tipos de datos.

Explicación previa

La conversión implícita no puede fallar para tipos de datos predefinidos.

„

Conversión de int a long

using using System; System; class class Test Test {{ static static void void Main( Main( )) {{ int int intValor intValor == 123; 123; long long longValor longValor == intValor; intValor; Console.WriteLine("(long) Console.WriteLine("(long) {0} {0} == {1}", {1}", intValor, intValor, ¬longValor); ¬longValor); }} }}

„

Las conversiones implícitas no pueden fallar z

Se puede perder precisión, pero no magnitud

La conversión de un tipo de datos int a otro long es implícita. Esta conversión siempre tiene éxito y jamás produce una pérdida de información. El siguiente ejemplo muestra cómo convertir la variable intValor de un int a un long: using System; class Test { static void Main( ) { int intValor = 123; long longValor = intValor; Console.WriteLine("(long) {0} = {1}", intValor, ¬longValor); } }

Uso de variables de tipo valor

27

Conversión explícita de tipos de datos Objetivo del tema

Explicar como hacer una conversión implícita de tipos de datos.

Explicación previa

Para hacer una conversión explícita de datos se emplea una expresión de cast (molde).

„

Para hacer conversiones explícitas se usa una expresión de cast (molde):

using using System; System; class class Test Test {{ static static void void Main( Main( )) {{ long long longValor longValor == Int64.MaxValor; Int64.MaxValor; int int intValor intValor == (int) (int) longValor; longValor; Console.WriteLine("(int) Console.WriteLine("(int) {0} {0} == {1}", {1}", longValor, longValor, ¬intValor); ¬intValor); }} }}

Para hacer una conversión explícita de tipos de variables se puede emplear una expresión de cast (molde). El siguiente ejemplo muestra cómo convertir la variable longValor de un tipo de datos long a otro int utilizando una expresión de cast: using System; class Test { static void Main( ) { long longValor = Int64.MaxValor; int intValor = (int) longValor; Console.WriteLine("(int) {0} = {1}", longValor, ¬intValor); } }

En este ejemplo se produce un desbordamiento, por lo que el resultado es el siguiente: (int) 9223372036854775807 = -1

Uso de variables de tipo valor

28

Para que esto no ocurra se puede usar la instrucción checked, que lanza una excepción en caso de fallo en una conversión: using System; class Test { static void Main( ) { checked { long longValor = Int64.MaxValor; int intValor = (int) longValor; Console.WriteLine("(int) {0} = {1}", longValor, ¬intValor); } } }

Instrucciones y excepciones

Índice Notas generales

1

Introducción a las instrucciones

2

Uso de instrucciones condicionales

6

Uso de instrucciones iterativas

15

Uso de instrucciones de salto

25

Tratamiento de excepciones básicas

28

Lanzamiento de excepciones

39

Instrucciones y excepciones

i

Notas para el instructor Este módulo explica el uso de algunas instrucciones comunes de C#. También explica el tratamiento de excepciones en C#. En particular, muestra cómo lanzar y capturar errores, y cómo emplear bloques try-finally para asegurarse de que una excepción no hace que el programa se detenga antes de que se elimine el error. Al final de este módulo, los estudiantes serán capaces de: Describir los distintos tipos de instrucciones de control. • Usar instrucciones de salto. • Usar instrucciones condicionales. • Usar instrucciones iterativas. • Tratar y lanzar excepciones en una aplicación C#.

Instrucciones y excepciones

1

Notas generales Objetivo del tema

Ofrecer una introducción a los contenidos y objetivos del módulo.

Explicación previa

En este módulo estudiará las instrucciones comunes y las instancias de programación que se pueden emplear en C#.

„

Introducción a las instrucciones

„

Uso de instrucciones condicionales

„

Use instrucciones iterativas

„

Uso de instrucciones de salto

„

Tratamiento de excepciones básicas

„

Lanzamiento de excepciones

Una de las cosas más importantes a la hora de utilizar un lenguaje de programación es saber escribir las instrucciones que forman la lógica de un programa en ese lenguaje. Este módulo explica cómo usar algunas instrucciones comunes, así como el tratamiento de excepciones en C#. En particular, este módulo muestra cómo lanzar y capturar errores, y cómo emplear bloques try-finally para asegurarse de que una excepción no hace que el programa se detenga antes de que se elimine el error. Al final de este módulo, usted será capaz de: • Describir los distintos tipos de instrucciones de control. • Usar instrucciones de salto. • Usar instrucciones condicionales. • Usar instrucciones iterativas. • Tratar y lanzar excepciones.

Instrucciones y excepciones

2

‹ Introducción a las instrucciones Objetivo del tema

Ofrecer una introducción a los temas tratados en esta sección.

Explicación previa

Esta sección ofrece una introducción a las instrucciones y a los principales tipos de instrucciones que se emplean en C#.

„

Bloques de instrucciones

„

Tipos de instrucciones

Un programa consiste en una sucesión de instrucciones. En tiempo de ejecución, estas instrucciones se ejecutan en el orden en que aparecen en el programa, de izquierda a derecha y de arriba a abajo. Al final de esta lección, usted será capaz de: • Agrupar un conjunto de instrucciones en C#. •

Usar los distintos tipos de instrucciones disponibles en C#.

Instrucciones y excepciones

3

Bloques de instrucciones Objetivo del tema

Explicar cómo agrupar instrucciones en bloques.

Explicación previa

Los grupos de instrucciones son necesarios en muchos lenguajes, incluido C#.

„

Se usan llaves para delimitar bloques {{ // // code code }}

„

Un bloque y su bloque padre o pueden tener una variable con el mismo nombre {{ int int i; i; ... ... {{ int int i; i; ... ... }}

„

Bloques hermanos pueden tener variables con el mismo nombre {{ int int i; i; ... ... }} ... ... {{ int int i; i; ... ...

}} }}

Cuando se desarrollan aplicaciones C# es necesario agrupar instrucciones, del mismo modo que se hace en otros lenguajes de programación. Para ello se emplea la sintaxis de lenguajes como C, C++ y Java, lo que significa que los grupos de instrucciones están rodeados por llaves: { y }. Para los grupos de instrucciones no se utilizan delimitadores con combinaciones de palabras, como If ... End If de Microsoft® Visual Basic®.

Instrucciones agrupadas en bloques Un grupo de instrucciones puestas entre llaves recibe el nombre de bloque. Un bloque puede contener una sola instrucción o bien otro bloque anidado dentro de él. Cada bloque define un ámbito. Una variable que esté declarada en un bloque es una variable local, y su ámbito se extiende desde su declaración hasta la llave de cierre con que termina el bloque al que pertenece. Es conveniente declarar una variable en un bloque lo más interno posible, ya que la menor visibilidad de la variable contribuye a hacer más claro el programa.

Instrucciones y excepciones

4

Uso de variables en bloques de instrucciones En C# no es posible declarar una variable en un bloque interno con el mismo nombre que una variable en un bloque externo. Por ejemplo, el siguiente código no está permitido: int i; { int i; // Error: i ya declarada en bloque padre ... }

Sin embargo, es posible declarar variables con el mismo nombre en bloques hermanos. Los bloques hermanos son bloques que pertenecen al mismo bloque padre y están anidados al mismo nivel, como en el siguiente ejemplo: { int i; ... } ... { int i; ... }

Se pueden declarar variables en cualquier punto de un bloque de instrucciones, lo que hace más sencillo seguir la recomendación de inicializar una variable en el momento de declararla.

Instrucciones y excepciones

5

Tipos de instrucciones Objetivo del tema

Describir los tres tipos de instrucciones comunes que se pueden utilizar en el lenguaje C#.

Instrucciones Instrucciones Condicionales Condicionales Las Las instrucciones instrucciones ifif yy switch switch

Explicación previa

C# ofrece tres tipos distintos de instrucciones para controlar el flujo de ejecución.

Instrucciones Instrucciones de de iteración iteración Las Las instrucciones instrucciones while, while, do, do, for, for, yy foreach foreach Instrucciones Instrucciones de de salto salto Las instrucciones Las instrucciones goto, goto, break, break, yy continue continue

La complejidad de la lógica de un programa aumenta a medida que lo hace la complejidad del problema que se intenta resolver con ese programa. Por ello es preciso que el programa tenga control estructurado de flujo, lo que se puede conseguir mediante el uso de instancias o instrucciones de más alto nivel. Estas instrucciones se pueden agrupar en las siguientes categorías: •

Instrucciones condicionales Las instrucciones if y switch se conocen como instrucciones condicionales, ya que toman decisiones en función del valor de expresiones y ejecutan unos comandos u otros en función de las decisiones tomadas.



Instrucciones iterativas Las instrucciones while, do, for y foreach se ejecutan repetidamente mientras se cumple una condición. También se conocen como instrucciones de bucle. Cada una de estas instrucciones está pensada para un estilo de iteración distinto.



Instrucciones de salto Las instrucciones goto, break y continue se usan para transferir el control incondicionalmente a otra instrucción.

Instrucciones y excepciones

6

‹ Uso de instrucciones condicionales Objetivo del tema

Ofrecer una introducción a los temas tratados en esta sección.

Explicación previa

Esta sección explica el uso de las instrucciones condicionales if y switch.

„

La instrucción if

„

Instrucción if en cascada

„

La instrucción switch

„

Problema: ¿Dónde está el error?

Las instrucciones if y switch se conocen como instrucciones condicionales, ya que toman decisiones en función del valor de expresiones y ejecutan unos comandos u otros en función de las decisiones tomadas. Al final de esta lección, usted será capaz de: •

Usar la instrucción if en C#.



Usar la instrucción switch en C#.

Instrucciones y excepciones

7

La instrucción if Objetivo del tema

Describir la instrucción if.

Explicación previa

A menudo los programas tienen que ejecutar distintas instrucciones dependiendo de una condición.

„

Sintaxis:

if if (( expresión-booleana expresión-booleana )) primera-instrucción-incrustada primera-instrucción-incrustada else else segunda-instrucción-incrustada segunda-instrucción-incrustada „

No hay conversión implicita de int a bool

int int x; x; ... ... if // if (x) (x) ... ... // Debe Debe ser ser if if (x (x != != 0) 0) en en C# C# if (x = 0) ... // Debe ser if (x == 0) en if (x = 0) ... // Debe ser if (x == 0) en C# C#

Recomendación al profesor

La sintaxis de la instrucción if no es ninguna novedad para los programadores de C y C++, así que procure no dedicar demasiado tiempo a este tema y concéntrese en las diferencias entre C# y otros lenguajes, y en particular en la ausencia de una conversión predeterminada de un valor entero en otro booleano. Muestre un ejemplo de una instrucción if que tenga un bloque incrustado, y utilice este ejemplo para explicar cómo declarar una variable dentro de un bloque.

La instrucción if es la más utilizada para tomar decisiones. Puede estar asociada con una cláusula opcional else, como se muestra aquí: if ( expresión-booleana ) primera-instrucción-incrustada else segunda-instrucción-incrustada

La instrucción if evalúa una expresión booleana para determinar el curso de acción a tomar. Si el resultado de la expresión booleana es true, el control pasa a la primera instrucción; si es false y existe una cláusula else, el control se transfiere a la segunda instrucción.

Instrucciones y excepciones

8

Ejemplos Se puede utilizar una instrucción if sencilla, como la siguiente: if (numero % 2 == 0) Console.WriteLine("par");

Aunque las instrucciones incrustadas no necesitan llaves, muchas guías de estilo recomiendan utilizarlas porque previenen errores y hacen que el código sea más fácil de mantener. El ejemplo anterior se puede reescribir con llaves, como vemos: if (numero % 2 == 0) { Console.WriteLine("par"); }

También es posible usar un bloque de instrucciones if como en este ejemplo: if (minuto == 60) { minuto = 0; hora++; }

Conversión de valores enteros en booleanos La conversión implícita de un valor entero en otro booleano es una fuente de posibles errores. Para evitar estos errores, C# no permite la conversión de valores enteros en booleanos. Ésta es una diferencia importante entre C# y otros lenguajes similares. Las instrucciones siguientes, por ejemplo, generan como mucho avisos en C y C++, mientras que en C# producen errores de compilación: int x; ... if (x) ... // En C# debe ser x != 0 if (x = 0) ... // En C# debe ser x == 0

Instrucciones y excepciones

9

Instrucciones if en cascada Objetivo del tema

Explicar cómo usar instrucciones condicionales complejas.

Explicación previa

En situaciones complejas puede ser necesario anidar varias instrucciones if.

Recomendación al profesor

El código de ejemplo mostrado en la transparencia aparecerá modificado cuando se estudie la instrucción switch. Puede ser conveniente repasar esta transparencia después de ver la instrucción switch.

enum enum Palo Palo {{ Treboles, Treboles, Corazones, Corazones, Diamantes, Diamantes, Picas} Picas} Palo cartas = Palo.Corazones; Palo cartas = Palo.Corazones; if if (cartas (cartas == == Palo.Treboles) Palo.Treboles) color = color = “Negro”; “Negro”; else else if if (cartas (cartas == == Palo.Corazones) Palo.Corazones) color = “Rojo"; color = “Rojo"; else else if if (palo (palo == == Palo.Diamantes) Palo.Diamantes) color = "Rojo"; color = "Rojo"; else else color color == “Negro"; “Negro";

Para las instrucciones if en cascada se utiliza else if. C# no incluye la instrucción else if, sino que forma una instrucción del mismo tipo a partir de una cláusula else y una instrucción if, como en C y C++. En otros lenguajes, como Visual Basic, se crean cascadas de instrucciones if colocando una instrucción else if entre la instrucción if y la instrucción final else. La instancia else if permite tener un número arbitrario de ramas. No obstante, las instrucciones controladas por una instrucción if en cascada son mutuamente excluyentes, lo que significa que sólo se ejecuta una instrucción de entre todas las instancias else if.

Instrucciones y excepciones

10

Instrucciones if anidadas El anidamiento de una instrucción if dentro de otra puede crear una ambigüedad llamada dangling else (else pendiente), como se ve en el siguiente ejemplo: if (porciento >= 0 && porciento 50) Console.WriteLine("Pasa"); else Console.WriteLine("Error: fuera del intervalo");

La cláusula else aparece indentada en la misma columna que el primer if, por lo que al leer el código no parece que el else esté asociado al segundo if. Esto puede resultar peligroso, ya que el compilador vincula una cláusula else a su instrucción if más cercana independientemente del diseño del programa. Esto significa que el compilador interpretará el código anterior de la siguiente manera: if (porciento >= 0 && porciento 50) Console.WriteLine("Pasa"); else Console.WriteLine("Error: fuera del intervalo"); }

Una forma de asociar el else al primer if es utilizar un bloque: if (porciento >= 0 && porciento 50) Console.WriteLine("Pasa"); } else { Console.WriteLine("Error: fuera del intervalo"); }

Consejo Es recomendable escribir instrucciones if en cascada con la indentación adecuada, ya que de lo contrario las decisiones largas se hacen rápidamente ilegibles y superan el margen derecho de la página o pantalla.

Instrucciones y excepciones

11

La instrucción switch Objetivo del tema

Explicar una forma alternativa de tomar decisiones complejas.

Explicación previa

Las instrucciones if anidadas pueden resultar confusas a la hora de expresar condiciones complejas. En algunos casos, pero no en todos, es posible utilizar la instrucción switch como alternativa.

Recomendación al profesor

Se dice a menudo que en programas orientados a objetos se debe evitar la instrucción switch. Por supuesto, esto se debe a que muchas instrucciones switch utilizan un marcador de tipo en lugar de un polimorfismo. La instrucción switch se puede emplear para tomar decisiones en función del valor de un dato, y es especialmente adecuada para determinar el valor de una variable enum.

„

Las instrucciones switch se usan en bloques de varios casos

„

Se usan instrucciones break para evitar caídas en cascada (fall through)

switch switch (palo) (palo) {{ case Palo.Treboles case Palo.Treboles :: case case Palo.Picas Palo.Picas :: color color == "Negro"; "Negro"; break; break; case Palo.Corazones case Palo.Corazones :: case case Palo.Diamantes Palo.Diamantes :: color color == "Rojo"; "Rojo"; break; break; default: default: color color == "ERROR"; "ERROR"; break; break; }}

La instrucción switch proporciona un mecanismo elegante para expresar condiciones complejas que, de lo contrario, requerirían el uso de instrucciones if anidadas. Consta de bloques de varios casos, cada uno de los cuales especifica una sola constante y una etiqueta case asociada. No está permitido agrupar varias constantes en una sola etiqueta case, sino que cada constante debe tener la suya propia. Un bloque switch puede contener declaraciones. El ámbito de una constante o variable local declarada en un bloque switch se extiende desde su declaración hasta el final del bloque switch, como se ve en el ejemplo de la transparencia.

Ejecución de instrucciones switch Una instrucción switch se ejecuta de la siguiente forma: 1. Si una de las constantes especificada es una etiqueta case es igual al valor de la expresión switch, el control pasa a la lista de instrucciones que sigue a la correspondiente etiqueta case. 2. Si ninguna constante de las etiquetas case es igual al valor de la expresión switch, y la instrucción switch contiene una etiqueta default, el control pasa a la lista de instrucciones que sigue a la etiqueta default. 3. Si ninguna constante de las etiquetas case es igual al valor de la expresión switch, y la instrucción switch no contiene una etiqueta default, el control pasa al final de la instrucción switch.

Instrucciones y excepciones

12

Una instrucción switch sólo se puede utilizar para evaluar los siguientes tipos de expresiones: cualquier tipo entero, un char, una enum o una string. También es posible evaluar otros tipos de expresiones con la instrucción switch, siempre y cuando haya exactamente una conversión implícita definida por el usuario del tipo no permitido a uno de los tipos permitidos. Nota Al contrario de lo que ocurre en Java, C o C++, el tipo que rige una instrucción switch en C# puede ser una cadena. Con una expresión de cadena, la constante de una etiqueta case puede tener el valor null. Para más información sobre operadores de conversión, busque “operadores de conversión” en los documentos de ayuda del SDK de Microsoft .NET Framework.

Grupos de constantes Para agrupar varias constantes hay que repetir la palabra clave case para cada una de ellas, como se muestra en el siguiente ejemplo: enum MesNombre { Enero, Febrero, ..., Diciembre } MesNombre actual; int mesDias; ... switch (actual) { case MesNombre.Febrero : mesDias = 28; break; case MesNombre.Abril : case MesNombre.Junio : case MesNombre.Septiembre : case MesNombre.Noviembre : mesDias = 30; break; default : mesDias = 31; break; }

Las etiquetas case y default se utilizan únicamente como puntos de entrada para el flujo de control del programa en función del valor de la expresión switch, pero no modifican el flujo de control. Los valores de las constantes en las etiquetas case deben ser únicos, lo que significa que no puede haber dos constantes con el mismo valor. Por ejemplo, este ejemplo generará un error en tiempo de compilación: switch (cartas) { case Palo.Treboles : case Palo.Treboles: // Error: etiqueta duplicada ... default : default : // Error: etiqueta duplicada de nuevo ... }

Instrucciones y excepciones

13

Uso de break en instrucciones switch Al contrario de lo que ocurre en Java, C o C++, las instrucciones de C# asociadas con una o más etiquetas case no pueden caer en cascada ni continuar hasta la siguiente etiqueta case. Una caída silenciosa en cascada (silent fall through) se produce cuando la ejecución avanza sin generar un error. En otras palabras, la última instrucción asociada con un grupo de etiquetas case no puede dejar que el flujo de control llegue hasta el segundo grupo de etiquetas case. Esta condición, conocida como regla de caída en cascada o fall-through rule, se puede cumplir con las instrucciones break (posiblemente la más común), goto (muy poco habitual), return o throw, así como con un bucle infinito. El siguiente ejemplo (que forma números ordinales en inglés) generará un error en tiempo de compilación porque incumple la regla de caída en cascada: string sufijo = "th"; switch (dias % 10) { case 1 : if (dias / 10 != 1) { sufijo = "st"; break; } // Error: Caída en cascada case 2 : if (dias / 10 != 1) { sufijo = "nd"; break; } // Error: Caída en cascada case 3 : if (dias / 10 != 1) { sufijo = "rd"; break; } // Error: Caída en cascada default : sufijo = "th"; // Error: Caída en cascada }

Instrucciones y excepciones

14

El error se puede corregir reescribiendo el código de la siguiente manera: switch (dias case 1 : sufijo break; case 2 : sufijo break; case 3 : sufijo break; default : sufijo break; }

% 10) { = (dias / 10 == 1) ? "th" : "st";

= (dias / 10 == 1) ? "th" : "nd";

= (dias / 10 == 1) ? "th" : "rd";

= "th";

Uso de goto en instrucciones switch Al contrario de lo que ocurre en Java, C o C++, en C# se puede utilizar una etiqueta case y una etiqueta default como destino de una instrucción goto. De esta forma se puede lograr el efecto de caída en cascada, si es necesario. Por ejemplo, este código se compilará sin ningún problema: switch (dias % 10) { case 1 : if (dias / 10 != 1) { sufijo = "st"; break; } goto case 2; case 2 : if (dias / 10 != 1) { sufijo = "nd"; break; } goto case 3; case 3 : if (dias / 10 != 1) { sufijo = "rd"; break; } goto default; default : sufijo = "th"; break; }

La regla de caída en cascada permite reordenar las secciones de una instrucción switch sin afectar a su comportamiento general.

Instrucciones y excepciones

15

‹ Uso de instrucciones iterativas Objetivo del tema

Ofrecer una introducción a los temas tratados en esta sección.

Explicación previa

Esta sección explica el uso de las instrucciones de bucle.

„

La instrucción while

„

La instrucción do

„

La instrucción for

„

La instrucción foreach

„

Problema: ¿Dónde está el error?

Las instrucciones while, do, for y foreach se conocen como instrucciones iterativas. Se puede utilizar para realizar operaciones mientras se cumple una condición. Al final de esta lección, usted será capaz de: •

Usar instrucciones iterativas en C#.



Identificar errores en el uso de instrucciones iterativas en C#.

Instrucciones y excepciones

16

La instrucción while Objetivo del tema

Describir la instrucción while.

Explicación previa

A menudo hay que ejecutar varias veces el mismo bloque de instrucciones hasta que se cumple una condición.

„

Ejecuta instrucciones en función de un valor booleano

„

Evalúa la expresión booleana al principio del bucle

„

Ejecuta las instrucciones mientras el valor booleano sea True

int int ii == 0; 0; while while (i (i