Contenido de Un Vistazo
Contenido de Un Vistazo
Contenido de Un Vistazo
1 Fundamentos de marco . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2 .Entrada/salida
...... 1
. 67
3 (E/S) . . modificar
Buscar, . . . . . . . . .y. codificación
. . . . . . . . . . . de
. . texto.
. . . . . .. .. .. .. .. .. .. .. .. .. .. .. . . 14
4 ........
Colecciones 3
y genéricos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
5 ........
Serialización 5
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
6 .Gráficos
........ ....... ............ ............ ........ 7
31
7 .Rosca
. . . . .. .. .. .. .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
36
8 . . . .dominios
Los ... 7
de aplicación y servicios . . . . . . . . . . . . . . . . 43
9 . . . . . . . . . . y. .configuración
Instalación . de 5
47
10 aplicaciones . . . . . . . .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. . . . . . . . . . . . . . . 7
La instrumentación. 55
11 .La
. . seguridad
. . . . . . . . .de
. la 1
62
aplicación
12 Y . . . .de
la seguridad . . los
. . . datos
. . . . .de
. . . . . . . . . . . . . . . . . . . . . . . . . 70
7
usuario
13 La . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
interoperación 1
14 .La
. . reflexión
. . . . . . . . .. .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
82
15 .Correo
. . . . . .. .. .. .. .. .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .9
88
......... ...
16 La 9
91
globalización . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Tabla de contenido
Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
...
1 Fundamentos de
marco . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1
Antes de comenzar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Lección 1: Uso de los tipos de valor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Los tipos de valor integrados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Cómo declarar los tipos de valor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Cómo crear tipos definidos por el usuario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Cómo crear enumeraciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Laboratorio: Declarar y utilizar los tipos de valor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Lección 2: Uso de tipos comunes de referencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
¿Qué es un tipo de referencia? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Comparando el comportamiento de referencia y los tipos de valor . . . . . . . . . . . . . . . . . . 17
Los tipos de referencia incorporada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Las cadenas y los constructores de cadena . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Cómo crear y ordenar matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Cómo utilizar Arroyos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Cómo lanzar y capturar excepciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Laboratorio: Trabajo con tipos de referencia. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2 entrada/salida (E/S). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . 67
Antes de comenzar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Lección 1: Explorar el sistema de archivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
¿Cuáles son las clases de sistema de archivo? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
FileSystemInfo la clase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
La clase FileInfo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Cómo obtener información acerca de un archivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Cómo copiar un archivo . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
4 colecciones y genéricos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . 185
Antes de comenzar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
Lección 1: recopilar elementos de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
Tipos de colecciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
Adición y eliminación de elementos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
Iterar a través de elementos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
Interfaces consistentes en colecciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
Ordenar elementos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
Laboratorio: ordenar una tabla de cadenas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
Lección 2: Trabajar con las listas secuenciales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
¿Qué son las listas secuenciales? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
La clase Queue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
La clase Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
Laboratorio: Construyendo FIFO y LIFO listas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
5 Serialización . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . 267
Antes de comenzar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
Lección 1: la serialización de objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
¿Qué es la serialización? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
Cómo serializar un objeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
Cómo deserializar un objeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
Cómo crear clases que se pueden serializar . . . . . . . . . . . . . . . . . . . . . . . . . . 274
Elegir un formato de serialización . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
Cómo utilizar SoapFormatter. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
Cómo controlar la serialización de jabón . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
Directrices para la serialización . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
Laboratorio: Serializar y deserializar objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
Lección 2: serialización XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
¿Por qué utilizar la serialización XML? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
Cómo usar XML para serializar un objeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
Cómo usar XML para deserializar un objeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
Cómo crear clases que se pueden serializar
Mediante la serialización XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
Cómo controlar la serialización XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
Cómo se ajustan a un Esquema XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
Cómo serializar un objeto DataSet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
Laboratorio: Uso de la serialización XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
Lección 3: Serialización personalizada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
Cómo implementar la serialización personalizada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
Respondiendo a la serialización de eventos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
Cómo cambiar la serialización basándose en el contexto . . . . . . . . . . . . . . . . . . . . . . . . 308
Cómo crear un formateador personalizado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
Práctica: Implementar la serialización personalizada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
Capítulo Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
Resumen del capítulo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
Términos clave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
Escenarios de caso. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
Caso práctico 1: Eligiendo una serialización técnica . . . . . . . . . . . . . . . . . . . . 314
Preguntas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
Caso práctico 2: serialización entre versiones. . . . . . . . . . . . . . . . . . . . . . . . . . 315
Preguntas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
6 Los gráficos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . 319
Antes de comenzar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
Lección 1: Dibujo de gráficos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
El espacio de nombres System.Drawing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
Cómo especificar la ubicación y el tamaño de los controles . . . . . . . . . . . . . . . . . . . . . . 324
Cómo especificar el color de los controles. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325
Cómo dibujar líneas y formas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
Cómo Personalizar bolígrafos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330
Cómo rellenar formas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
Laboratorio: crear un método para dibujar un gráfico circular . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
Resumen de la lección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
Examen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340
Lección 2: Trabajar con imágenes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
Las clases Image y Bitmap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
Cómo mostrar imágenes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343
Cómo crear y guardar las imágenes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343
Cómo utilizar los iconos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
Laboratorio: Guardar un gráfico como una imagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
Resumen de la lección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
Examen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
Lección 3: formato de texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
Cómo agregar texto a un gráfico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
Cómo crear un objeto Font . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
Cómo escribir texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
Cómo controlar el formato del texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
Laboratorio: Agregar texto a una imagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354
Resumen de la lección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360
Examen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360
Capítulo Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
Resumen del capítulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
7 Rosca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . 367
Antes de comenzar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
Lección 1: Crear subprocesos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
Hilos simple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
Pasando datos a las roscas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
Detener subprocesos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379
El contexto de ejecución . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381
Laboratorio: usar la clase Thread para demostrar el subprocesamiento múltiple . . . . . . . . . . . . . . . 383
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385
Lección 2: Intercambio de datos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387
Evitando colisiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387
Bloqueos de sincronización . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
Laboratorio: usar un mutex para crear un Single Instance Application . . . . . . . . . . . . . . . 408
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
Lección 3: El modelo de programación asincrónica . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
Comprender la programación asincrónica . . . . . . . . . . . . . . . . . . . . . . . . . . 412
Utilizando el ThreadPool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
Utilizando objetos de temporizador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
Laboratorio: utilizar el ThreadPool a la cola de elementos de trabajo. . . . . . . . . . . . . . . . . . . . . . . . . 428
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429
Capítulo Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
Resumen del capítulo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
8 dominios de aplicación y
servicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435
Antes de comenzar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436
Lección 1: crear dominios de aplicación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437
¿Qué es un dominio de aplicación?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437
La clase AppDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439
Cómo crear un dominio de aplicación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443
Cómo cargar ensamblados en un dominio de aplicación . . . . . . . . . . . . . . . . . . . . 443
Cómo descargar un dominio de aplicación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444
Laboratorio: creación de dominios y cargar ensamblados . . . . . . . . . . . . . . . . . . . . . . . 444
Resumen de la lección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446
Examen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446
Lección 2: Configuración de los dominios de aplicación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448
Cómo utilizar un dominio de aplicación para lanzar
Conjuntos con privilegios limitados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448
Cómo configurar las propiedades del dominio de aplicación . . . . . . . . . . . . . . . . . . . . . 451
Laboratorio: aplicación de control de privilegios de dominio . . . . . . . . . . . . . . . . . . . . . . . . . . . 453
Resumen de la lección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454
Examen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455
Lección 3: Crear servicios de Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457
¿Qué es un servicio de Windows? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457
Cómo crear un proyecto de servicio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459
Cómo implementar un servicio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460.
Cómo crear un proyecto de instalación de un servicio. . . . . . . . . . . . . . . . . . . . . . . . . . 461
Cómo gestionar y controlar un servicio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463
Laboratorio: crear, instalar e iniciar un servicio para monitorizar un sitio Web . . . . . . . . . . . 465
Resumen de la lección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469
Examen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 470
Capítulo Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 472
Resumen del capítulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 472
Términos clave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 472
Caso escenarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473
Caso práctico 1: Creación de una herramienta de pruebas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473
Caso práctico 2: Supervisión de un archivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474
Prácticas recomendadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475
Crear una unidad de aislamiento para Common Language Runtime
Dentro de una aplicación de .NET Framework mediante el uso de dominios de aplicación . . . . . 475
Implementar, instalar y controlar un servicio. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476
Tomar un Test de práctica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476
9 Instalación y configuración de
aplicaciones. . . . . . . . . . . . . . . . . . . . . . . . . 477
Antes de comenzar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 478
Lección 1: Opciones de configuración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480
Configuración de .NET Framework 2.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481
Ajustes comunes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 486
Configuración de la aplicación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 498
Laboratorio: Obtener la cadena de conexión de base de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509
Lección 2: Crear un instalador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511
Usando el instalador de base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511
Cometer una instalación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515
La reversión de una instalación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516
Laboratorio: establecer y revertir una clave de Registro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 518
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519
Lección 3: Uso de la herramienta Configuración de .NET Framework 2.0 . . . . . . . . . . . . . . . . . . . 520
Las configuraciones de navegación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520
Cambiar una configuración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522
Restablecer una configuración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 527
Laboratorio: cambio y restaurar la configuración de la aplicación . . . . . . . . . . . . . . . . . . . . . . . . . 528
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 529
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 530
Lección 4: Gestión de la configuración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 531
La obtención y almacenamiento de configuración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 531
Implementar interfaces de configuración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 533
Laboratorio: Leer y escribir la configuración . . . . . . . . . . . . . . . . . . . . . . . . . . . 543
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 545
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546
Capítulo Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 547
Resumen del capítulo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 547
10
Instrumentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . 551
Antes de comenzar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 552
Lección 1: Registro de eventos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 553
Mediante el registro de eventos de Windows y de Microsoft . . . . . . . . . . . . . . . . . . . 553
Creación y eliminación de un registro de eventos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 555
Para escribir en un registro de sucesos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 556
Lectura de un registro de eventos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 558
Laboratorio: crear y utilizar una aplicación de registro de eventos . . . . . . . . . . . . . . . . . . . . . . . . . 559
Resumen de la lección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 560
Examen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561
Lección 2: la depuración y el seguimiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 563
Escribir la salida. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 563
Atributos Debug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 572
Crear agentes de escucha de seguimiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 581.
Oyente objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584
Laboratorio: crear y utilizar una aplicación de registro de eventos . . . . . . . . . . . . . . . . . . . . . . . . . 589
Resumen de la lección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 590
Examen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 590
Lección 3: Supervisar el rendimiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 592
Una visión general de los Procesos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 594
La clase Process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 594
Enumerar los procesos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 594
Utilizando contadores de rendimiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 598
La clase CounterCreationData. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 600
La clase PerformanceCounterCategory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 601
La clase PerformanceCounter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 603
Procesos de inicio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 604
El StackTrace StackFrame y clases. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 607
Laboratorio: aplicación de monitorización del rendimiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . 609
Resumen de la lección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 612
Examen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 612
11 La seguridad de la aplicación . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . 627
Antes de comenzar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 629
Lección 1: Descripción de la seguridad de acceso a código. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 630
¿Cuál es la seguridad de acceso a código? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 630
Elementos de seguridad de acceso del código . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 631
¿Cuál es la política de seguridad? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 639
Cómo CAS trabaja con la seguridad del sistema operativo . . . . . . . . . . . . . . . . . . . . . . . 640
Cómo utilizar la herramienta Configuración de .NET Framework para configurar CA. . . . 641
Cómo utilizar la herramienta Directiva de seguridad de acceso a código . . . . . . . . . . . . . . . . . . . . . . 646
Laboratorio: configuración de seguridad de acceso a código. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 652
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 655
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 656
Lección 2: Usar la seguridad declarativa para proteger las reuniones . . . . . . . . . . . . . . . . . . . . 658
Razones para utilizar el conjunto CAS declaraciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . 658
Clases para permisos de CAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 659
Tipos de permiso de conjunto de declaraciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . 662
Cómo crear General declaraciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 663
Directrices para el uso de declaraciones de montaje . . . . . . . . . . . . . . . . . . . . . . . . . . . 666
Laboratorio: Uso General solicitudes de permisos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 666
14 La reflexión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . 829
Antes de comenzar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 830
Lección 1: Descripción de la reflexión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 831
Descripción ensamblados y módulos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 831
Examinar un conjunto. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 833
Laboratorio: utilizar las herramientas .NET para examinar una Asamblea . .. .. . . . . . . 838
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 840
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 840
Lección 2: atributos de ensamblado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 842
Atributos comunes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 842
Obtener atributos de ensamblado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 847
Laboratorio: Establecer atributos de ensamblado y mostrarlos en tiempo de ejecución. . . . . . . . . . . . . .
848
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 850
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 850
Lección 3: reflejo de Tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 852
Obtención de Tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 852
La enumeración de miembros de clase . . . .. . . . . . . . . . . . . . . . . . . . . . . . . 859
BindingFlags utilizando el . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 863
Laboratorio: cargar un ensamblado, y volcar su información de tipo. .. . . . . . . 864
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 866
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 867
Lección 4: Escribir el código dinámico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 868
Utilizando el código dinámico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 868
Laboratorio: invocar miembros mediante la reflexión . . . .. . . . . . . . . . . . 872
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874
Lección 5: Crear el código en tiempo de ejecución . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . 876
La construcción de su propio código . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 876
Laboratorio: crear un ensamblado dinámico . . . . . . . . . . . . . .. . . . . . . . . . . . . 882
Resumen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 885
Lección Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 885
Capítulo Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 886
Resumen del capítulo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . 886
Términos clave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 886
Caso práctico: Crear una arquitectura de plugin . . . . . . . . . . .. . . . . . . . . . . . . . 887
Prácticas recomendadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 887
Escribir una aplicación de explorador de montaje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 887
Tomar un Test de práctica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 888
15 de Correo . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . 889
Antes de comenzar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 890
Lección 1: Crear un mensaje de correo electrónico . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . 891
El proceso de creación y envío de un mensaje de correo electrónico . . .. . . . . . 891
Cómo crear un objeto MailMessage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 892
Cómo adjuntar archivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 894
Cómo crear mensajes de correo electrónico HTML. . . . . . .. . . . . . . . . . . . . . . . . . . 895
Laboratorio: crear un objeto MailMessage . . . . . . . . . . . . . .. . . . . . . . . . 897
Resumen de la lección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 900
Examen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 900
Lección 2: Envío de correo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 902
Cómo enviar un mensaje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 902
Cómo gestionar el correo Excepciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 903
Cómo configurar las credenciales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 904
Cómo configurar SSL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 905.
Cómo enviar un mensaje de forma asincrónica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 905.
Laboratorio: Enviar un mensaje de correo electrónico . . . . . .. .. . . . . . . . . . . . . . . . . . 907
Resumen de la lección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 912
Examen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 913
Capítulo Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 915
Resumen del capítulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . 915
Términos clave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 915
Caso práctico: Agregar capacidades de correo electrónico a una aplicación existente ..
. . . . . . . . . . . 915
Prácticas recomendadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 916
Enviar correo electrónico a un servidor SMTP (Simple Mail Transfer Protocol)
Para la entrega de una aplicación de .NET Framework . . . . . . . . . . . . . . . . . . . . . . . 917
Tomar un Test de práctica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 917
16 de la
globalización. . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . 919
Antes de comenzar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 919
Lección 1: Utilizando información de Cultura. . . . .. . . . . . . . . . . . . . . . . . . . . . . . . 920
Clase CultureInfo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 920
CultureTypes enumeración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 925
RegionInfo Clase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 926
DateTimeFormatInfo NumberFormatInfo y Clases . . . . . . . . . . . . . . . . . . . 927
Utilizando la clase y enumeración CompareOptions CompareInfo
Para las comparaciones de la Cultura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 929
Laboratorio: Escribir código que se ajusta a la cultura . .. . . . . . . . . . . . . . . . . . . 932
Resumen de la lección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 934
Examen de la lección. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 935
Respuestas. . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . . . . 945
Glosario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . 1007
Índice . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . . . . . . 1015
Capítulo 1
Fundamentos marco
❑ tipos genéricos
❑ clases de excepción
❑ Boxing y Unboxing
❑ TypeForwardedToAttribute Class
■ Implementar interfaces de .NET Framework para causar componentes para cumplir con
los contratos estándar. (Consultar el espacio de nombres System)
❑ El interfaz IComparable
❑ El interfaz IDisposable
❑ interfaz IConvertible
❑ interfaz ICloneable
❑ interfaz IEquatable
❑ interfaz IFormattable
■ para controlar
las interacciones entre los componentes de la aplicación .NET
Framework mediante eventos y delegados. (Consultar el espacio de nombres System)
❑ El delegado de clase
❑ clase EventArgs
❑ EventHandler delegados
Antes de empezar
Este libro asume que usted tiene por lo menos dos a tres años de experiencia en el desarrollo
basado en la Web, basado en Microsoft Windows o aplicaciones distribuidas mediante el uso
de .NET Framework 1.0, .NET Framework 1.1 y .NET Framework 2.0. Los candidatos
deberán tener conocimientos básicos de Microsoft Visual Studio 2005. Antes de comenzar,
debe estar familiarizado con Microsoft Visual Basic o C# y estar familiarizado con las
siguientes tareas:
■ Crearuna consola o una aplicación de Windows Forms en Visual Studio utilizando Visual
Basic o C#.
■ agregar espacios de nombres y las referencias al sistema de bibliotecas de clases para un
proyecto.
■ ejecutar un proyecto en Visual Studio, establecer puntos de interrupción, el paso a través
del código, y observar los valores de las variables.
Lección 1: Uso de los tipos de valor
El más simple de los tipos de .NET Framework, principalmente tipos numéricos y booleanos,
son tipos de valor. Los tipos de valor son variables que contienen sus datos directamente en
lugar de conteniendo una referencia a los datos almacenados en la memoria. Las instancias de
los tipos de valor se almacena en un área de memoria llamada la pila, donde el tiempo de
ejecución puede crear, leer, actualizar y eliminar de forma rápida con una sobrecarga mínima.
Más información
Tipos de referencia
Para obtener más información acerca de los tipos de
referencia, consulte la Lección 2.
Cada uno de estos tipos se derivan de la clase System.ValueType tipo base. Las sec- ciones
siguientes muestran cómo utilizar estos tipos diferentes.
Hay casi 300 tipos de valor en el marco, pero los tipos mostrados aquí cubren la mayoría de
necesidades. Cuando asigne entre las variables de tipo de valor, se copian los datos de una variable
a la otra y se almacenan en dos ubicaciones diferentes en la pila. Este comportamiento es diferente
del de los tipos de referencia, que se discute en la Lección 2.
Aunque los tipos de valor a menudo representan valores simples, todavía funcionan como objetos.
En otras palabras, puede llamar a métodos en ellos. De hecho, es común utilizar el método
ToString al mostrar valores como texto. Es invalidado ToString de la fundamental de tipo
System.Object.
// C#
Bool b = false;
// C#
Nullable<bool> b = null;
// C#
Si b.HasValue)Console.WriteLine("b es {0}." b.Value);
Else Console.WriteLine("b no está establecida.");
Cómo crear tipos definidos por el usuario
Los tipos definidos por el usuario se denominan también estructuras o simplemente las
estructuras, después de la palabra clave idioma utilizado para crearlos. Como con otros tipos de
valor, instancias de tipos definidos por el usuario se almacenan en la pila y contienen directamente
sus datos. En la mayoría de otras maneras, es- tructuras se comporte casi idénticas a las clases.
Las estructuras son un compuesto de otros tipos que hacen que sea más fácil trabajar con datos
relacionados. El ejemplo más simple de esto es System.Drawing.El punto, que contiene enteros X e
Y propiedades que definen las coordenadas horizontal y vertical de un punto. La estructura Point
simplifica el trabajo con coordenadas de constructor y proporcionando a los países miem- bros
demostrado aquí:
' VB - Requiere la referencia a System.Drawing
' Crear punto
Dim p como nuevo System.Drawing.Punto(20, 30).
Puede definir sus propias estructuras mediante la estructura clave en Visual Basic o la palabra
clave struct en C#. Por ejemplo, el código siguiente crea un tipo que recorre un conjunto de
números enteros comprendidos entre los valores mínimo y máximo establecidos por el constructor:
// C#
Ciclo de estruct.
{
// Campos privados
Int _val, _min, _max;
// Constructor
Ciclo público(int, int mín máx.).
{
_Val = min;
_Min = min;
_Max = max;
}
El valor int público
{
Get { return _val; }
Establecer
{
Si (valor > _max)
_Val = _min;
Otra cosa
{ Si (valor < _min)
_Val = _max;
Otra cosa
}
}
}
_Val = valor;
nulación pública string ToString()
{
Valor de retorno.ToString();
}
Puede utilizar esta estructura para representar los elementos que se repiten a lo largo de un
intervalo fijo, como grados de rotación o cuartos de un partido de fútbol, como se muestra aquí:
' VB
Dim grados como nuevo ciclo(0, 359), en los barrios como nuevo ciclo(1, 4) Para i as Integer = 0
a8
Grados += 90 : cuartos += 1
Console.WriteLine("grados = {0}, trimestres = {1}", grados, trimestres) Siguiente
// C#
Grados de ciclo = nuevo ciclo(0, 359); Ciclo
trimestres = nuevo ciclo(1, 4); en el caso de (int i
= 0; i <= 8; i++)
{
Grados += 90; cuartos += 1;
Console.WriteLine("grados = {0}, trimestres = {1}", grados, trimestres);
}
El ciclo muestra puede ser fácilmente convertida a y desde un tipo de valor a un tipo de referencia
cambiando la estructurastruct / palabras clave para la clase. Si realiza este cambio, las instancias
de la clase de ciclo se asignan en el montón administrado, en lugar de como 12 bytes en la pila (4
bytes para cada campo entero privado) y asignación entre dos variables resultados en ambas
variables apuntando a la misma instancia.
Mientras que la funcionalidad es similar, las estructuras son generalmente más eficientes que las
clases. Debe definir una estructura, en lugar de una clase, si el tipo funcionará mejor como un tipo
de valor de un tipo de referencia. Concretamente, tipos de estructura debe cumplir todos estos
criterios:
■ lógicamente representa un solo valor
■ Tiene una instancia tiene un tamaño inferior a 16 bytes
■ no será modificado tras la creación
■ no será arrojado a un tipo de referencia
// C#
T = Títulos Títulos.dr;
Console.WriteLine("{0,}". t); // Muestra "Dra."
❑ lastName (una cadena)
❑ la edad (un entero)
El siguiente código muestra esto:
// C#
Cadena pública FirstName,
LastName cadena pública; public
int edad;
4. Cree un constructor que inicializa los tres variables miembro, como demuestra el código
siguiente:
// C#
Persona pública(string _FirstName, LastName, cadena _int _edad)
{
FirstName = _FirstName,
LastName = _lastName; edad =
_edad;
}
// C#
Anulación pública string ToString()
{
Volver firstName lastName + + " " + " " + edad, edad;
}
6. En el método Main de la aplicación de consola, escribir código para crear una instancia de la
estructura y pase la instancia para el método Console.WriteLine, como demuestra el código
siguiente:
// C#
Persona p = new persona("Tony", "Allen", 32); Console.WriteLine(p);
// C#
Cadena pública FirstName, LastName
cadena pública; public int edad;
Géneros pública género;
// C#
Anulación pública string ToString()
{
Volver firstName lastName + + " " + " (" + sexo + " " +), de edad edad;
}
// C#
Static void main(String[] args)
{
Persona p = new persona("Tony", "Allen", 32 personas.sexos.macho);
Console.WriteLine(p.ToString();
}
Resumen de la lección
■ El.NET Framework incluye un gran número de tipos integrados que se pueden usar
directamente o utilizar para construir tus propios tipos.
■ Lostipos de valor contienen directamente sus datos, ofreciendo un excelente rendimiento. Sin
embargo, los tipos de valor están limitadas a tipos que almacene pedazos muy pequeños de datos.
En .NET Framework, todos los tipos de valor de 16 bytes o menos.
■ Puede crear tipos definidos por el usuario que almacenar varios valores y métodos.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba su conocimiento de la información en la
lección 1, "Uso de tipos de valor." Las preguntas también están disponibles en el CD
complementario si prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final del
libro.
1. Cuales de los siguientes son tipos de valor? (Seleccione todos los que
correspondan).
A. Decimal
B. Cadena
C. System.Drawing.El punto
D. Integer
2. Se pasa una variable de tipo de valor en un procedimiento como argumento. El procedimiento
cambia la variable; sin embargo, cuando el procedimiento devuelve, la variable no ha cambiado.
¿Qué ha sucedido? (Elija uno).
A. No se ha inicializado la variable antes de que fuera promulgada.
B. Pasar de un tipo de valor en un procedimiento crea una copia de los datos.
C. La variable fue declarando de nuevo en el nivel de procedimiento.
D. El procedimiento manejó la variable como una referencia.
3. Que es la declaración correcta para un entero nullable?
A.
// C#
Nullable(int) i = null;
B.
// C#
Nullable<int> i = null;
C.
// C#
Int i = null;
D.
// C#
Int<Nullable> i = null;
4. Necesita crear una simple clase o estructura que contiene sólo los tipos de valor. Debe crear la
clase o estructura, para que se ejecute de forma tan eficiente como sea posible. Usted debe ser
capaz de pasar una instancia de la clase o estructura a un procedimiento sin la preocupación de que
el procedimiento se modifica. Cuál de los siguientes debería crear?
A. Una clase de referencia
B. Una estructura de referencia
C. Una clase de valor
D. Una estructura de valores
Lección 2: Uso de los tipos de referencia común.
La mayoría de los tipos de .NET Framework son tipos de referencia. Los tipos de referencia
proporcionan una gran flexibilidad y ofrecen un rendimiento excelente al pasar a métodos. En las
secciones siguientes se presentan los tipos de referencia común discutiendo clases incorporadas. La
lección 4, "Conversión entre tipos", abarca la creación de clases, inter- faces y delegados.
Ahora considere el código siguiente, que crea una instancia de la estructura de números, copias de
esa estructura a una segunda instancia, modifica ambos valores, y muestra los resultados:
// C#
Los números n1 = new números(0); los
números N2 = n1;
N1.val += 1;
N2.val += 2;
Console.WriteLine("n1 = {0}, n2 = {1}", n1, n2).
Este código podría mostrar "n1 = 1, n2 = 2" porque una estructura es un tipo de valor, y copiando
un tipo de valor se traduce en dos valores distintos. Sin embargo, si cambia el num- tancia
la declaración de tipo de una estructura para una clase, la misma aplicación podría mostrar "n1 = 3,
n2 = 3". Cambiar números de una estructura para una clase, hace que pueda ser un tipo de
referencia, en lugar de un tipo de valor. Cuando se modifica un tipo de referencia variable, debe
modificar todas las copias de dicho tipo de referencia variable.
Cadenas de tipo System.String son inmutables en .NET. Esto significa que cualquier cambio a una
cadena hace que el tiempo de ejecución para crear una nueva cadena y abandonar la antigua. Esto
sucede invisiblemente, y muchos programadores podrían sorprenderse al enterarse de que el
siguiente código asigna cuatro nuevas cadenas en memoria:
// C#
Cadena s;
S = "wombat"; // "wombat"
S += " kangaroo"; // "canguro" wombat
S += " wallaby"; // "wombat canguro wallaby"
S += " Koala"; // "wombat canguro wallaby koala" Console.WriteLine(s);
Sólo la última cadena tiene una referencia; los otros tres serán eliminadas durante la recolección de
la basura. Evitar estos tipos de cadenas temporales ayuda a evitar la innecesaria la recolección de
basura, lo que mejora el rendimiento. Hay varias maneras de evitar cadenas temporales:
■ Utilice la clase String's concat, Joino métodos de formato para unir varios
elementos en una sola declaración.
■ Utilice la clase StringBuilder para crear dinámicas (mutable) cadenas.
StringBuilder es la solución más flexible porque puede abarcar varias declaraciones. El constructor
predeterminado crea un búfer de 16 bytes de longitud, que crece a medida que sea necesario. Puede
especificar un tamaño inicial y Tamaño máximo si te gusta. El siguiente código- dem onstrates
utilizar StringBuilder:
// C#
System.Text.StringBuilder sb = new System.Text.StringBuilder(30).
Sb.append("wombat"); // Build String. sb.append("
KANGAROO");
Sb.append(" wallaby");
Sb.append(" koala");
String s = sb.ToString(); // copia el resultado en una cadena. Console.WriteLine(s);
Otra característica sutiles pero importantes de la clase String es que anula los operadores
de System.Object. La tabla 1-4 muestra los operadores la clase String de reemplazos.
Tabla 1-4 Operadores de cadena
// C#
// Declarar e inicializar una matriz. int[] ar = { 3, 1,
2 };
// C#
// Crear y escribir en un archivo de texto
StreamWriter sw = new StreamWriter("text.txt");
Sw.WriteLine("Hello, World!");
Sw.Close();
Observe que la declaración StreamReader se trasladó fuera del bloque try en la pre- cede el
ejemplo. Esto es necesario porque el bloque finally no puede tener acceso a las variables que se
declaran dentro del bloque Try. Esto tiene sentido porque dependiendo del lugar donde se ha
producido una excepción, declaraciones de variables dentro del bloque Try puede no haber sido
ejecutados. Para capturar las excepciones que se producen durante y después de la declaración de
StreamReader, utilizar try anidadocatch // bloques Finally.
Normalmente, todos los códigos excepto por simples declaraciones de variables deben ocurrir
dentro de bloques try. Error sólido manejo mejora la experiencia del usuario cuando se producen
problemas y simplifica enormemente los problemas de depuración. Sin embargo, el manejo de
excepciones no incurrir
Una pequeña penalización de rendimiento. Para ahorrar espacio y centrarse en temas específicos, el
código de muestra en este libro normalmente no incluirá la gestión de excepciones.
Laboratorio: Trabajo con tipos de referencia
Los siguientes ejercicios reforzar el conocimiento de los tipos de referencia, cadenas y excep-
ciones. Si se produce un problema de completar un ejercicio, los proyectos terminados están
disponibles en el CD en la carpeta de código.
Ejercicio 1: Identificar los tipos de valor o referencia
En este ejercicio, va a escribir una aplicación de consola que muestra si los objetos son tipos de
valor o de referencia.
1. Con Visual Studio, cree un nuevo proyecto de aplicación de consola. Nombre del proyecto
Tipos List-Value.
2. Crear instancias de las clases siguientes:
❑ SByte
❑ El Byte
❑ Int16
❑ Int32
❑ Int64
❑ cadena
❑
Excepción
El siguiente código muestra esto:
// C#
SByte un Byte = 0, b
= 0; Int16 c = 0;
Int32 d = 0; Int64 e
= 0; string s = "";
Exception ex = nueva excepción();
3. Agregue cada uno de los casos a un nuevo objeto Array, como demuestra el código siguiente:
// C#
Tipos object[] = {a, b, c, d, e, s, ex };
3. Llamar al método Array.Sort para ordenar el conjunto de palabras, como demuestra el código
siguiente:
// C# Array.sort(SA);
4. Llamar al método String.Join para convertir la matriz de palabras en una sola cadena y, a
continuación, escriba la cadena a la consola. El código de ejemplo siguiente demonio demuestra
esto:
// C#
S = String.Join(" ", sa);
Console.WriteLine(s);
3. Ejecute su aplicación. Primero verifique que pueda mostrar correctamente un archivo de texto.
A continuación, proporcione un nombre de archivo no válido, y compruebe que aparece un cuadro
de mensaje cuando se proporciona un nombre de archivo no válido.
4. Siguiente Agregar sobrecargado de excepciones para la captura
de System.IO.FileNotFoundExcep- ción y System.UnauthorizedAccessException. El código de
ejemplo siguiente demonio demuestra esto:
// C#
Pruebe
{
TextReader tr = new StreamReader(locationTextBox.Text);
Pruebe
{ DisplayTextBox.Text = tr.ReadToEnd(); }
Catch (Exception ex)
{ MessageBox.Show(ex.message); }
Finalmente
{ Tr.Close(); }
}
Capturas (System.IO.FileNotFoundException ex)
{ MessageBox.Show("Lo sentimos, el archivo no existe."); }
Capturas (System.UnauthorizedAccessException ex)
{ MessageBox.Show("Lo sentimos, pero no tienes suficientes privilegios."); }
Catch (Exception ex)
{ MessageBox.Show(ex.message); }
Resumen de la lección
■ Los tipos de referencia contienen la dirección de datos en lugar de los datos reales.
■ Cuando copia un tipo de valor, una segunda copia del valor es creado. Cuando copia un tipo de
referencia, sólo el puntero es copiado. Por lo tanto, si copia una referencia- encia tipo y, a
continuación, modifique la copia, la copia y el original se cambian las variables.
■ El .NET Framework incluye un gran número de tipos de referencia incorporada que puede
utilizar directamente o utilizar para construir tus propios tipos.
■ Lascadenas son inmutables; utilizar la clase StringBuilder para crear una cadena de forma
dinámica.
■ Utilice secuencias de lectura y escritura a los archivos, la memoria y la red.
■ Utilice la cláusula catch dentro de bloques try para filtrar excepciones por tipo. Cierre y dis-
plantean de nonmemory recursos en la cláusula final de un bloque Try.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba tus conocimientos de la información
Les- hijo 2, "Uso de los tipos de referencia común." Las preguntas también están disponibles en el
CD complementario si prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de respuesta es
correcta o no se encuentran en la sección "Respuestas" al final del libro.
1. Cuales de los siguientes son tipos de referencia? (Seleccione todos los que correspondan).
A. Los tipos declarados Nullable
B. Cadena
C. Excepción
D. Todos los tipos derivados de System.Object
2. ¿Cuál es el orden correcto de cláusulas Catch cuando el manejo de diferentes tipos de
excepción?
A. Orden de más general a más específico.
B. Orden de más probable a menos probable de ocurrir.
C. Ordenar desde el más específico al más general.
D. Orden de menos probable que con mayor probabilidad de ocurrir.
3. Cuándo se debe utilizar la clase StringBuilder en lugar de la clase String?
A. Cuando se construye una cadena de cadenas más cortas.
B. Cuando se trabaja con datos de texto de más de 256 bytes.
C. Cuando desea buscar y reemplazar el contenido de una cadena.
D. Cuando una cadena es un tipo de valor.
4. ¿Por qué debe cerrar y disponer de recursos en un bloque finally en lugar de un
Bloque catch?
A. Se le evita tener que repetir la operación en cada captura.
B. Ejecutar bloques finally si o no se produce una excepción.
C. El compilador genera un error si los recursos no están dispuestos en el finalmente
Bloque.
D. No puede disponer de los recursos en un bloque Catch.
Lección 3: Crear clases
En los lenguajes orientados a objetos, el grueso del trabajo deberá realizarse dentro de los objetos.
Pero todas las aplicaciones más sencillas requieren construir uno o más clases personalizadas, cada
una con varias propiedades y métodos que se utilizan para realizar tareas relacionadas con ese
objeto. Esta lección explica cómo crear clases personalizadas.
¿Qué es la herencia?
El .NET Framework tiene miles de clases y cada clase tiene muchos métodos y propiedades
diferentes. El seguimiento de todas estas clases y miembros sería imposible si el .NET Framework
no se ejecutaron muy coherente. Por ejemplo, cada clase tiene un método ToString que realiza
exactamente la misma tarea--verting una instancia de la clase en una cadena. Asimismo, muchas
clases admiten los mismos operadores, tales como la comparación de dos instancias de una clase
para la igualdad.
Esta coherencia es posible a causa de la herencia y las interfaces (descrito en la siguiente
sección). Utilizar la herencia para crear nuevas clases a partir de otras existentes. Por ejemplo,
aprenderá en el Capítulo 6, "Gráficos", que la clase Bitmap hereda de la clase Image y se
extiende por la adición de funcionalidad. Por lo tanto, se puede utilizar una instancia de la clase
Bitmap de la misma manera que puede utilizar una instancia de la clase Image. De cualquier
modo, la clase Bitmap proporciona métodos adicionales que le permiten hacer más con imágenes.
Puede crear fácilmente una excepción personalizada heredando de la clase System.Application-
excepción, como se muestra aquí:
// C#
La clase System.ApplicationException DerivedException :
{
Anulación pública string mensaje
{
Get { return "se produjo un error en la aplicación."; }
}
}
Puede lanzar y agarrar la nueva excepción porque la clase personalizada hereda esa conducta de su
clase base, como se muestra aquí:
// C#
Pruebe
{
Nueva DerivedException throw();
}
Capturas (DerivedException ex)
{
Console.WriteLine("Fuente: {0}, error: {1}", ex.Source, ex.message);
}
4. Escribir código para cada uno de los métodos de la interfaz. En este ejemplo, puede escribir
código en el método Dispose para liberar los recursos que tenía asignados.
La tabla 1-6 muestra las interfaces utilizadas más comúnmente en el .NET Framework.
Tabla 1-6 interfaces de uso común
Clase Descripción
IComparable implementado por tipos cuyos valores pueden ser ordenado;
por ejemplo, las clases numéricas y de
cadena. IComparable es necesaria para la ordenación.
IDisposable Demultas métodos para eliminar manualmente de un objeto. Esta
interfaz es importante para grandes objetos que consumen
recursos, o los objetos que bloquean el acceso a recursos tales
como bases de datos.
IConvertible permite una clase que se va a convertir en un tipo base,
como Boolean,
Byte, Doble, o String.
ICloneable admite copiar un objeto.
IEquatable permite comparar a instancias de una clase para la igualdad. Por
ejemplo, si implementa esta interfaz, usted podría decir "si
(A == b)".
IFormattable le permite convertir el valor de un objeto en una cadena con
formato especial. Esto ofrece una mayor flexibilidad que la base
del método ToString.
Puede crear sus propias interfaces, demasiado. Esto es útil si necesita crear varias clases
personalizadas que se comportan de forma similar y se pueden utilizar indistintamente. Por
ejemplo, el código siguiente define una interfaz que contiene tres miembros:
// C#
Interfaz IMessage
{
// Enviar el mensaje. Devuelve True es un éxito, FALSE en caso contrario. bool
Send();
// El mensaje a enviar mensaje de
cadena { GET; set; }
// La Dirección Enviar a. cadena
dirección { GET; set; }
}
Si implementar esa interfaz en una clase nueva, Visual Studio genera la siguiente plantilla
para los miembros de la interfaz:
// C#
Clase IMessage EmailMessage :
{
Public bool Send()
{
Nueva excepción throw("La operación o método no está implementado.");
}
Si crea una clase personalizada y, posteriormente, decide que sería útil disponer de varias
clases con los mismos miembros, Visual Studio tiene un atajo para extraer una interfaz de una
clase personalizada. Simplemente siga estos pasos:
1. Haga clic con el botón secundario en la clase en Visual Studio 2005.
2. Haga clic en Refactorizar y, a continuación, haga clic en Extraer interfaz.
3. Especifique el nombre de la interfaz, seleccione los miembros públicos que deben
formar la inter- cara y, a continuación, haga clic en Aceptar.
Las clases pueden implementar varias interfaces. Por lo tanto, una clase puede implementar
la interfaz IComparable y IDisposable.
Punta del examen tipos genéricos son nuevos en .NET 2.0, y probablemente verá
un número inusualmente grande de preguntas acerca de los genéricos en el examen.
Como puede ver, la clase Obj tiene dos miembros del tipo Object. La clase gen tiene dos
miembros de tipo T y U. El código de consumo determinará los tipos para T y U.
Dependiendo de cómo consumir el código utiliza la clase gen, T y U puede ser una cadena,
un int, una clase personalizada, o cualquier combinación de los mismos.
Hay una gran limitación para la creación de una clase genérica: código genérico sólo es válido
si va a compilar para cada posible instancia construida del genérico, ya sea un Int, una cadena,
o de cualquier otra clase. Básicamente, usted está limitado a las capacidades de la base
de clase de objeto al escribir código genérico. Por lo tanto, usted puede llamar al método
ToString o
Método GetHashCode dentro de su clase, pero no puede utilizar el signo + o el operador >.
Estas mismas restricciones no se aplican a los consumidores porque el código código de
consumo ha declarado un tipo para el genérico.
Public T max()
{
Si (t2.CompareTo(t1) < 0)
¿Qué es un evento?
Un evento es un mensaje enviado por un objeto para indicar la ocurrencia de una acción. La
acción puede ser causada por la interacción del usuario, como hacer clic con el ratón, o podría
ser reaccionará por algún otro programa de lógica. El objeto que genera el evento se conoce
como remitente del evento. El objeto que captura el evento y responde a ella se llama
el receptor de eventos.
En caso de que la comunicación, el remitente del evento no sabe qué objeto o método recibirá
los eventos que provoca. Lo que se necesita es un intermediario (o puntero-como el
mecanismo) entre la fuente y el receptor. El marco de trabajo .NET- define un tipo especial
(delegado) que proporciona la funcionalidad de un puntero a función.
¿Qué es un delegado?
Un delegado es una clase que puede contener una referencia a un método. A diferencia de
otras clases, una clase del delegado tiene una firma, y puede contener referencias a los
métodos que coinciden con su firma. Un delegado es equivalente a un puntero a función con
seguridad o una devolución de llamada. Mientras los delegados tienen otros usos, la discusión
se centra en la funcionalidad de gestión de eventos de delegados. Una declaración de delegado
es suficiente para definir una clase de delegado. La declaración proporciona la firma del
delegado, y common language runtime proporciona la aplicación. En el ejemplo siguiente se
muestra una declaración de delegado de evento:
// C#
Public void AlarmEventHandler delegado(object sender, EventArgs e);
Cómo responder a un
evento
Usted debe hacer dos cosas para responder a un evento:
■ Crear un método para responder al evento. El método debe coincidir con la firma del
delegado. Normalmente, esto significa que debe devolver void y aceptar dos parámetros:
un objeto EventArgs y (o una clase derivada). El siguiente código muestra esto:
// C#
Private void button1_Click(object sender, EventArgs e)
{
// Código de Método
}
■ agregarel controlador de eventos para indicar qué método debe recibir eventos, como
demuestra el código siguiente:
// C#
Este.button1.Click += new System.EventHandler(this.button1_Click);
El .NET Framework 2.0 incluye una nueva versión genérica del tipo EventHandler.
// C#
Si (MyEvent != null)
MyEvent(este, EventArgs.Empty); e =
Si (controlador != null)
{
// Invoca los delegados.
controlador(esto, e);
}
// Nota que C# comprobaciones para determinar si el controlador es nulo.
// Esto no es necesario en Visual Basic
Además, se puede derivar una clase personalizada de EventArgs si necesita pasar infor-
mación al controlador de eventos.
Sin el atributo Serializable, una clase no es serializable. Asimismo, el código siguiente utiliza
atributos para declarar que necesita leer el archivo C:\boot.ini. A causa de este atributo, el
tiempo de ejecución generará una excepción antes de la ejecución si carece el speci- zos
privilegio:
// C#
Utilizando
System;
Utilizando System.Security.Permissions.
[General:FileIOPermissionAttribute(SecurityAction.RequestMinimum, Read=@"C:\boot.ini")]
DeclarativeExample namespace
{
La clase Class1
{
[STAThread]
Static void main(String[] args)
{
Console.WriteLine("Hello, World!");
}
}
}
// C#
Administrador público(string _FirstName, LastName, cadena _int _edad, sexos _el
género, la cadena _phoneNumber, cadena _officeLocation)
: Base (_FirstName, LastName, __edad, _sexo)
{
PhoneNumber = _phoneNumber;
OfficeLocation = _officeLocation;
}
// C#
Anulación pública string ToString()
{
Volver base.ToString() + " " + phoneNumber + " " + officeLocation;
}
7. Modificar el método principal para crear un objeto Manager en lugar de un objeto person.
Vuelva a ejecutar la aplicación para comprobar que funciona correctamente.
En este ejercicio vamos a crear una clase que responde a un evento de temporizador.
1. Con Visual Studio, cree un nuevo proyecto de aplicación de formularios Windows Forms.
Nombre del proyecto TimerEvents.
2. Agregar un control ProgressBar al formulario, como se muestra en la figura 1-2.
4. En el diseñador, ver las propiedades del formulario. A continuación, ver la lista de eventos.
Haga doble clic en el evento Load para crear automáticamente un controlador de eventos que
se ejecutan la primera vez que el formulario es inicializado. Dentro del método, inicializar
el objeto de temporizador, establezca el intervalo de un segundo, crear un controlador de
eventos para el evento Tick, e iniciar el temporizador. En el ejemplo de código siguiente se
muestra esto:
// C#
Private void Form1_Load(object sender, EventArgs e)
{
T = new System.Windows.Forms.Timer();
T.Intervalo = 1000;
T.Tick += new EventHandler(t_Tick);
T.Start();
}
// C#
Void t_Tick(object sender, EventArgs e)
{
ProgressBar.Value += 10;
6. Ejecutar la aplicación para comprobar que responde al evento timer cada segundo.
Resumen de la lección
■ Utilizar la herencia para crear nuevos tipos sobre la base de las ya existentes.
■ Utilizar interfaces para definir un conjunto común de miembros que deben ser aplicadas
por los tipos relacionados.
■ clases parciales dividir una definición de clase en varios archivos de código fuente.
■ Eventos le permiten ejecutar un método especificado cuando algo ocurre en una dife-
rentes sección de código.
■ utilizar atributos para describir ensamblados, tipos y miembros.
■ Utilice el atributo TypeForwardedTo para pasar un tipo de clase de una biblioteca a otra.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba su conocimiento de la información
en la lección 3, "Construyendo clases." Las preguntas también están disponibles en el CD
complementario si prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final
del libro.
1. Cuál de las siguientes afirmaciones es verdadera? (Seleccione todos los que correspondan).
A. Define un contrato de herencia entre tipos.
B. Interfaces definen un contrato entre tipos.
C. La herencia se deriva de un tipo de un tipo base.
D. Interfaces derivar un tipo de un tipo base.
2. Cuales de los siguientes son ejemplos de tipos genéricos incorporada? (Seleccione todos
los que correspondan).
A. Nullable
B. Valor booleano
C. EventHandler
D. System.Drawing.El punto
3. Se está creando una clase genérica y necesita deshacerse de los objetos genéricos.
¿Cómo se puede hacer esto?
A. Llame al objeto. método Dispose.
B. Implementar la interfaz IDisposable.
C. Derive de la clase genérica de la clase IDisposable.
D. Utilizar restricciones para exigir el tipo genérico para implementar
la IDisposable
Interfaz.
4. Se ha implementado un delegado de eventos de una clase, pero cuando intenta fijar un
procedimiento de evento obtendrá un error de compilador que no hay sobrecarga que coincida
con el delegado. ¿Qué ha sucedido?
A. La firma del procedimiento de evento no coincide con la definida por el
delegado.
B. El procedimiento de evento es declarado compartida/estática, pero debe ser
un miembro de la instancia.
C. Escribió incorrectamente el nombre de procedimiento de evento cuando se
conecta al delegado.
D. La clase fue creada en un idioma diferente.
// C#
Int i =
1;
Double d = 1.0001;
D = i; // Conversión permitida.
// C#
Int i = 123;
O = object (Objeto) i;
Unboxing ocurre si asigna a un objeto de referencia a un tipo de valor. El siguiente ejem- plo
demuestra unboxing:
// C#
Objeto o = 123;
Int i = (int) o;
Es mejor crear varios procedimientos sobrecargados de uno que acepta un objeto Argumento.
■ Utilizar genéricos siempre que sea posible en lugar de aceptar los argumentos del objeto.
■ El override ToString, Igual a, y GetHash miembros virtuales al definir estructuras.
Definir los operadores de conversión le permite asignar directamente desde un tipo de valor a su
tipo personalizado. Utilice la ampliación/ Palabra clave implícito para las conversiones que no
pierda preci- sión; utilice el estrechamiento/ Palabra clave para las conversiones explícitas que
podrían perder precisión. Por ejemplo, la siguiente estructura define que permiten a los operadores
de asignación y de valores enteros:
// C#
Struct TypeA
{
El valor int pública;
El tipo anterior también invalida ToString para realizar la conversión a cadena sin boxeo. Ahora
puede asignar números enteros al tipo directamente, como se muestra aquí:
// C#
TypeA a; int i;
// Conversión de ampliación está bien implícito. a =
42; // en lugar de a.Value = 42
// Conversión de restricción debe ser explícita. i = (int); // en
lugar de i = valor.
Console.WriteLine("a = {0}, i = {0}",.ToString(), i.ToString());
Métodos simplemente arrojar una excepción-Visual Studio agrega automáticamente código para
lanzar una excepción para cualquier métodos de conversión que no se implementen.
Después de implementar IConvertible, el tipo personalizado puede ser convertido con la apre-
ciación de la clase System.Convert como se muestra aquí:
// C#
TypeA a; b; bool
A = 42;
// Convertir utilizando ToBoolean. b =
Convert.ToBoolean(a);
Console.WriteLine("a = {0}, b = {1}",.ToString(), b.ToString());
Laboratorio: realizar
conversiones de forma segura
Los siguientes ejercicios muestran cómo evitar problemas con las conversiones implícitas para que
los programas funcionen de manera predecible. Si usted encuentra un problema completando una
exer- cise, los proyectos terminados están disponibles en el CD en la carpeta de código.
Ejercicio 1: Examinar la Conversión implícita
En este ejercicio, examinará la conversión para determinar qué número de tipos permiten la
conversión implícita.
1. Crear una nueva aplicación de consola en Visual Studio.
2. Declarar instancias de tres tipos de valores: Int16, Int32, y doble. En el ejemplo de código
siguiente se muestra esto:
// C#
Int16 i16 = 1; Int32
i32 = 1; doble db =
1;
3. Intento de asignar a cada variable para todos los demás, como demuestra el ejemplo de código
siguiente.
// C#
I16 = i32.
I16 = db;
I32 = i16;
I32 = db;
Db = i16.
Db = i32.
4. Intento de construir su proyecto. Que las conversiones implícitas no permitir que el
compilador, y por qué?
Ejercicio 2: Activar la opción Estricta (sólo Visual Basic)
En este ejercicio, que es sólo para los desarrolladores que utilizan Visual Basic, podrá modificar
las opciones del compilador y, a continuación, reconstruir el proyecto creado en el ejercicio 1.
Resumen de la lección
■ El .NET Framework se puede convertir automáticamente entre tipos integrados. Ampliando las
conversiones ocurren implícitamente en Visual Basic y C#. Estrechamiento conver- siones
requieren conversión explícita en C#, mientras que Visual Basic permite conversiones de
restricción por defecto.
■ El boxeo permite cualquier tipo a ser tratada como un tipo de referencia.
■ Debe aplicar específicamente los operadores de conversión para activar la conversión de tipos
personalizados.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba tus conocimientos de la información
Les- hijo 4, "Conversión entre tipos." Las preguntas también están disponibles en el CD de iones
complementaria si prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final del
libro.
■ La conversión le permite comparar y copiar los valores entre dos tipos diferentes. La
conversión implícita ocurre automáticamente y se comporta de manera diferente en Visual Basic y
C#. C# permite la conversión implícita sólo para las conversiones de restricción, donde no hay
información podría perderse. Visual Basic permite la conversión implícita tanto para el
estrechamiento y conversiones de ampliación. Cuando los valores se convierten en un tipo de
valor a un tipo de referencia, se considera el boxeo. Unboxing ocurre si asigna a un objeto de
referencia a un tipo de valor.
Términos clave
¿ Sabes lo que significan estos términos clave? Puede verificar sus respuestas mediante la
búsqueda de los términos en el glosario al final del libro.
■ El boxeo
■ emitidos
■ restricción
■ contrato
■ excepción
■ excepciones de filtrado
■ La recolección de basura
■ tipo genérico
■ heap
■ interface
■ estrechamiento
■ tipo Nullable
■ La firma
■ stack
■ estructura
■ unboxing
■ ampliación
Escenario de caso
En el caso siguiente escenario, tendrá que aplicar lo que ha aprendido acerca de los tipos. Usted
puede encontrar las respuestas a estas preguntas en la sección de "respuestas" al final de este libro.
Caso práctico: diseño de una aplicación
Recientemente usted ha aceptado un trabajo como desarrollador de aplicaciones internas en el
departamento de tecnología de la infor- mación de una empresa empresa del sector sanitario. Su
primera tarea consiste en diseñar una aplicación interna que los empleados vayan a utilizar para
gestionar la información sobre clientes (a quien todo el mundo llama "abonados"), sus planes
actuales, medicamentos y médicos elegidos. Contestar las preguntas de su jefe acerca de sus
opciones de diseño.
1. Necesitamos gestionar información sobre ambos abonados y médicos. ¿Cómo se puede hacer
esto? Tendrá usted una clase para ambos, dos clases separadas, o qué?
2. Nuestros empleados necesitan para buscar grupos de abonados o médicos. Por ejemplo, si un
médico se jubila, necesitamos contactar con todos los abonados de ese doctor y ayudarlos a
encontrar un nuevo médico. Asimismo, estamos en contacto con los médicos anualmente para
renovar sus contratos. ¿Cómo se puede almacenar un grupo de suscriptores o médicos en su
aplicación?
3. Una de las tareas que su aplicación va a realizar es la generación de etiquetas de correo para
grupos de abonados o médicos. ¿Hay alguna manera de que usted puede escribir un único método
que controlará las direcciones para ambos abonados y los médicos? Cómo se va a implementar
esto?
4. La confidencialidad de nuestra información es extremadamente importante para nosotros.
Nuestra base de datos devel- oper va a restringir los permisos en la base de datos para evitar que
usuarios no autorizados obtengan acceso. Si los privilegios de un usuario son rechazadas, me
gustaría que indique al usuario que se ponga en contacto con su administrador para obtener acceso.
Cómo va a manejar si una consulta de base de datos es rechazado por falta de privilegios?
Prácticas recomendadas
Que le ayudarán a dominar los objetivos del examen se presenta en este capítulo, se com- pleta las
siguientes tareas.
Administrar datos en una aplicación de .NET
Framework usando .NET Framework 2.0 Tipos de
sistema
Para esta tarea, se deben completar un mínimo de prácticas 1 y 2. Si desea una mejor comprensión
de cómo los genéricos realizar en el mundo real, la práctica completa 3.
■ prácticas 1 Abra el último proyecto que ha creado, y añadir excepciones a su código. A
menos que el rendimiento es una prioridad mayor que la fiabilidad, todo el código fuera- lado de
declaraciones de tipo de valor debe estar en un bloque Try.
■ La Práctica 2 Crear una lista vinculada clase genérica que permite crear una cadena de
diferentes tipos de objetos.
■ La Práctica 3 crear dos clases con funciones idénticas. Use genéricos para la primera clase,
y el reparto de la segunda clase para los tipos de objeto. Crear un bucle que utiliza la clase a lo
largo de miles de iteraciones. Momento de la actuación de ambos el genérico
La clase y la clase base Object -para determinar cuál funciona mejor. Puede utilizer
DateTime.Now.garrapatas para medir el tiempo.
Capítulo 2
Entrada/Salida (I/O)
En este capítulo, aprenderá a trabajar con la entrada/salida (E/S) en el Microsoft .NET Framework.
Los elementos básicos del sistema de E/S incluyen el acceso a archivos y carpetas en el sistema de
archivos, trabajar con secuencias de lectura y escritura, utilizando compresión de arroyos, y usar el
almacenamiento aislado.
❑ clase DeflateStream
❑ GZipStream class
Antes de empezar
Para completar las lecciones de este capítulo, debe estar familiarizado con Microsoft Visual
Mundo Real
Shawn Wildermuth
He escrito cientos, si no miles de líneas de código y siempre vuelvo al sistema
de E/S para mucho . La sección de E/S de .NET Framework proporciona
ayuda para realizar una multitud de tareas. Mucho de lo que hay en el sistema
de E/S es la base para otras partes del Marco, así como para los productos de
terceros. Aprender los conceptos básicos de cómo funcionan los archivos y
arroyos ha hecho haciendo mi trabajo mucho más fácil.
Lección 1: Explorar el sistema de archivos
En el trabajo diario de los desarrolladores, una de las tareas más comunes es la de trabajar con el
sistema de archivos. Esta tarea incluye la navegación y recopilar información acerca de las
unidades, carpetas y archivos, así como esperando cambios que ocurren en el sistema de archivos.
La clase FileSystemInfo proporciona la funcionalidad básica para todos archivo informativo Sys-
tem clases. La tabla 2-1 muestra las propiedades FileSystemInfo más importantes.
Tabla 2-1 FileSystemInfo Propiedades
Nombre Descripción
Obtiene o establece FileAttributes atributos del archivo o directorio actual.
CreationTime obtiene o establece el tiempo que el archivo o
directorio actual fue creado.
Determina si existe el archivo o directorio.
Extensión obtiene una representación de cadena de la extensión del
archivo o directorio.
FullName obtiene la ruta de acceso completa del archivo o directorio.
LastAccessTime obtiene o establece el momento en que el fichero o directorio
fue visitada. LastWriteTime obtiene o establece el momento en que el
fichero o directorio fue el último escrito. Name Obtiene el
nombre simple para el archivo o directorio. Para un archivo, este
Es el nombre del directorio. Para un directorio, este es el
Último nombre de directorio en la jerarquía de directorios.
Nombre Descripción
Eliminar: elimina el archivo o directorio del sistema de archivos
Actualizar Actualiza los datos en la clase con la informa- ción
más actual desde el sistema de archivos
Nombre Descripción
Directory obtiene el objeto DirectoryInfo que representa el directorio que
este archivo se almacena dentro de
Nombredirectorio Obtiene el nombre del directorio que este archivo se almacena dentro de
IsReadOnly obtiene o establece el indicador que determina si el archivo
puede ser modificado o eliminado
Length obtiene la longitud del archivo
Nombre Descripción
AppendText crea un nuevo StreamWriter que permitirá Anexar al archivo de
texto. Consulte la lección 2 para obtener más información.
CopyTo hace una copia del archivo en una nueva ubicación.
Crear crea un archivo basado en la información del archivo actual.
Crea un nuevo CreateText StreamWriter y un nuevo archivo para escribir el texto.
Ver Lección 2 para obtener más información.
Descifrar descifra un archivo cifrado por el usuario actual.
Cifrar cifra un archivo, de modo que sólo el usuario actual puede descifrar
la información dentro del archivo.
MoveTo mueve el archivo a una nueva ubicación.
Abrir abre el archivo con privilegios específicos (lectura, lectura y escritura, y
así sucesivamente).
OpenRead abre el archivo con acceso de sólo lectura.
OpenText abre el archivo y devuelve un StreamReader para permitir la lectura
de texto dentro del archivo.
OpenWrite abre el archivo con acceso de sólo escritura.
Replace reemplaza un archivo con el que se describe en la FileInfo actual
Objeto.
Cómo obtener información acerca de un archivo
Para obtener información acerca de un archivo específico, siga este procedimiento:
■ Crear un nuevo objeto FileInfo utilizando la ruta de acceso al archivo.
■ acceder a las propiedades del objeto FileInfo.
Por ejemplo, puede comprobar si un archivo existe llamando al objeto FileInfo existe
La propiedad, tal como se muestra en el siguiente código:
// C#
OurFile = new FileInfo FileInfo(@"c:\boot.ini ");
Si (ourFile.Existe).
{
Console.WriteLine("Filename : {0}", ourFile.Nombre); Console.WriteLine("ruta
: {0}", ourFile.FullName);
}
Utilizando el objeto FileInfo de esta forma permite que el código para interrogar la información
acerca de un archivo en el sistema de archivos.
// C#
OurFile = new FileInfo FileInfo(@"c:\boot.ini");
OurFile.CopyTo(@"c:\boot.bak");
El mismo procedimiento se utiliza para mover y crear archivos. Una vez que tenga una validez
Objeto FileInfo, puede acceder a todas sus propiedades y llamar a sus métodos.
Nombre Descripción
Obtiene el principal objeto DirectoryInfo al directorio padre del
directorio actual en la jerarquía del directorio
Obtiene la raíz raíz parte de la ruta del directorio como una cadena
Nombre Descripción
Crear crea el directorio descrito en el actual DirectoryInfo Objeto
CreateSubdirectory crea un nuevo directorio como un niño directorio del
directorio actual en la jerarquía del directorio
GetDirectories DirectoryInfo recupera una matriz de objetos que
representan los subdirectorios del directorio actual.
GetFiles Reintentoves una matriz de objetos FileInfo que representa
todos los archivos en el directorio actual.
GetFileSystemInfos FileSystemInfo recupera una matriz de objetos que
representan los archivos y subdirectorios del directorio
actual
MoveTo mueve el directorio actual a una nueva ubicación
// C#
DirectoryInfo ourDir = new DirectoryInfo(@"c:\windows");
Los modelos de clase DriveInfo una unidad y proporciona métodos y propiedades para consultar
la información de la unidad. Utilice DriveInfo para determinar qué unidades están disponibles y
qué tipo de unidades son. También puede realizar consultas para determinar la capacidad y el
espacio libre disponible en la unidad. La tabla 2-7 muestra las propiedades DriveInfo más
importantes.
Tabla 2-7 DriveInfo Propiedades
Nombre Descripción
AvailableFreeSpace obtiene la cantidad de espacio disponible en la unidad. La
cantidad puede ser diferente de la cantidad devuelta
por TotalFreeSpace (descrita más adelante en esta tabla), en
función de las cuotas de disco.
DriveFormat obtiene el formato de la unidad, como NTFS o FAT32.
Nombre Descripción
DriveType Obtiene el tipo de unidad en la forma de la DriveType enumer-
ción (que se describe en la siguiente sección).
IsReady Obtiene el estado de la unidad, indicando si está preparada
para ser visitada.
Name Obtiene el nombre de la unidad.
RootDirectory obtiene un objeto DirectoryInfo que representa el directorio
raíz de la unidad.
TotalFreeSpace obtiene la cantidad total de espacio libre en el disco.
TotalSize obtiene el tamaño total de la unidad.
VolumeLabel obtiene o establece la etiqueta de la unidad. Podría establecerse
sólo en unidades que no sean de sólo lectura.
Nombre Descripción
GetDrives un método estático (o compartido en Visual Basic) que
devuelve todas las unidades en el sistema actual.
La enumeración DriveType
La enumeración DriveType proporciona los posibles tipos de unidades que pueden ser
representados por un objeto DriveInfo. La tabla 2-9 muestra los miembros de la enumeración
DriveType.
Tabla 2-9 DriveType miembros
Nombre Descripción
Una unidad óptica de CD-ROM. Puede ser un CD-ROM, DVD, y así
sucesivamente.
Arreglado un disco fijo.
Red una unidad asignada de red.
Nombre Descripción
NoRootDirectory una unidad que no tiene un directorio raíz.
Ram una unidad R AM.
Una unidad extraíble que tiene medios extraíbles.
Desconocido El tipo de unidad no pudo ser determinada.
// C#
DriveInfo[] unidades = DriveInfo.GetDrives();
Todos los tipos de unidades ópticas (CD, CD/R, DVD, DVD/R, etcétera) están
marcados como DriveInfo.CDRom.
Nombre Descripción
Toma una ruta ChangeExtension y devuelve una nueva ruta con la
extensión del nombre de archivo cambiado. (Tenga en
cuenta que sólo la cadena de la ruta de los cambios, no la
extensión de nombre de archivo).
Cosechadora Combina dos cadenas de ruta de acceso
compatibles. GetDirectoryName devuelve el nombre del directorio en la ruta
especificada. GetExtension devuelve el nombre de la extensión del
archivo especificado Ruta.
Nombre Descripción
IncludeSubdirectories obtiene o establece un indicador de si la
observación de un directorio es incluir
subdirectorios o sólo en el directorio especificado
en la propiedad Path.
NotifyFilter obtiene o establece el tipo de cambios que
observar. Por defecto, todos los cambios (crear,
suprimir, renombrar archivos y modificaciones)
son notificados.
Ruta obtiene o establece la ruta de acceso al directorio en
el monitor.
Nombre Descripción
WaitForChanged método sincrónico para ver un directorio para los
cambios y para devolver una estructura que con-
mantiene todos los cambios
Nombre Descripción
Se produce cuando cambia un archivo o directorio ha
cambiado en el directorio observados
Se produce cuando se crea un archivo o directorio ha sido
creado en el directorio observados
Eliminado Se produce cuando un archivo o directorio ha sido
eliminado en el directorio observados
Renombrado Ohccurs cuando un archivo o directorio ha sido
cambiado en el directorio observados
// Registrarse para
eventos watcher.Creada
+=
Nueva FileSystemEventHandler(watcher_changed);
Watcher.Deleted +=
Nueva FileSystemEventHandler(watcher_changed);
// Inicio viendo
watcher.EnableRaisingEvents = true;
// Controlador de eventos
Static void watcher_cambiado(object sender,
FileSystemEventArgs e)
{
Console.WriteLine("directorio cambiado({0}): {1}", e.ChangeType,
E.FullPath);
}
// C#
// Ir a través de los subdirectorios
// Recursivamente
(Foreach DirectoryInfo subDir en dir.GetDirectories())
{
ShowDirectory(subDir);
}
6. En el método Main, escribir código para crear una nueva instancia de la clase
DirectoryInfo para el directorio del sistema y utilizarlo para llamar al método ShowDirectory
nuevo. Por ejemplo, el código siguiente:
// C#
DirectoryInfo dir = new DirectoryInfo(Entorno.SystemDirectory); ShowDirectory(dir);
7. Generar el proyecto y resolver cualquier error. Compruebe que la aplicación de consola suc-
logre enumera todos los archivos en el directorio del sistema (Environment.SystemDirectory).
Ejercicio 2: observar cambios en el sistema de archivos
En este ejercicio, podrá observar los cambios en el sistema de archivos para todos los archivos que
terminan con la La extensión .ini.
1. Crear una nueva aplicación de consola denominada FileWatchingDemo.
2. Importar el espacio de nombres System.IO en el nuevo archivo.
3. Crear una nueva instancia de la clase FileSystemWatcher, especificando el sistema di-
rectorio. Por ejemplo, podría usar el siguiente código:
// C#
Watcher FileSystemWatcher =
Nueva(FileSystemWatcher entorno.SystemDirectory);
4. Modificar las propiedades del vigilante del sistema de archivos para buscar sólo para
archivos .ini, buscar a través de todos los subdirectorios, y aceptar los cambios sólo si los atributos
del archivo cambia o si el tamaño del archivo cambia. El código podría tener este aspecto:
// C#
Watcher.Filter = "*.ini"; watcher.IncludeSubdirectories =
true; watcher.NotifyFilter =
| NotifyFilters NotifyFilters.Attributes.Tamaño;
5. Para ver los cambios, agregue un controlador de eventos para el evento Changed de su objeto
Watcher.
Por ejemplo, podría usar el siguiente código:
// C#
Watcher.Cambio +=
Nueva FileSystemEventHandler(watcher_changed);
6. Necesitará el siguiente método que el evento Changed se va a llamar. Dentro de este método,
escribir en la consola el nombre del archivo cambiado. El código podría tener este aspecto:
// C#
Static void watcher_cambiado(object sender, FileSystemEventArgs
e)
{
Console.WriteLine("cambiado: {0}", e.FullPath);
}
8. Generar el proyecto y resolver cualquier error. Compruebe que la aplicación de consola suc-
logre informes cuando los atributos de cualquier archivo .ini en el directorio del sistema cambie o
cuando cambia el tamaño del archivo.
Resumen de la lección
■ El FileInfo, DirectoryInfo DriveInfo , y las clases se pueden usar para enumerar y
revisar las propiedades de los objetos del sistema de archivos.
■ La clase Path puede ser utilizada para interrogar una ruta del sistema de archivos
y debe ser utilizado en lugar de analizar la cadena manualmente.
■ La clase FileSystemWatcher puede utilizarse para supervisar el sistema de
archivos para los cambios como adiciones, eliminaciones y renamings.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba tus conocimientos de la información
Les- hijo 1, "Cómo navegar en el sistema de archivos." Las preguntas también están disponibles en
el CD de iones complementaria si prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final del
libro.
1. Que son medios aceptables para abrir un archivo de escritura? (Seleccione todos los que
correspondan).
A.
// C#
File.Open("somefile.txt", FileMode.Create);
B.
// C#
File.Open("somefile.txt", FileMode.Create, FileAccess.Write);
C.
// C#
File.Open("somefile.txt", FileMode.Create, FileAccess.Read);
D.
// C#
Archivo = new FileInfo FileInfo("archivo.txt");
File.Open(FileMode.Create);
2. Cuál de los siguientes tipos de cambios que puede ser detectado por
el archivo- SystemWatcher? (Seleccione todos los que correspondan).
A. Nuevos archivos
B. Los nuevos directorios
C. Archivos modificados D. Archivos cambiados E. Ninguno
3. El código siguiente cambia la extensión del archivo. (True o False).
// C#
Cadena ourPath = @"c:\boot.ini";
Ruta.ChangeExtension(ourPath, "bak");
A. True
B. False
Lección 2: Lectura y escritura de archivos
Lectura y escritura de archivos son dos de las tareas más comunes en el mundo del de-
sarrollo. Como un desarrollador de .NET, usted necesita saber cómo leer y escribir
archivos. .NET Framework facilita la realización de estas tareas.
Comprensión arroyos
Las secuencias son una forma común de tratar ambos secuencial y acceso aleatorio a los datos
dentro de .NET Framework. Las secuencias son utilizadas en diferentes partes del marco.
Comienzan con una clase abstracta (por medio de la palabra clave MustInherit en Visual
Basic) que proporciona la interfaz básica y aplicación para todos los flujos en el marco.
Algunas de las propiedades y métodos de la clase Stream se muestran en la tabla 2-14 y la
tabla 2-15, respectivamente.
Tabla 2-14 propiedades de secuencia
Nombre Descripción
CanRead determina si el stream es compatible con la
lectura. CanSeek determina si la secuencia admite la
función de búsqueda. CanTimeout determina si la secuencia
puede agotar el tiempo de espera. CanWrite determina si
la secuencia puede ser escrito. Length obtiene la
longitud (en bytes) de la secuencia.
Obtiene o establece la posición del cursor virtual para determinar
dónde en el arroyo la posición actual. El valor
de posición no puede ser mayor que el valor de
la longitud de la secuencia.
ReadTimeout obtiene o establece la secuencia de tiempo de espera para
las operaciones de lectura.
WriteTimeout obtiene o establece la secuencia de tiempo de espera para
las operaciones de escritura.
Nombre Descripción
Cerrar Cierra la secuencia y libera todos los recursos asociados con ella.
A ras Borra los buffers en el stream y obliga a cambios a escribir en
el sistema subyacente o dispositivo.
Leer Performs una lectura secuencial de un número especificado
de bytes desde la posición actual y actualiza la posición al final
de la lectura tras la finalización de la operación.
ReadByte Performs la lectura de un solo byte y actualiza la posición
moviendo por uno. Idéntico al llamar a Read para leer de un solo
byte.
Seek establece la posición dentro de la secuencia.
SetLength Specifies la longitud de la secuencia. Truncará la corriente si la
nueva longitud es menor que la longitud anterior y expandirá la
corriente si la verdad es lo contrario.
Escribir escribe la información en la secuencia como un número
de bytes y actualiza la posición actual para reflejar la nueva
posición de escritura.
WriteByte escribe un byte a la secuencia y actualiza la posición.
Idéntico al llamar a escribir con un solo
byte.
Todas las demás clases stream en el .NET Framework se derivan de la clase Stream.
Estas clases derivadas incluyen los siguientes:
■ FileStream (System.IO)
■ MemoryStream (System.IO)
■ CryptoStream (System.Security)
■ NetworkStream System.Net ()
■ GZipStream (System.Compression)
La razón por la que estas corrientes tienen una clase base común es que trabajar con
datos como un flujo es una manera común de trabajar con datos. Por aprender a trabajar
con una corriente en general, puede aplicar este conocimiento a cualquier tipo de flujo.
Por ejemplo, podría escribir un método simple para volcar el contenido de una
secuencia a la consola de la siguiente manera:
// C#
Static void DumpStream(Stream theStream)
{
// Mover la posición de la secuencia al principio
theStream.posición = 0;
Este código no importa qué clase de stream es enviado; puede tratar con cualquier secuencia
de la misma manera. Asimismo, anexar información a un arroyo puede hacerse en una com-
mon, como se muestra en este ejemplo:
/
/
C
#
Static void AppendToStream(Stream theStream, byte[]
datos)
{
// Mover la posición hasta el final
theStream.Posición = theStream.Length;
Las sencillas operaciones de archivo que el archivo clase admite son idénticas a las de la clase
FileInfo explicado en la Lección 1.
Además de estas clases, la clase MemoryStream es un especializado para manip ulating
stream- los datos en la memoria. Esta clase se utiliza a menudo para crear flujo de objetos en
memoria para optimizaciones.
Nombre Descripción
AppendAllText anexa una cadena especificada en un archivo existente,
también crea el archivo si no existe.
AppendText abre un archivo o crea un archivo nuevo si no existe
uno) y devuelve un StreamWriter que está dispuesta a
permitir que el texto se anexa al archivo.
Copy copia un archivo a un nuevo archivo. El nuevo archivo no
debe existir para
Copia sea exitosa.
Crear crea un nuevo archivo y devuelve un objeto FileStream.
CreateText crea o abre un archivo y devuelve un objeto
StreamWriter que está listo para tener el texto escrito
en ella.
Move mueve un archivo de un lugar a otro.
Nombre Descripción
Abrir Abre un archivo existente y devuelve un objeto
FileStream.
OpenRead abre un archivo existente y devuelve un FileStream de sólo
lectura Objeto.
OpenText abre un archivo existente y devuelve un objeto
StreamReader.
OpenWrite abre un archivo existente para escribir y devuelve
un StreamWriter Objeto.
ReadAllBytes abre un archivo, lee el contenido de ésta en una matriz
de bytes, y cierra el archivo en una operación atómica.
ReadAllLines abre un archivo, lee el contenido del mismo en una matriz
de
cadenas (Uno por línea) y cierra el archivo en una operación atómica.
ReadAllText abre un archivo, lee el contenido de ésta en una cadena,
y cierra el archivo en una operación atómica.
WriteAllBytes abre un archivo, escribe el contenido de una matriz de
bytes en ella (más escribir cualquier dato existente) y
cierra el archivo en una operación atómica.
WriteAllLines abre un archivo, escribe el contenido de una matriz de
cadenas en ella (sobrescribiendo los datos existentes),
y cierra el archivo en una operación atómica.
WriteAllText abre un archivo, escribe el contenido de una cadena en
ella (overwrit- ing cualquier dato existente) y cierra el
archivo en una operación atómica.
Nombre Descripción
CreateDirectory crea todos los directorios en un trazado suministrado
Eliminar Elimina un directorio especificado.
Existe determina si existe un directorio en el sistema de
archivos GetCreationTime devuelve la fecha y hora de creación de un
directorio GetCurrentDirectory devuelve un objeto DirectoryInfo para el
trabajo actual
Directorio de la aplicación
GetDirectories obtiene una lista de los nombres de los subdirectorios
en un directorio especificado.
GetDirectoryRoot devuelve el volumen de información y/o la raíz de un
directorio especificado.
GetFiles devuelve los nombres de los archivos de un directorio
GetFileSystemEntries devuelve una lista de subdirectorios y archivos en el
directorio especificado.
GetLastAccessTime devuelve el tiempo que un directorio especificado del último
acceso GetLastWriteTime devuelve el tiempo que un directorio especificado se
escribió último GetLogicalDrives obtiene una lista de unidades en el sistema
actual como cadenas con el
Patrón de "C:\"
GetParent obtiene el directorio padre del directorio especificado.
Move mueve un archivo o directorio (y su contenido) a un lugar
determinado
Establece el tiempo SetCreationTime un directorio específico fue creado
SetCurrentDirectory Establece el directorio especificado para el directorio
de trabajo actual para una aplicación.
SetLastAccessTime establece la última vez que se accedió a un directorio
SetLastWriteTime establece la última vez fue escrito para un directorio
Nombre Descripción
Leer Specifies que el archivo debe abrirse con acceso de
sólo lectura.
Escribir Especifica que el archivo debe abrirse para ser
escrito. No se puede leer el archivo, sólo se pueden
agregar.
ReadWrite especifica acceso completo al archivo para lectura o
escritura. Equiv alent- para combinar los valores de
lectura y escritura.
La enumeración FileMode
La enumeración FileMode proporciona a los miembros que especifican la forma en que un
archivo se ha abierto o creado. La tabla 2-19 muestra la mayoría de las FileMode miembros.
Tabla 2-19 FileMode miembros de enumeración
Nombre Descripción
Append abre un archivo y mueve el puntero en la clase
FileStream al final del archivo. Sólo puede utilizarse
con FileAccess.Write.
Crear crea un archivo nuevo. Si el archivo ya existe, se
sobrescribe.
CreateNew crea un archivo nuevo. Si el archivo ya existe, se
produce una excepción.
Abrir Abre un archivo existente. Si el archivo no existe, se
genera una excepción.
OpenOrCreate abre un archivo existente. Si el archivo no existe, se crea
un archivo nuevo.
Truncar abre un archivo existente pero vacía el archivo existente
de manera que su longitud es cero bytes.
Nombre Descripción
BaseStream obtiene la secuencia subyacente de que el lector está
escrito en CurrentEncoding obtiene la actual codificación usada para la
secuencia subyacente EndOfStream determina si el lector ha
encontrado el final de
La
secuen
cia
Nombre Descripción
Cerrar Cierra el lector y la secuencia subyacente
Peek devuelve el siguiente carácter en el arroyo sin mover
la posición actual del flujo
Read Lee el siguiente conjunto de caracteres en el
flujo ReadBlock lee el siguiente bloque de caracteres en
el flujo ReadLine lee la siguiente línea de caracteres en
el flujo
ReadToEnd lee todos los caracteres hasta el final de la secuencia
Cómo leer de un archivo
Abrir un archivo es bastante común. En su forma más simple, la apertura de un archivo
consiste en pedir la clase File para abrir una secuencia especificando la ruta de acceso al
archivo. Cuando se abre un archivo para leer su contenido, puede utilizar el miembro de
enumeración FileMode.Open para especificar un archivo existente, así
como FileAccess.Read para obtener acceso de sólo lectura a los archivos, como se ve en este
ejemplo de código:
// C#
= File FileStream
File.Open(@"C:\boot.ini", FileMode.Open, FileAccess.Read);
La clase StreamReader se destina a leer una secuencia como una cadena, no como una serie
de bytes. De esta manera, la StreamReader's métodos para devolver datos devuelven cadenas
o matrices de cadenas.
La clase File admite algunos métodos adicionales para hacer más simple para abrir un
archivo para lectura. En el ejemplo anterior, se ha creado un objeto FileStream y luego creó
un nuevo StreamReader. La clase File apoya la creación de un StreamReader directamente
con el método de texto abierto, como se ve en este fragmento de código:
/
/
C
#
Rdr StreamReader = File.OpenText(@"C:\boot.ini");
Console.Write(rdr.ReadToEnd();
Rdr.Close
();
Si todo lo que usted necesita hacer es leer todo el archivo, el archivo clase admite la lectura
del archivo en una única llamada al método, ocultar todos los detalles de la secuencia y reader
aplicación llamando a su método ReadAllText:
// C# Console.WriteLine(File.ReadAllText(@"C:\boot.ini");
Por lo tanto, si usted puede conseguir todo lo que necesite con el archivo de la clase método
ReadAllText, ¿por qué habría de utilizar estos otros métodos? La razón habitual es que usted
no necesita el archivo de texto completo. Este enfoque es especialmente útil si usted está
buscando un determinado fragmento de texto. Por ejemplo, en este fragmento de código,
puede extraer los datos, línea por línea y prueba para una cadena que coincide, y si la
encuentra, no necesitas cargar toda la cadena en la memoria:
// C#
Rdr StreamReader = File.OpenText(@"C:\boot.ini");
// Limpiar
rdr.Close();
Análisis de archivos con este método es especialmente útil cuando se busca a través de
archivos muy grandes.
Nombre Descripción
AutoFlush obtiene o establece un indicador que muestra si cada
llamada al método Write deben enjuagar los cambios
en la secuencia subyacente.
BaseStream obtiene la secuencia subyacente de que el lector está
leyendo. Obtiene la actual codificación codificación usada para la
secuencia subyacente. NewLine obtiene o establece una cadena
que contiene la cadena de terminador de línea.
Normalmente sólo se utiliza si es necesario cambiar la
cadena que ter-
Minates una línea
individual.
Nombre Descripción
Cerrar Cierra el escritor y la secuencia subyacente
Escribir escribe al arroyo
WriteLine escribe datos a la secuencia seguida por la cadena que
termi- coordenadas una línea individual
/
/
C
#
FileStream = file archivo.Create(@"c:\somefile.txt");
A diferencia del código para abrir un archivo para lectura, este código crea un archivo nuevo
con un objeto FileStream listo para ser escrito. Con el objeto FileStream en la mano, usted
puede escribir a la secuencia directamente, si así lo desea. Más a menudo, sin embargo, usted
deseará utilizar un objeto StreamWriter para escribir datos en el archivo nuevo, como se
muestra en este código:
// C#
Escritor StreamWriter = new StreamWriter(Archivo);
Writer.WriteLine("Hello");
writer.Close(), File.Close();
// C#
Escritor StreamWriter = File.CreateText(@"c:\somefile.txt");
Writer.WriteLine("Hello");
Writer.Close();
La clase File también soporta el método WriteAllText que escribe una cadena en un
nuevo archivo, como se muestra aquí:
// C#
Archivo.WriteAllText(@"c:\somefile.txt", "Hola");
Este proceso es sencillo, pero hay veces cuando necesite escribir en un archivo existen- tes.
Para escribir en un archivo existente es similar excepto en la forma de realmente abrir el
archivo. Para abrir un archivo para escritura, puede utilizar el método Open de la clase de
archivo pero especifica que desea escribir en la secuencia que se devolverá, como se muestra
en este ejemplo:
/
/
C
#
Archivo FileStream = null;
= file archivo.Open(@"c:\somefile.txt",
FileMode.Open,
FileAccess.Write);
El archivo de clase tiene el método OpenWrite, que es un atajo para lograr esto y simplifica
la apertura de archivos existentes para escribir. En lugar de llamar al método Open de
la clase File y especificando que desea abrirlo para escritura, puede simplemente usar un
código como este:
// C#
= file archivo.OpenWrite(@"c:\somefile.txt");
Estos fragmentos de código funciona sólo si el archivo existe. En muchas ocasiones, deseará
abrir un archivo existente o crear uno nuevo. Lamentablemente, el método OpenWrite abrirá
sólo un archivo existente. Podría escribir código para comprobar la existencia del archivo y
crear el archivo si no existe, sin embargo, afortunadamente, puede utilizar el método Open de
la clase File para especificar que desea abrir o crear un archivo, como se muestra aquí:
// C#
= file archivo.Open(@"c:\somefile.txt", FileMode.OpenOrCreate, FileAccess.Write);
// C#
String s = @"Hola a todos esta
es una cadena de texto de
múltiples líneas".
Console.WriteLine(escritor.ToString();
Pero porque no necesita siempre de sólo lectura o escritura de datos textuales, el marco de
trabajo .NET- namespace BinaryReader también soporta dos clases para la lectura o escritura
de archivo binario
Los datos. Las clases BinaryReader y BinaryWriter puede usarse para manejar obteniendo
los datos binarios y de los arroyos. Por ejemplo, si desea crear un nuevo archivo para
almacenar datos binarios, puede utilizar la clase BinaryWriter para escribir distintos tipos de
datos en una secuencia de la siguiente manera:
// C#
FileStream = File newFile.Create(@"c:\somefile.bin");
Escritor.Write(número); escritor.Write(bytes); escritor.Write(s);
Escritor.Close();
Si usted ha escrito los datos con la clase BinaryWriter, puede utilizar la clase
BinaryReader para obtener los datos en el mismo orden. Para cada clase
BinaryWriter.Write o llamada WriteLine, necesitará llamar a la clase BinaryReader.Leer
el método apropiado. Por ejemplo, el código siguiente leerá los datos escritos por el código
mostrado:
// C#
NewFile FileStream = File.Open(@"c:\somefile.bin", FileMode.Open);
Console.WriteLine(número);
Foreach (byte b en bytes)
{
Console.Write("[{0}]", b);
}
Console.WriteLine();
Console.WriteLine(s);
Nombre Descripción
Length obtiene la longitud (en bytes) de la secuencia. (Heredado de la
Clase Stream).
Obtiene o establece la posición del cursor virtual para determinar
dónde en el arroyo la posición actual. El valor de posición no
puede ser mayor que la longitud de la secuencia. (Heredado de
la clase Stream).
ReadTimeout Obtiene o establece la secuencia de tiempo de espera para las
operaciones de lectura. (Heredado de la clase Stream).
WriteTimeout obtiene o establece la secuencia de tiempo de espera para las
operaciones de escritura. (Heredado de la clase Stream).
Nombre Descripción
Cerrar Cierra la secuencia y libera todos los recursos asociados con
ella. (Heredado de la clase Stream).
A ras Borra los buffers en el stream y obliga a cambios a escribir en
el sistema subyacente o dispositivo. (Heredado de la clase
Stream).
GetBuffer recupera la matriz de bytes sin signo que se utilizaron para crear
la secuencia.
Leer Performs una lectura secuencial de un número especificado
de bytes desde la posición actual y actualiza la posición al
final de la lectura tras la finalización de la operación.
(Heredado de la clase Stream).
ReadByte Performs la lectura de un solo byte y actualiza la posición
moviendo por uno. Idéntico al llamar a Read para leer de un
solo byte. (Heredado de la clase Stream).
Seek establece la posición dentro de la secuencia. (Heredado de
la clase Stream).
SetLength Especifica la longitud de la secuencia. Este método truncará la
corriente si la nueva longitud es menor que la longitud anterior
y expandirá la corriente si la verdad es lo contrario. (Heredado
de la clase Stream).
Nombre Descripción
ToArray escribe toda la secuencia en una matriz de bytes.
Escribir escribe la información en la secuencia como un número
de bytes y actualiza la posición actual para reflejar la
nueva posición de escritura. (Heredado de la clase
Stream).
WriteByte escribe un byte a la secuencia y actualiza la posición. Este
método es idéntico a llamar escribir con un solo byte.
(Heredado de la clase Stream).
WriteTo escribe el MemoryStream a otra secuencia.
Ahora que tienes los datos en su objeto MemoryStream, qué hacemos con ella? Los
diseñadores de la clase MemoryStream comprender que almacenar la secuencia en la
memoria suele ser una situación temporal. De modo que la clase admite la escritura de la
secuencia directamente a otra secuencia o copiar los datos a otros dispositivos de
almacenamiento. Un uso común de una memoria- Stream es limitar el tiempo se abre un
archivo para escritura (debido a que bloquea el archivo). Para Seguir este ejemplo de
ejecución, puede indicarle el MemoryStream para escribir un FileStreamcomo se muestra a
continuación:
// C#
// Forzar al escritor a cargar los datos en el
// La secuencia subyacente
Writer.flush();
Nombre Descripción
ReadByte Performs la lectura de un solo byte, y actualiza la
posición moviendo por uno. Idéntico al llamar
a Read para leer un pecado- gle byte. (Heredado de
la clase Stream).
Seek establece la posición dentro de la secuencia. (Heredado de
la
Clase
Stream).
SetLength Specifies la longitud de la secuencia. Este método
complir- cate la corriente si la nueva longitud es menor
que la longitud anterior y expandirá la corriente si la
verdad es lo contrario. (Heredado de la clase Stream).
Escribir escribe la información en la secuencia como un
número de bytes y actualiza la posición actual para
reflejar la nueva escritura de posi- ción. (Heredado de
la clase Stream).
WriteByte escribe un byte a la secuencia y actualiza la posición.
Este método es idéntico a llamar escribir con un solo
byte. (Heredado de la clase Stream).
Writer.Close();
// C#
Lector StreamReader = File.OpenText(@"c:\Newfile.txt");
Contenido de cadena = reader.ReadToEnd();
lector.Close(); Console.WriteLine(índice);
Resumen de la lección
■ La claseFile puede ser usada para abrir archivos, crear nuevos archivos, leer
archivos completos atomi- camente, e incluso escribir archivos.
■ La claseFileStream representa un archivo en el sistema de archivos y
permite la lectura y escritura (dependiendo de cómo se haya creado).
■ El StreamReader y StreamWriter clases se utilizan para simplificar la
escritura de cadenas a los arroyos.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba tus conocimientos de la
información Les- hijo 2, "la lectura y escritura de archivos." Las preguntas también
están disponibles en el CD de iones complementaria si prefiere revisarlos en forma
electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final
del libro.
1 http://www.ietf.org/rfc/rfc1952.txt?number=1952
Tabla 2-31
GZipStream métodos
Nombre Descripción
Cerrar Cierra la secuencia y libera todos los recursos
asociados con ella. (Heredado de la clase Stream).
A ras Borra los buffers en el stream y obliga a cambios a
escribir en el sistema subyacente o dispositivo.
(Heredado de la clase Stream).
Nombre Descripción
Leer Performs una lectura secuencial de un número
especificado de bytes desde la posición actual y
actualiza la posición al final de la lectura tras la
finalización de la operación. (Inher- ited de la clase
Stream).
ReadByte Performs la lectura de un solo byte y actualiza la
posición moviendo por uno. Este método es idéntico a
llamar a Read para leer de un solo byte. (Heredado de
la clase Stream).
Buscar No utilice. Generará NotSupportedException.
(Heredado de la clase Stream).
SetLength No utilice. Generará NotSupportedException.
(Heredado de la clase Stream).
Escribir escribe la información en la secuencia como un
número de bytes y actualiza la posición actual para
reflejar la nueva escritura de posi- ción. (Heredado de
la clase Stream).
WriteByte escribe un byte a la secuencia y actualiza la posición.
Este método es idéntico a llamar escribir con un solo
byte. (Heredado de la clase Stream).
Nombre Descripción
Cerrar Cierra la secuencia y libera todos los recursos asociados
con ella. (Heredado de la clase Stream).
A ras Borra los buffers en el stream y obliga a cambios a escribir
en el sistema subyacente o dispositivo. (Heredado de
la clase Stream).
Leer Performs una lectura secuencial de un número especificado
de bytes desde la posición actual y actualiza la posición al
final de la lectura tras la finalización de la operación.
(Inher- ited de la clase Stream).
ReadByte Performs la lectura de un solo byte y actualiza la posición
moviendo por uno. Este método es idéntico a llamar
a Read para leer de un solo byte. (Heredado de la clase
Stream).
Buscar No utilice. Generará NotSupportedException. (Heredado de
la clase Stream).
Nombre Descripción
SetLength No utilice. Generará NotSupportedException.
(Heredado de la clase Stream).
Escribir escribe la información en la secuencia como un
número de bytes y actualiza la posición actual para
reflejar la nueva escritura de posi- ción. (Heredado de
la clase Stream).
WriteByte escribe un byte a la secuencia y actualiza la posición.
Este método es idéntico a llamar escribir con un solo
byte. (Heredado de la clase Stream).
Esta declaración indica la secuencia de compresión para comprimir datos y empujarla hacia la
des- tination stream. La constr CompressionMode uctor toma un valor que especifica si la
secuencia va a ser usado para comprimir o descomprimir. En este caso, desea comprimir la
secuencia, por lo que utilizar CompressionMode.Compress. Una vez que haya creado la
secuencia de compresión, es simplemente una cuestión de lectura de datos desde la secuencia
de origen e introduciéndolo en la secuencia de compresión, tal y como se muestra aquí:
// C#
Int = theByte sourceFile.ReadByte();
Mientras (theByte !=
-1)
{
CompStream.WriteByte((byte)theByte);
TheByte = .sourceFile ReadByte();
}
Este código transfiere datos de byte en byte desde el archivo de origen () en la sourceFile
com-compStream pression stream (). Observe que usted no escribe directamente en el archivo
de destino en todo (destFile). Porque estás escribiendo en la secuencia de compresión
sexyskadi- ción, el arroyo se llena con la versión comprimida de los datos desde el archivo de
origen.
Las secuencias de código recién mostrado no es específico para el método de compresión
gzip. Si cambiamos la construcción de la secuencia a utilizar en su lugar el DeflateStream, el
resto del código no cambia en absoluto. Todo lo que debe hacer es crear un lugar
DeflateStream, tal como se muestra aquí (observe la firma del constructor es el mismo que el
de la GZipStream):
// C#
DeflateStream compStream =
Nuevo (destFile DeflateStream, CompressionMode.Compress);
// C#
= Archivo sourceFile FileStream.OpenRead(inFilename); =
Archivo destFile FileStream.Create(outFilename);
Además, necesita cambiar la forma en que procesa el archivo para leer la secuencia de
compresión en lugar de desde el archivo de origen y escribir en el archivo directamente, en
lugar de a través de la secuencia de compresión:
// C#
Int = compStream theByte.ReadByte();
Mientras (theByte !=
-1)
{
DestFile.WriteByte((byte)theByte);
= compStream theByte.ReadByte();
}
// C#
GZipStream compStream =
Nueva GZipStream(destFile, CompressionMode.Compress);
// C#
CompressFile(@"c:\boot.ini", @"c:\boot.ini.gz");
// C#
Int = compStream theByte.ReadByte();
Mientras (theByte != -1)
{
DestFile.WriteByte((byte)theByte);
= compStream theByte.ReadByte();
}
// C#
DecompressFile(@"c:\boot.ini.gz", @"c:\boot.ini.test");
Resumen de la lección
■ La secuencia de compresión ( las clasesGZipStream y DeflateStream) puede
ser usada para comprimir o descomprimir los datos de hasta 4 GB.
■ La secuencia de compresión clases se utilizan para envolver otra secuencia en
la que se guardarán los datos comprimidos.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba tus conocimientos de la
información Les- hijo 3, "comprimir secuencias." Las preguntas también están
disponibles en el CD complementario si prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final
del libro.
Nombre Descripción
GetMachineStoreForApplication recupera una máquina-nivel de
almacenamiento para el clic- una
aplicación que llama
GetMachineStoreForAssembly recupera un almacén a nivel de la máquina
para la asamblea que llamó
GetMachineStoreForDomain recupera una máquina-nivel de almacenamiento
para el AppDomain
Dentro de la corriente general que llama
GetStore recupera almacena cuyo ámbito de aplicación
se basa en el
Enumerador IsolatedStorageScope
GetUserStoreForApplication recupera un almacén a nivel de usuario
para la aplicación que llama Click-Once
GetUserStoreForAssembly recupera un almacén a nivel de usuario para
la asamblea que llamó
GetUserStoreForDomain recupera un almacén a nivel de usuario
para AppDomain
Dentro de la corriente general que llama
La tabla 2-35 muestra las más importantes propiedades de IsolatedStorageFile.
Tabla 2-35 IsolatedStorageFile
Propiedades
Nombre Descripción
La Click-Once ApplicationIdentity la identidad de la aplicación que
orienta el almacenamiento aislado
La identidad del ensamblado AssemblyIdentity que orienta el
almacenamiento aislado
Tabla 2-35
IsolatedStorageFile Propiedades
Nombre Descripción
CurrentSize el tamaño actual de los datos almacenados en este
almacenamiento aislado
DomainIdentity L aidentidad del AppDomain que orienta el
almacenamiento aislado
Tamañomáximo el tamaño máximo de almacenamiento para este
almacenamiento aislado
Alcance el valor de la enumeración
IsolatedStorageScope que describe el alcance
de este almacenamiento aislado
La tienda es en este caso en el ámbito del usuario específico que está ejecutando la asamblea.
Si necesita especificar el usuario para el almacén, usted necesitará usar la suplantación (que se
describe en el capítulo 12).
Nombre Descripción
Cerrar Cierra la secuencia y libera todos los recursos asociados con
ella. (Heredado de la clase Stream).
A ras Clears cualquier buffers en el stream y obliga a cambios a
escribir en el sistema subyacente o dispositivo. (Heredado de
la clase Stream).
El bloqueo impide que otros procesos puedan cambiar todo o
parte del archivo. (Heredado de la clase FileStream.)
Leer Performs una lectura secuencial de un número especificado
de bytes desde la posición actual y actualiza la posición al
final de la lectura tras la finalización de la operación.
(Heredado de la clase Stream).
ReadByte Performs la lectura de un solo byte y actualiza la posición
moviendo por uno. Este método es idéntico a llamar
a Read para leer de un solo byte. (Heredado de la clase
Stream).
Seek establece la posición dentro de la secuencia. (Heredado de
la secuencia
Cla
se).
SetLength Especifica la longitud de la secuencia. Truncará la corriente si
la nueva longitud es menor que la longitud anterior y
expandirá la corriente si la verdad es lo contrario. (Heredado
de la clase Stream).
Permite desbloquear otros procesos para cambiar una parte o la
totalidad del fichero subyacente. (Heredado de la clase
FileStream.)
Escribir escribe la información en la secuencia como un número de
bytes y actualiza la posición actual para reflejar la nueva
posición de escritura. (Heredado de la clase Stream).
WriteByte escribe un byte a la secuencia y actualiza la posición. Este
método es idéntico a llamar escribir con un solo byte.
(Heredado de la clase Stream).
IsolatedStorageFileStream userStream =
Nueva IsolatedStorageFileStream("UserSettings.set", FileMode.Create, userStore);
Después de crear una tienda, puede crear una secuencia de archivos especificando el nombre
de archivo, el FileMode utilizar en abrir o crear el archivo y almacenar el objeto que ha
creado. Una vez que tenga una instancia de la clase IsolatedStorageFileStream, trabajar con
ella es idéntica a trabajar con cualquier secuencia de archivos (como hicimos en la lección 2).
Esto es porque IsolatedStorageFileStream deriva de FileStream. El siguiente fragmento de
código proporciona un ejemplo:
// C#
StreamWriter userWriter = new StreamWriter(userStream);
UserWriter.WriteLine("User Prefs");
UserWriter.Close();
La preparación para leer los datos es tan simple como crear un objeto Stream abriendo el
archivo en lugar de crear, como se muestra aquí:
// C#
IsolatedStorageFileStream userStream =
Nueva IsolatedStorageFileStream("UserSettings.set", FileMode.Open, userStore);
Puede utilizar el método GetFileNames de la clase IsolatedStorageFile para obtener una lista
de los archivos que coincidan con el nombre de archivo (u otras máscaras de archivo
como *.set). Esta sustitución es suficiente para probar la existencia del archivo antes de tr
ying para leer, eliminar o reemplazar el archivo.
En este ejemplo, se crea el directorio antes de intentar crear un nuevo archivo en ese
directorio. Si no crea el directorio en primer lugar, obtendrá una excepción de análisis de ruta.
Los directorios son tratados como archivos que para probar su existencia, debe utilizar un
método que devuelve una matriz de cadenas que coincidan con una máscara.
La GetDirectoryNames método de la clase IsolatedStorageFile le permite encontrar un
directorio existente antes de intentar crear:
// C#
String[] = directorios
UserStore.GetDirectoryNames("SomeDir");
Si (directorios.Length == 0)
{
UserStore.CreateDirectory("SomeDir");
}
Obteniendo los nombres de directorio que coincida con su nombre, usted puede hacer una
prueba para ver si existe el directorio y crear sólo si no estaba ya creado.
Nombre Descripción
UsageAllowed obtiene o establece los tipos de uso permitido.
Opciones UserQuota obtiene o establece el tamaño total de
almacenamiento permitido por usuario
Este permiso también admite varias propiedades que se pueden utilizar para modificar la
forma de iso- lacionadas con el almacenamiento se utiliza, como se muestra en este ejemplo:
// C# [IsolatedStorageFilePermission(SecurityAction.La demanda,
Opciones UserQuota=1024,
UsageAllowed=IsolatedStorageContainment.AssemblyIsolationByUser)]
Programa de clase
{
// ...
}
// C#
UserStream = new
IsolatedStorageFileStream("UserSettings.set", FileMode.Open,
userStore);
StreamReader userReader = new StreamReader(userStream);
Contenido de cadena = userReader.ReadToEnd();
Resumen de la lección
■ La clase IsolatedStorageFile puede utilizarse para acceder a zonas seguras
para almacenar datos para las asambleas y los usuarios.
■ El IsolatedStorageFileStream clase puede usarse para leer y escribir datos en
estos almacenes seguros.
■ El IsolatedStorageFileStream clasederiva de la clase FileStream, así que
alguno de los archivos de la clase crea puede usarse como cualquier otro
archivo en el sistema de archivos.
■ El IsolatedStorageFilePermission clase puede utilizarse para asegurarse de
que el código tiene los permisos adecuados para actuar sobre el
almacenamiento aislado.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba su conocimiento de la información
en la lección 4, "Trabajar con el almacenamiento aislado." Las preguntas también están
disponibles en el CD complementario si prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final
del libro.
Términos clave
¿ Sabes lo que significan estos términos clave? Puede verificar sus respuestas
mediante la búsqueda de los términos en el glosario al final del libro.
■ desinflar
■ Sistema de archivo
■ El almacenamiento aislado
■ gzip
Casos
En los siguientes casos, podrá aplicar lo que ha aprendido acerca de los archivos y directorios.
Usted puede encontrar las respuestas a estas preguntas en la sección de "respuestas" al final de
este libro.
Preguntas
Responda las siguientes preguntas para el administrador.
1. En un nivel alto, describir cómo se podría almacenar la información para los
usuarios.
2. Cómo sería que si cambio de diseño necesarios para comprimir los datos de
preferencia para ayudar a limitar el tamaño de los datos?
Entrevistas
La siguiente es una lista de personal de la empresa entrevistados y sus
declaraciones:
■ IT Manager "Estoy seguro de que algunos usuarios siguen usando los
servidores sin saberlo. Si pudiéramos controlar los servidores por una semana,
así que puedo migrar los usuarios a nuestros nuevos servidores de ficheros,
podríamos ahorrar un montón de dinero en los gastos de mantenimiento".
Preguntas
Responda las siguientes preguntas para el administrador.
1. ¿Qué tipo de aplicación se puede crear para atender la necesidad del
departamento de TI?
2. ¿Cómo va a supervisar los servidores de archivos?
3. ¿Cómo va a lidiar con el gerente de desarrollo está preocupado con el
rendimiento?
Prácticas recomendadas
Que le ayudarán a dominar los objetivos contemplados en el presente capítulo, complete las
siguientes tareas.
Crear un archivo de aplicación Buscador
Para esta tarea, se deben completar un mínimo de prácticas 1 y 2. Para más expe- riencia con
las secuencias de compresión, por favor complete la Práctica 3.
■ La Práctica 1 Crear una aplicación que se va a buscar una unidad para un
archivo en particular.
■ La Práctica 2 Agregar código para ver el archivo utilizando la clase
FileStream para mostrar el archivo en una ventana de texto.
■ Práctica 3. Por último, añadir una función para comprimir un archivo
cuando se encuentra.
El procesamiento de texto es una de las tareas de programación más comunes. Entrada de usuario
es habitualmente en formato de texto, y podría tener que ser validados, esterilizado, y reformatear.
A menudo, los desarrolladores necesitan para procesar archivos de texto generado a partir de un
sistema heredado para extraer datos importantes. Estos sistemas heredados a menudo utilizan
técnicas de codificación no estándar. Además, los desarrolladores pueden necesitar para la salida
de los archivos de texto en formatos específicos para introducir datos en un sistema heredado.
En este capítulo se describe cómo utilizar expresiones regulares para validar los datos de entrada,
cambiar el formato del texto, y extraer datos. Además, en este capítulo se describen los diferentes
tipos de codificación utilizado por archivos de texto.
143
Antes de empezar
Para completar las lecciones de este capítulo, debe estar familiarizado con Microsoft
Visual
Basic o en C# y se sienten cómodos realizando las siguientes tareas:
■ Crear una aplicación de consola en Microsoft Visual Studio, usando Visual Basic o
C#.
■ Sistema de agregar referencias a bibliotecas de clases para un proyecto.
■ leer y escribir archivos y arroyos.
// C#
Utilizando System.Text.RegularExpressions;
TestRegExp namespace
{
La clase Class1
{
[STAThread]
Static void main(String[] args)
{
Si (Regex.IsMatch(args[1], args[0])) Console.WriteLine("Input coincide con la expresión regular.");
Otra cosaConsole.WriteLine("Input no coincide con la expresión regular.");
Como demuestra este código, el regex. método IsMatch compara una expresión regular a una
cadena y devuelve VERDADERO si la cadena coincide con la expresión regular. En este ejem- plo,
"^\d{5}$" significa que la cadena debe tener exactamente 5 dígitos numéricos. Como se muestra en
la Figura 3-1, el carat ("^") representa el inicio de la cadena "\d" significa dígitos numéricos, "{5}"
indica cinco dígitos numéricos secuenciales, y "$" representa el final de la cadena.
^\d{5}$
Figura 3-1 El análisis de una expresión regular
Las expresiones regulares pueden ser utilizadas para hacer coincidir los patrones de entrada
complejos, demasiado. La siguiente expresión regular coincide con las direcciones de correo
electrónico:
^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w]+\).+) ([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$
Las expresiones regulares son una manera muy eficaz para comprobar la entrada del usuario;
sin embargo, el uso de expresiones regulares tiene las siguientes limitaciones:
■ Las expresiones regulares son difíciles de crear, a menos que esté muy
familiarizado con el formato. Si tiene años de experiencia en programación en
Perl, no tendrás ningún problema usando expresiones regulares en código C#. Sin
embargo, si usted tiene una copia-
Terreno en Visual Basic Scripting, el formato críptico de expresiones regulares que
inicialmente parecen completamente ilógico.
■ Creación de expresiones regulares puede ser confuso, pero la lectura de las
expresiones regulares es definitivamente. Hay una buena probabilidad de que
otros programadores se dan errores en expresiones regulares al realizar una revisión de
código entre pares. Más
Complejo la expresión regular, mayor será la probabilidad de que la estructura de la
expresión contiene un error que será ignorada.
Las secciones que siguen describen estos y otros aspectos de la expresión regular pat- tern
matching en más detalle. A medida que lea estas secciones, experimentar con- dif erentes
tipos de expresiones regulares usando la aplicación TestRegExp.
Más info expresiones
regulares.
Libros enteros han sido escritos sobre las expresiones regulares, y esta lección
sólo pueden rayar la superficie. La información proporcionada en esta lección
debería ser suficiente para el examen. Sin embargo, si usted desea aprender
más acerca de las características avanzadas de las expresiones regulares, lea la
sección "Elementos del lenguaje de expresiones regulares" en la Referencia
general de .NET Framework en http://msdn.microsoft.com/library/ en-
us/cpgenref/html/cpconRegularExpressionsLanguageElements.asp .
Nota confundida?
Si las expresiones regulares parece críptica, y eso es porque ellos son. A
diferencia de casi todo lo demás en el
.NET Framework, las expresiones regulares se basan en gran medida en
caracteres especiales con significados que no
Ser humano nunca pudo descifrar en su propio. La razón de esto es simple:
Regular expres-
Sion" se originó en el mundo UNIX durante una época en que la memoria y el
almacenamiento son extremadamente limitadas
Y los desarrolladores tenían que hacer cada recuento de caracteres. Por esta
razón, deberá siempre com-
El ment expresiones regulares. Tan duro como pueden ser la creación, lectura
regular del otro desarrollador
Expresiones es casi imposible.
La tabla 3-1 muestra los caracteres que puede utilizar para provocar la expresión
regular para que coincida con una ubicación- pecífico en una cadena. De éstos, el más
importante saber son "^" y "$".
Tabla 3-1 caracteres que coinciden con la ubicación en cadenas
Para identificar a un grupo de personajes, rodean los caracteres entre paréntesis. Por
ejemplo, "foo(100){1,3} hoo" coincide con "fooloohoo" y "fooloolooloohoo" pero no
"foo-hoo" o "foololohoo". Asimismo, "foo(loo|roo|)hoo" podría coincidir con
"fooloohoo" o "fooroohoo". Puede aplicar cualquier carácter comodín o de otro
carácter especial a un grupo de caracteres.
También puede nombrar grupos para referirse a la coincidencia de datos más tarde.
Para asignar un nombre a un grupo, utilice t él fo r m a "(?< nam e > cháchara n )".
Fo r ejemplo, t h e re gular expresión
Construccion de
referecia imversa
// C#
Entrada de cadena = "Nombre de la empresa: Contoso,
Ltd.";
M = Match Regex.Match(entrada, @"Nombre de la empresa: (.*$");
Console.WriteLine(m.Grupos[1]);
// C#
String(String MDYToDMY entrada)
{
Volver Regex.Replace(entrada, "\\b(?<mes>\\d{1,2})/(?<día>\\d{1,2})/(?<año>\\d{2,4})\\b", "${day}-${month}-${año}");
}
Este ejemplo demuestra el uso de referencias inversas con nombre dentro del modelo de
reemplazo de Regex.Sustituir. Aquí, la sustitución de la expresión ${day} inserta la sub-
cadena capturada por el grupo (?<día>…).
En el siguiente ejemplo de código se utiliza el método estático Regex.Replace para quitar los
caracteres no válidos- acters desde una cadena. Puede utilizar el método CleanInput definido
aquí strip poten- considerablemente los caracteres nocivos que se han introducido en un
campo de texto que acepta datos del usuario. CleanInput devuelve una cadena después de la
eliminación de todos los caracteres no alfanumérico, excepto @, - (guión), y . (Un punto).
// C#
Cadena CleanInput(string cadena)
{
// Reemplazar caracteres no válidos con cadenas vacías. volver Regex.Replace(cadena, @"[^\w\.@-]", "");
}
Caracteres de escape y las sustituciones son las únicas construcciones especiales reconocidas
en un patrón de sustitución. Todas las construcciones sintácticas descritas en las siguientes
secciones se permiten solamente en expresiones regulares; no son reconocidos en sustitución
patrones. Por ejemplo, el patrón de sustitución*${txt}b Inserta la cadena "a*" fol- lowed por
la subcadena coincidente txt por el grupo de captura, si cualquiera, seguido por la cadena "b".
El carácter * no se reconoce como un metacarácter dentro de un patrón de sustitución.
Asimismo, $ patrones no son reconocidos dentro de patrones de expresiones regulares. Dentro
de expresiones regulares, $ designa al final de la cadena.
La tabla 3-7 muestra cómo definir patrones de sustitución nombradas y
numeradas.
Tabla 3-7 caracteres de escape utilizado en las sustituciones
Mundo Real
Tony Northrup
A menudo me obstinada a un fallo. Durante muchos años, yo simplemente se negó a
aprender expresiones regulares. Las expresiones regulares son la forma en la que UNIX de
hacer las cosas, y yo era un chico de Windows.
Recientemente, he revisado algunos código que escribí hace ya varios años cuando yo
todavía era terco. Yo había escrito decenas de líneas de código para comprobar la validez
de los datos de texto que podría haber sido escrito con una singular expresión regular. Que
no me molesta en sí mismo, porque a veces escribir más código mejora la legibilidad. Sin
embargo, en este caso, la comprobación de texto había quedado tan complejo que contenía
errores.
Me reescribió el código utilizando expresiones regulares, y no sólo arregló los bugs, pero
simplifica el código. Así, por su propio bien, no ignore las expresiones regulares sólo
porque les parece demasiado complejo. En buceo, pasar unas horas trabajando con ellos, y
no te arrepentirás.
❑ El (555) 555-1212
❑ 555-555-1212
❑ 5555551212
Cada componente de esta expresión regular coincide con una parte requerida
u opcional de un número de teléfono:
■ ^ coincide con el principio de la cadena.
■ \(? Opcionalmente coincide con un paréntesis de apertura. El
paréntesis es pre- cedido con una barra invertida, ya que el paréntesis es
un carácter especial en las expresiones regulares. La siguiente
interrogante hace el paréntesis
Opcional.
■ \d{3,} coincide exactamente tres dígitos numéricos.
❑ 01111-1111
// C#
Static bool IsZip(string s)
{
Volver Regex.IsMatch(S, @"^\d{5}(\\d{4})?$");
}
Cada componente de esta expresión regular coincide con una parte requerida
u opcional de un código postal:
■ ^ coincide con el principio de la cadena.
■ \d{5} coincide exactamente cinco dígitos numéricos.
■ (\\d{4})? Opcionalmente coincide con un guión seguido por
exactamente cuatro dígitos numéricos. Porque la expresión está rodeado
de paréntesis y seguido por un signo de interrogación, la expresión se
consideran opcionales.
■ $ coincide con el final de la cadena.
Si el resultado que obtiene no coincide con el resultado mostrado, ajustar sus expresiones
regulares según sea necesario.
Ejercicio 2: Formatear una cadena
En este ejercicio, debe volver a formatear números de teléfono en un estándar (###) ###-####
Formato.
1. Abra el proyecto creado en el ejercicio 1.
2. Agregue un método denominado ReformatPhone que devuelve un valor de tipo
string y acepta una cadena como argumento. El uso de expresiones regulares,
aceptar datos de número de teléfono proporcionado en uno de los formatos que se
usan en el ejercicio 1, y el formato de los datos en el (###) ###-#### de formato.
Aunque muchos diferentes expresiones regulares, el método IsZip escribir podría
tener este aspecto:
// C#
Cadena estática ReformatPhone(string s)
{
M = Match Regex.Match(S, @"^\(?(\d{3})?[\)\s\-]?(\d{3})\-?(\d{4}$");
Devuelve String.Format("({0}) {1}-{2,}", m.Grupos[1], m.Grupos[2], m.Grupos[3]);
}
Observe que esta expresión regular coincide casi exactamente con que se utiliza
en el método IsPhone. La única diferencia es que cada uno de losn \d{}
expresiones está cercada por paréntesis. Esto coloca a cada uno de los conjuntos
de números en un grupo separado que puede ser fácilmente formateado
utilizando String.Format.
3. Cambiar el método principal de modo que escribe ReformatPhone(s) en el bucle
foreach en lugar de simplemente s. Por ejemplo, el bucle foreach debe tener este
aspecto:
// C#
Foreach (cadena de entrada)
{
Si (IsPhone(s) Console.WriteLine(ReformatPhone(s) + " es un número de teléfono");
Else If (IsZip(s) Console.WriteLine(s + " no es un código postal");
Else Console.WriteLine(s + " es desconocido");
}
Observe que cada uno de los números de teléfono ha sido reordenada aunque fueron
inicialmente en cuatro formatos diferentes. Si el resultado no coincide con el de salida sólo se
muestra, ajuste las expresiones regulares según sea necesario.
Resumen de la lección
■ Las expresiones regulares permiten determinar si el texto coincide con casi cualquier tipo
de formato. Soporte para expresiones regulares docenas de operadores y caracteres
especiales. Los más comúnmente utilizados son "^" para coincidir con el inicio de la cadena,
"$" para que coincida con el final de una cadena, "?" para hacer un carácter facultativo, "."
para que coincida con cualquier carácter, y "*" para hacer coincidir un carácter repetido.
■ para hacer coincidir los datos mediante una expresión regular, crear un patrón utilizando
grupos a spec- ify los datos que usted necesita para extraer, llamada Regex.Match para crear
un objeto Match y, a continuación, examine cada uno de los elementos de los Grupos
coinciden. Array.
■ Para cambiar el formato del texto de datos mediante una expresión regular, llame al
estático Regex.Sustituir Método.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba su conocimiento de la información
en la lección 1, "formar expresiones regulares." Las preguntas también están disponibles en el
CD complementario si prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final
del libro.
B.
// C#
S = Regex.Replace(s, "https://" "http://");
C.
// C#
S = Regex.Replace(s, "http://", "https://" RegexOptions.IgnoreCase);
D.
// C#
S = Regex.Replace(s, "https://" "http://", RegexOptions.IgnoreCase);
Se han leído los datos del formulario en la variable de cadena s. Cuál de los
siguientes ejemplos de código almacena correctamente la parte de datos del
formulario en el fullName, dirección, ciudad, estado, y zip variables?
A.
// C#
Cadena p = @"Nombre: (?<firstName>.*$)\n" +
@"Apellidos: (?<Apellido>.*$)\n" +
@"Dirección: (?<dirección>.*$)\n" +
@"Ciudad: (?<ciudad>.*$)\n" +
@"Estado: (?<estado>.*$)\n" +
@"Zip: (?<zip>.*$)".
M = Match Regex.Match(s, p, RegexOptions.Multiline);
Cadena FullName = m.Groups["nombre"] + " " + m.Groups["LastName"];
Cadena dirección = m.Groups["Dirección"].ToString();
Ciudad de cadena = m.Groups["Ciudad"].ToString(); string estado = m.Groups["Estado"].ToString(); string zip =
m.Groups["zip"].ToString();
B.
// C#
Cadena p = @"Nombre: (?<firstName>.*$)\n" +
@"Apellidos: (?<Apellido>.*$)\n" +
@"Dirección: (?<dirección>.*$)\n" +
@"Ciudad: (?<ciudad>.*$)\n" +
@"Estado: (?<estado>.*$)\n" +
@"Zip: (?<zip>.*$)"; m = Match Regex.Match(s, p);
Cadena FullName = m.Groups["nombre"] + " " + m.Groups["LastName"];
Cadena dirección = m.Groups["Dirección"].ToString();
Ciudad de cadena = m.Groups["Ciudad"].ToString(); string estado = m.Groups["Estado"].ToString(); string zip =
m.Groups["zip"].ToString();
C.
// C#
Cadena p = @"Nombre: (?<firstName>.*$)\n" +
@"Apellidos: (?<Apellido>.*$)\n" +
@"Dirección: (?<dirección>.*$)\n" +
@"Ciudad: (?<ciudad>.*$)\n" +
@"Estado: (?<estado>.*$)\n" +
@"Zip: (?<zip>.*$)".
M = Match Regex.Match(s, p, RegexOptions.Multiline);
Cadena FullName = m.Groups["<nombre>"] + " " + m.Groups["<Apellido>"];
Cadena dirección = m.Groups[" <dirección>"].ToString();
Ciudad de cadena = m.Groups["<ciudad>"].ToString(); string estado = m.Groups["<ESTADO>"].ToString(); string zip =
m.Groups["<zip>"].ToString();
D.
// C#
Cadena p = @"Nombre: (?<firstName>.*$)\n" +
@"Apellidos: (?<Apellido>.*$)\n" +
@"Dirección: (?<dirección>.*$)\n" +
@"Ciudad: (?<ciudad>.*$)\n" +
@"Estado: (?<estado>.*$)\n" +
@"Zip: (?<zip>.*$)"; m = Match Regex.Match(s, p);
Cadena FullName = m.Groups["<nombre>"] + " " + m.Groups["<Apellido>"];
Cadena dirección = m.Groups[" <dirección>"].ToString();
Ciudad de cadena = m.Groups["<ciudad>"].ToString(); string estado = m.Groups["<ESTADO>"].ToString();
string zip = m.Groups["<zip>"].ToString();
3. Cuál de las siguientes expresiones regulares coincide con las cadenas "zoot" y
"Zot"?
A. Z(oo)+t
B.
Zo*t$
C.
$zo*t
D.
^(zo)+t
4. Cuál de las siguientes cadenas de caracteres coincide con la expresión regular
"^A(MO)+t.*z$"? (Seleccione todos los que correspondan).
A. Amotz
B. Amomtrewz
C. Amotmoz
D. Atrewz
E. Amomomottothez
Lección 2: la codificación y descodificación
Cada cadena y archivo de texto está codificado usando uno de los muchos estándares de
codificación distintos. La mayor parte del tiempo, el .NET Framework gestiona la codificación
para usted automáticamente. Sin embargo, hay veces en que usted podría necesitar para controlar
manualmente la codificación y decodificación, como cuando:
■ interoperar con sistemas UNIX o heredados
■ la lectura o escritura de archivos de texto en otros idiomas.
■ Creación de páginas HTML
■ generar manualmente los mensajes de correo electrónico
Esta lección describe técnicas de codificación común y le muestra cómo usarlos en aplicaciones
.NET Framework.
Comprender la codificación
Aunque no fue el primer tipo de codificación, Código estándar americano para el intercambio de
información (ASCII) sigue siendo la base para los tipos de codificación. Asignados a caracteres
ASCII de 7 bits de bytes utilizando los números de 0 a 127. Estos caracteres incluyen Inglés letras
en mayúsculas y minúsculas, números, signos de puntuación y algunos caracteres de control
especiales. Por ejemplo, 0x21 es "!", 0x31 es "1", 0x43 es "C", 0x63 es "c", y 0x7D es "}".
Mientras ASCII fue suficiente para la mayoría de las comunicaciones en idioma inglés, ASCII no
incluir caracteres usados en alfabetos no inglés. Para permitir que los equipos que se utilizan en los
no-lugares de habla inglesa, los fabricantes han hecho uso de los valores restantes-128 y 255-en un
byte de 8 bits. A lo largo del tiempo, distintos lugares asignados caracteres únicos para valores
mayores de 127. Porque diferentes ubicaciones pueden tener diferentes caracteres asignados a un
único valor, la transferencia de documentos entre diferentes idiomas creado problemas.
Para ayudar a reducir estos problemas, American National Standards Institute (ANSI) define
el código estandarizado páginas que había valores ASCII estándar de 0 a 127, y la lan- meden-
valores específicos para 128 y 255. Una página de códigos es una lista de algunos códigos de
caracteres (los caracteres representados como código de puntos) en un orden determinado. Las
páginas de código se define generalmente en apoyo de idiomas específicos o grupos de idiomas
que comparten recurso- ing sistemas. Las páginas de código de Windows contienen 256 puntos de
código y se basan en cero.
Si has recibido un mensaje de correo electrónico o ver una página Web que parecía tener caracteres
de cuadro o signos de interrogación donde debería aparecer cartas, que han experimentado un
problema de codificación. Porque la gente cree páginas Web y correos electrónicos en muchos
idiomas diferentes, cada uno de ellos debe estar marcado con un tipo de codificación. Por ejemplo,
un mensaje de correo electrónico podría incluir uno de los siguientes encabezados:
Content-Type: text/plain; charset=iso-8859-1
Content-Type: text/plain; charset="Windows-1251"
Más y más, ASCII y tipos de codificación ISO 8859 están siendo sustituidas por Unicode. Unicode
es una gran página de códigos con decenas de miles de caracteres que admiten la mayoría de los
idiomas y alfabetos, incluyendo latín, griego, cirílico, árabe, hebreo, chino y japonés (y muchos
otros scripts).
Unicode en sí no especifica un tipo de codificación; sin embargo, hay varias normas para la
codificación Unicode. El .NET Framework utiliza Unicode UTF-16 (Unicode trans- formación
Format, Formato de codificación de 16 bits) para representar los caracteres. En algunos casos, el
.NET Framework utiliza UTF-8 internamente. El espacio de nombres System.Text proporciona
clases que permiten codificar y decodificar caracteres. System.Text encoding support incluye los
siguientes tipos de codificaciones:
■ La codificación Unicode UTF-32 Unicode UTF-32 representa la codificación
Unicode char- acters como secuencias de números enteros de 32 bits. Puede
utilizar la clase de codificación UTF32para convertir los caracteres a y desde la
codificación UTF-32.
■ La codificación Unicode UTF-16 la codificación Unicode UTF-16
representa los caracteres Unicode- acters como secuencias de enteros de 16 bits.
Puede utilizar la clase UnicodeEncoding para convertir los caracteres a y desde la
codificación UTF-16.
■ La codificación Unicode UTF-8 Unicode UTF-8 utiliza 8 bits, 16 bits, 24 bits
y 48 bits de codificación. Los valores del 0 al 127, use 8-bit ASCII encoding y
coinciden exactamente con val- ores, proporcionando algún grado de
interoperabilidad. Los valores de 128 a 2047 utilice
Codificación de 16 bits y prestar apoyo para el latín, griego, cirílico, hebreo y
árabe alfabetos. Valores de 2048 a 65.535 el uso de 24 bits de codificación para
chino, japonés, coreano y otros idiomas que requieren un gran número de valores.
Puede utilizar la clase UTF8Encoding para convertir los caracteres a y desde la
codificación UTF-8.
■ la codificación ASCII CODIFICACIÓN ASCII codifica el alfabeto latino como
solo caracteres ASCII de 7 bits. Porque esta codificación sólo admite valores de
caracteres U+0000 a U+007F, en la mayoría de los casos es insuficiente para
internacionalizarse aplica-
Ema. Puede utilizar la clase ASCIIEncoding para convertir los caracteres a y
desde La codificación ASCII.
■ ANSI/ISO codificaciones System.Text.Encoding clase proporciona soporte
para una amplia variedad de codificaciones de ANSI/ISO.
// C#
// Obtener la codificación coreana
E = codificación Encoding.GetEncoding("Korean");
// C#
Ei EncodingInfo[] = Encoding.GetEncodings();
(Foreach EncodingInfo e en ei)
Console.WriteLine("{0}: {1}, {2}", e.CodePage, e.Nombre, e.DisplayName);
// C#
StreamWriter swUtf7 = new StreamWriter("utf7.txt", falso, la codificación UTF7);
SwUtf7.WriteLine("Hello, World!");
SwUtf7.Close();
Si ejecuta el ejemplo de código anterior, notará que los cuatro archivos diferentes, cada uno de
ellos tiene diferentes tamaños de archivo: el archivo UTF-7 es de 19 bytes, el archivo UTF-8 es de
18 bytes, el archivo UTF-16 es de 32 bytes y el archivo UTF-32 es de 64 bytes. Si abre cada uno de
los archivos en la nota- pad, UTF-8 y UTF-16 Presentación de archivos correctamente. Sin
embargo, el formato UTF-7 y UTF-32 archivos se muestran incorrectamente. Todos los archivos se
han codificado correctamente; sin embargo, el Bloc de notas no es capaz de leer correctamente en
UTF-7 y UTF-32 archivos.
// C#
StreamReader sr = new StreamReader(@"C:\boot.ini");
StreamWriter sw = new StreamWriter("boot-utf7.txt", falso, la codificación UTF7);
Sw.WriteLine(sr.ReadToEnd();
Sw.Close();
Sr.Close();
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba su conocimiento de la información en la
lección 2, "la codificación y la descodificación." Las preguntas también están disponibles en el CD
de iones complementaria si prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final del
libro.
Términos clave
¿ Sabes lo que significan estos términos clave? Puede verificar sus respuestas mediante la
búsqueda de los términos en el glosario al final del libro.
■ página de código
■ expresión regular
■ Unicode
Casos
En los siguientes casos, podrá aplicar lo que ha aprendido sobre cómo val- idate entrada
utilizando expresiones regulares y cómo procesar archivos de texto con diferentes tipos de
codificación. Usted puede encontrar las respuestas a estas preguntas en la sección de
"respuestas" al final de este libro.
Caso práctico 1: Validación de las entradas
Su organización, Neptuno, está creando una aplicación basada en Web para permitir a los clientes
para introducir su propia información de contacto en su base de datos. Como un nuevo empleado,
se le asignará una tarea sencilla: crear la interfaz de front-end y preparar la entrada del usuario para
ser almacenados en una base de datos. Usted debe comenzar por varias entrevistas con el personal
de la empresa y revisar los requisitos técnicos.
Entrevistas
La siguiente es una lista de personal de la empresa entrevistados y sus declaraciones:
■ IT Manager "Esta es la primera asignación, así que estoy comenzando que fuera
fácil. Bofetada juntos una página Web que toma la entrada del usuario. Que deben
tomar, qué, cinco minutos?".
■ desarrollador de base de datos "simplemente abandona la entrada en cadenas
denominado "" CompanyName, ContactName "" y "" phoneNumber. Es entrar en
una base de datos back-end de SQL, pero voy a escribir ese código después de que
haya terminado. Oh, el "companyName" no puede tener más
A 40 caracteres, "contactName" está limitada a 30 caracteres, y "phoneNum- ber"
está limitada a 24 caracteres."
■ Jefe de Seguridad "Esta no es una tarea tan fácil como parece. Esta página va a
estar disponible al público en Internet, sucias, y hay un montón de sombreros
negros. Hemos obtenido cierta atención negativa en la prensa
Recientemente para nuestras prácticas de comercio internacional. Concretamente,
hemos irritado a cou- ple de grupos con estrechos lazos con organizaciones de
hackers. Acaba de hacer su mejor para limpiar la entrada, porque vas a ver algunos
malintencionados basura arrojada contra ustedes".
Requisitos técnicos
Crear una aplicación ASP.NET que acepta los siguientes elementos de información de los usuarios
y la valida rigurosamente:
■ El nombre de la empresa
■ Nombre de contacto
■ Número de teléfono
Preguntas
Responda las siguientes preguntas para el administrador:
1. ¿Cómo se puede restringir la entrada antes de escribir cualquier tipo de código?
2. ¿Cómo se puede limitar aún más la entrada escribiendo código?
Caso práctico 2: Procesamiento de datos desde un equipo
heredado
Usted es un desarrollador de aplicaciones de trabajo Seguros inmensos. Recientemente, ges-
tión decidió iniciar el proceso de migración de un sistema heredado (apodado "mainframe")
personalizado a las aplicaciones .NET Framework. Como parte de la reunión inicial para el
proyecto de migración, su jefe le pregunta acerca de cómo va a manejar varios desafíos.
Preguntas
Responda las siguientes preguntas para el administrador:
1. Mainframe almacena sus datos en una base de datos; sin embargo, los datos en
bruto no es en sí accesibles a nosotros a menos que podamos encontrar un
programador que sabe cómo escribir código para ese sistema. Podemos
generar los datos que necesitamos en informes basados en texto, sin embargo.
Es posible analizar el texto informes para extraer sólo los datos sin formato y
las etiquetas? Cómo se puede hacer eso, y qué clases y métodos que debe
utilizar?
2. Informes del mainframe están en formato ASCII. Puede manejar que ASCII?
Si es así, ¿cómo?
Prácticas recomendadas
Que le ayudarán a dominar los objetivos del examen se presenta en este capítulo, complete las
siguientes tareas.
Colecciones y genéricos
Colecciones de clases que se utiliza para agrupar y gestionar objetos relacionados que le permiten
iterar sobre esos objetos son una de las herramientas más básicas en cualquier Developer's
toolchest. Permiten almacenar, buscar, e iterar sobre colecciones de objetos. Colecciones toman
más en Matrices Matrices. son útiles, pero sin la riqueza de las colecciones la mayoría de las
aplicaciones nunca consigue despegar.
❑ clase Hashtable
❑ CollectionBase clase y clase ReadOnlyCollectionBase
❑ DictionaryBase clase y clase DictionaryEntry
❑ Comparer class
❑ clase Queue
❑ clase SortedList
❑ BitArray class
❑ clase Stack
■ Gestionar los datos en una aplicación .NET Framework mediante colecciones
especializadas. (Consulte la sección System.Collections.Specialized )
❑ especializado clases String
❑ diccionario especializado
❑ clase NameValueCollection
❑ CollectionsUtil
185
■ Mejorar la seguridad de tipos y el rendimiento de la aplicación en un archivo
.NET Framework aplica- ción mediante las colecciones genéricas. (Consulte
el espacio de nombres System.Collections.Generic)
❑ Colección.interfaces genéricas
❑ diccionario genérico
❑ Comparer genérico clase y clase EqualityComparer genérico
❑ estructura KeyValuePair genérico
❑ Una lista
genérica de clase, la lista Genérica.estructura de enumerador
y ordenar- edList clase genérica
❑ cola genérica de clase y cola genérica.estructura de enumerador
❑ SortedDictionary clase genérica
❑ LinkedList genérico
❑ una clase de pila genérica y Generic Stack.estructura de enumerador
Antes de empezar
Para completar las lecciones de este capítulo, debe estar familiarizado con Microsoft Visual
Basic o C# y cómodo con las siguientes tareas:
■ Crear una aplicación de consola en Microsoft Visual Studio, usando Visual Basic
o C#.
■ Sistema de agregar referencias a bibliotecas de clases
para un proyecto.
Mundo Real
Shawn Wildermuth
Las colecciones son el fundamento de la mayor parte de las aplicaciones se escribirá como
desarrollador. Prácticamente todas las aplicaciones que he desarrollado nunca ha utilizado
colecciones ampliar- clusivamente. Por ejemplo, he utilizado colecciones para almacenar listas
de mensajes de correo electrónico que estoy listo para procesar en un sistema de correo
electrónico que escribí hace algunos años.
Tipos de colecciones
.NET Framework el espacio de nombres System.Collections admite varios tipos de colectores-
ciones. Estas colecciones son clases que admiten la obtención de información en forma ordenada.
Su reto será discernir la colección para utilizarla en una instancia específica. La tabla 4-1 muestra
las colecciones más frecuentemente utilizado en el sistema.Colectores- nes de espacio de
nombres y para qué se utilizan.
Tabla 4-1 Tipos de colecciones
Nombre Descripción
Un simple resizeable ArrayList, basado en índices, colección de
objetos SortedList una recopilación ordenada de pares
nombre/valor de los objetos cola un primero en entrar,
primero en salir colección de objetos.
Una pila de último en entrar, primero en salir colección de objetos.
Hashtable una colección de pares nombre/valor de objetos que
permite la recuperación por nombre o índice
BitArray una colección compacta de valores
booleanos StringCollection una simple colección de cadenas
resizeable StringDictionary una colección de pares nombre/valor de
cadenas que permite
Por nombre o índice de recuperación
Nombre Descripción
ListDictionary una recaudación eficaz para almacenar pequeñas listas de
objetos
Una colección que utiliza HybridDictionary ListDictionary para
almacenamiento cuando el número de elementos de la
colección es pequeña, y después migra los elementos a
una Hashtable para grandes colecciones
NameValueCollection una colección de pares nombre/valor de cadenas que le
permite recuperar por nombre o índice
Todas estas colecciones se utilizan en una variedad de situaciones. Las primeras cuatro lecciones
de este capítulo le explicará cómo usar estas colecciones, así como cuándo utilizar que recogió-
ción. Para el resto de la lección 1, utilizaremos la colección ArrayList para almacenar y recuperar
objetos. ArrayList es la más básica de todas las colecciones.
Además de apoyar el método Add, el ArrayList admite el método AddRange para agregar una
gama de elementos, generalmente a partir de una matriz o de otra colección. El código siguiente
proporciona un ejemplo:
// C#
String[] anArray =
New string[] { "más", "o", "menos" };
Coll.AddRange(anArray);
Object[] = anotherArray
New Object[] { new Object(), new ArrayList(); }
Coll.AddRange(anotherArray);
El método AddRange admite la adición de un rango de elementos desde cualquier objeto que
admita la interfaz ICollection (que incluye todos los arrays, ArrayList de objetos, y la mayoría de
los colectores- nes tratadas en este capítulo).
Los métodos Add y AddRange agregar elementos al final de la colección. Porque Array- listas
son colecciones dinámicas, también permiten insertar objetos en ellos en posiciones específicas.
Para llevar a cabo su tarea, t un ArrayList también admite t él InsertRange inserta y métodos. El
código siguiente proporciona un ejemplo:
// C#
Coll.Insert(3, "Hola a todos");
String[] moreStrings =
New string[] { "Goodnight", "ya" };
Coll.moreStrings InsertRange(4);
// C#
Coll[3] = "Hola a todos".
Tenga en cuenta que utilizando el indizador no es lo mismo que usar el método Insert, como lo
establece el elemento en esa ubicación concreta en la colección sobrescribiendo el objeto antiguo
en esa posición en lugar de insertar un objeto.
Por último, el ArrayList apoya la eliminación de elementos de la colección. Tres métodos de
eliminación de elementos de apoyo: Quitar, RemoveRange RemoveAt , y. El método Remove
eliminará un objeto específico de la colección. No hay ninguna indicación de si el retiro no se
pudo encontrar el elemento que desea eliminar. En otras palabras, si no se encuentra el elemento en
la colección, quitar volverá sin lanzar una excepción. El método Remove es demostrado en el
ejemplo siguiente:
// C# coll.Add("Hello"); collQuitar("Hello");
// C#
// Elimina el primer elemento de ArrayList coll.RemoveAt(0).
// Quita los primeros cuatro artículos en ArrayList coll.RemoveRange(0, 4).
La clase ArrayList admite también algunos otros métodos que son útiles para agregar objetos y
eliminación de objetos de la colección:
■ El método Clear se usa para vaciar una colección de todos sus elementos.
■ El método IndexOf es utilizado para determinar el índice de un determinado
elemento de la colección.
■ El método Contains se utiliza para comprobar si un determinado objeto existe en
la colección.
Al utilizar estos métodos, puede realizar más compleja adición y eliminación de elementos dentro
de la colección, como se muestra en este ejemplo:
// C#
Cadena myString = "Mi cadena".
Si (collcontiene(Micadena)
{
Int index = collIndexOf(Micadena);
Coll.RemoveAt(index);
}
Otra cosa
{
Coll.Clear();
}
Ahora puede manipular los objetos de la colección, pero ¿cómo puede sacarlos de la colección?
Iterar a través de elementos
Una colección no es muy útil a menos que usted puede caminar a través de los elementos que
contiene. Afortunadamente, el ArrayList (como la mayoría de las colecciones en este capítulo)
admite varias maneras para iterar sobre su contenido. El ArrayList admite un indizador numérico
que permite escribir código sencillo, como la siguiente, para mostrar los elementos en orden (de
manera muy similar a como se haría con una matriz):
// C#
(Int x = 0; x < collcontar; ++x)
{
Console.WriteLine(coll[x]);
}
Nombre Descripción
Corriente obtiene el elemento actual de la colección que se enumera
Nombre Descripción
MoveNext mueve al siguiente elemento de la colección. El valor
devuelto por el método utilizado para determinar si el
enumerador ha llegado al final de la colección.
Restablecer Establece el empadronador antes del primer elemento de la
colección para permitir MoveNext para ser llamados a
obtener el primer elemento de la colección.
La construcción foreach especifica que está enumerando el coll de objetos y crear un objeto de
elemento para cada elemento de la colección. Esta construcción se basa en la interfaz
IEnumerable. Puede ser utilizado en cualquier colección que admite la interfaz IEnumerable. Una
de las ventajas de este esquema de iteración es que si usted tiene una colección de algunos tipos
conocidos, puede especificar el tipo de la construcción foreach para ahorrar tiempo en la fundición
de objetos, como se puede ver en este fragmento de código:
' VB
Dim newColl como nuevo newColl
ArrayList().Add("Hello") newColl.Add("Adiós").
// C#
ArrayList newColl = new ArrayList();
newColl.Add("Hello"); newColl.Add("Adiós");
Porque usted sabe que todos los elementos de la colección son cadenas, puede especificar
la cadena como el tipo de elementos para iterar. Si la colección había un elemento que no era una
cadena, el .NET Framework arrojaría un casting de excepción.
Interfaces consistentes en colecciones
Como se mencionó en la sección anterior, la interfaz IEnumerable se utiliza para
proporcionar un modo común para iterar en una colección. Además, .NET Framework admite
otra interfaz importante que debe ser implementada en el programa de aplicación- Ming de
interfaz (API) de una clase de colección. Esta interfaz se llama la interfaz ICollection y
deriva de la interfaz IEnumerable. Esto significa que cada colección que admita la interfaz
ICollection también debe admitir la interfaz IEnumerable.
El objetivo de esta interfaz es asegurar que cada colección admite una forma común de
obtener los elementos de una colección, así como una forma de copiar la colección a
un objeto Array. La interfaz ICollection más importante de propiedades y métodos se
muestran en la Tabla 4-4 y Tabla 4-5, respectivamente.
Tabla 4-4 ICollection Propiedades
Nombre Descripción
Conde obtiene el número de elementos de la colección
actualmente IsSynchronized obtiene un indicador de si la colección es
seguro para los subprocesos SyncRoot obtiene un objeto que
puede utilizarse para sincronizar el
Colec
ción
Nombre Descripción
CopyTo copia el contenido de una colección en una matriz.
Para simple lista de colecciones (como ArrayList), el .NET Framework admite una interfaz
que se utiliza para exponer las listas de elementos. Esta interfaz se llama la interfaz IList y
deriva directamente de la interfaz ICollection. Si una clase admite la interfaz IList, debe
apoyar también la interfaz ICollection e interfaces IEnumerable. Esta
coherencia de interfaces simplifica la forma en que trabajamos con colecciones en general.
La mayoría de la interfaz IList debe resultarle familiar a usted en este punto. En la sección
"Agregar y Quitar elementos" anteriormente en este capítulo, la mayoría de estas propiedades
y métodos fueron cubiertos como parte de la clase ArrayList. La interfaz IList es más
importante prop- erties y métodos se muestran en la Tabla 4-6 y Tabla 4-7, respectivamente.
Tabla 4-6 IList Propiedades
Nombre Descripción
IsFixedSize obtiene un indicador de si esta colección puede ser
redimensionado IsReadOnly obtiene un indicador de si una colección
puede ser cambiado Item obtiene o establece el elemento de un
índice específico de la colección
Nombre Descripción
Add agrega un elemento a la colección
Clear borra la colección de todos los elementos
Contiene tests si un elemento está contenido en la colección
IndexOf Finds un elemento en la colección, y devuelve el índice del
elemento
Inserte agrega un elemento a un índice específico de la colección
Quitar Quita la primera aparición del objeto especificado en la
colección
RemoveAt quita un elemento en un índice específico de la colección
Ordenar elementos
El ArrayList admite un método para ordenar los elementos de una colección. Para ordenar los
elementos dentro de un
ArrayList, basta con llamar al método Sort de ArrayList así:
// C#
Coll.Sort();
Condición de valor
Menor que cero el objeto izquierdo es menor que el objeto de derecho. Los
objetos son iguales a cero.
Más de cero a la izquierda es el objeto más que el objeto de derecho.
Escribir su propio comparer es relativamente sencillo, ya que sólo requiere que usted para
implantar el método Compare de la interfaz IComparer. Por ejemplo, si quería hacer la
comparación en sentido inverso (resultando en una colección clasificada en orden descendente),
puede escribir una clase comparador rápido así:
// C#
Public Class DescendingComparer : IComparer
{
CaseInsensitiveComparer _comparer = new CaseInsensitiveComparer();
// C#
Coll.Sort(nueva DescendingComparer();
// C#
Utilizando System.Collections.
Programa de clase
{
Static void main(String[] args)
{
ArrayList myList = new ArrayList();
myList.Add("First"); myList.Add("Segundo");
myList.Add("tercera"); myList.Add("Cuarta");
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba su conocimiento de la información en la
lección 1, "Recopilación de datos Artículos." Las preguntas también están disponibles en el CD
complementario si prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final del
libro.
Nombre Descripción
Conde obtiene el número de elementos en la cola.
Nombre Descripción
Dequeue recupera un elemento desde la parte delantera de la cola,
eliminando al mismo tiempo
Enqueue agrega un elemento al final de la cola.
Peek recupera el primer elemento de la cola sin quitarlo
realmente
Trabajar con la clase Queue es muy sencillo. Una vez que tenga una instancia de la clase,
puede utilizar el método Enqueue para agregar elementos a la cola y el método Dequeue
para quitar elementos de la lista, como se demuestra en este breve ejemplo:
// C#
La cola q = nueva cola();
q.Enqueue("Un tema");
Console.WriteLine(q.Dequeue();
La clase Queue permite agregar elementos duplicados y valores nulos, por lo que no se puede
comprobar el resultado de la cola o el método Peek para ver si la cola está vacía. Para ello,
puede comprobar la propiedad Count para ver si la colección está vacía. Por ejemplo, si
agrega elementos a la cola y desea eliminarlos y mostrarlas en la consola, se puede escribir un
código como el siguiente:
// C#
La cola q = nueva cola();
Q.Enqueue("First");
q.Enqueue("Segundo"
);
q.Enqueue("tercera");
q.Enqueue("Cuarta");
Porque la cola es una colección de FIFO, en el ejemplo anterior se producirá la fol- bramido
orden de visualización en la ventana de la consola:
Primer Segundo Tercer cuarto
Hay momentos en el que ser capaz de mirar al siguiente elemento sin quitar realmente es una
buena idea. Imagínese si usted tenía algún código que podría trabajar con determinados tipos
de objetos. Si usted fuera a Dequeue y luego descubre que alguien tenía que manejar, usted
podría poner de nuevo en la cola, pero perdería su lugar en la línea. Ahí es donde entra en
juego el método Peek, como se muestra en este ejemplo:
// C#
Si (q.Peek() es una cadena)
{
Console.WriteLine(q.Dequeue();
}
Nombre Descripción
Conde obtiene el número de elementos de la pila
Nombre Descripción
Pop recupera un elemento desde la parte superior de la pila,
eliminando al mismo tiempo
Push agrega un elemento a la parte superior de la pila
Peek recupera el elemento superior de la pila sin extraerlo
Trabajar con la clase Stack es similar a trabajar con la clase Queue, pero en lugar de
enqueuing y cola, que están empujando en y saltando fuera de la pila. Una vez que tenga una
instancia de la clase, se utiliza el método Push para agregar elementos a la pila y el método
Pop para eliminar elementos de la pila, como se muestra en este breve ejemplo:
// C#
Pila s = new Stack(); s.("push");
un elemento
Console.WriteLine(s.Pop();
Como con la clase Queue, puede agregar duplicados y valores nulos, por lo que no se puede
comprobar el resultado del pop o método Peek para ver si la pila está vacía. Por ejemplo, si
agrega elementos a la pila y desea eliminarlos y mostrarlas en la consola, se puede escribir un
código como el siguiente:
// C#
Pila s = new Stack();
Debido a que la pila es una colección LIFO, el orden de los resultados de este código están
invertidas, por lo que vimos anteriormente en la clase Queue ejemplo:
Cuarto Segundo tercio
Primera
// C#
Utilizando System.Collections.
Programa de clase
{
Static void main(String[] args)
{
Cola = nueva cola();
La cola.Enqueue("First"); la
cola.Enqueue("Segundo");
la cola.Enqueue("tercera");
la cola.Enqueue("Cuarta");
// C#
Stack pila = new Stack();
Stack.push("First");
stack.push("Segundo");
stack.push("tercera");
stack.push("Cuarta");
Mientras (pila.Count > 0)
{
Object OBJ = stack.Pop(); Console.WriteLine("de la
pila: {0}", obj);
}
Resumen de la lección
■ El .NET Framework admite la cola y pila para ofrecer clases de colectores-
ciones que representan las listas secuenciales de elementos.
■ La cola es el primero en entrar, primero en salir (FIFO) colección.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba su conocimiento de la
información en la lección 2, "Trabajar con las listas secuenciales." Las preguntas
también están disponibles en el CD complementario si prefiere revisarlos en forma
electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final
del libro.
1. Lo que hace el método Dequeue de la clase Queue? (Seleccione todos los que
correspondan).
A. Recupera un elemento desde la parte frontal de la colección
B. Agrega un elemento a la colección
C. Elimina el primer elemento de la colección
D. Borra la colección
2. ¿En qué orden hace una pila recuperar elementos que use su método pop?
A. Orden aleatorio
B. Primero en entrar, primero en salir
C. Último en entrar, primero en salir
D. El último, último-out
Lección 3: trabajar con diccionarios
En el otro extremo del espectro de las listas secuenciales son diccionarios. Los
diccionarios son colecciones que están diseñados para almacenar listas de pares
clave/valor para permitir la búsqueda de valores basados en una clave.
Utilizando un diccionario.
El diccionario clases compatibles con .NET Framework se utiliza para asignar una clave a un
valor. Básicamente, éstas existen para permitir crear tablas de búsqueda que se pueden
correlacionar arbi- claves arbitrarias a valores arbitrarios. En el caso más básico, la clase
Hashtable se utiliza para realizar esta asignación de pares clave/valor. Por ejemplo, supongamos
que usted necesita para asignar direcciones de correo electrónico para el nombre completo del
usuario. Usted podría utilizar una tabla hash para almacenar este mapa- ping, como se ve en este
fragmento de código:
// C#
= new emailLookup Hashtable Hashtable();
A diferencia de los anteriores tipos de colecciones, diccionarios siempre esperar dos pedazos de
información para agregarlos a la colección: una clave y un valor. Este ejemplo nos muestra dos
maneras de agregar elementos a nuestra colección. En primer lugar, el método Add nos permite
añadir un elemento especificando el par clave/valor. Además, puede usar el indizador para
especificar un par clave/valor especificando la clave en el indizador y asignar el valor que desee
para que apunte a la clave.
Recuperar objetos de un diccionario también es sencillo. Para acceder a los datos una vez que se ha
agregado al diccionario (aquí, un Hashtable), simplemente llame al indizador con la clave que está
buscando:
// C# Console.WriteLine(emailLookup["sbishop@contoso.com"]);
Diccionarios porque están hechas para buscar pares clave/valor, no es una sorpresa que la iteración
a través de los objetos en un diccionario no es sencillo. Por ejem- plo, suponga que ha creado
una Hashtable y desea iterar sobre todos los valores. El código para llevar a cabo esta tarea podría
tener este aspecto:
// C#
= new emailLookup Hashtable Hashtable();
Usted podría esperar que esto le mostrará los nombres de cada persona en la vari- emailLookup
capaz. Lo que realmente se escriben en la consola es esta:
System.Collections.DictionaryEntry
System.Collections.DictionaryEntry
System.Collections.DictionaryEntry
¿Por qué sucede esto? Sucede porque en realidad se está repasando las entradas del objeto
Dictionary, no las claves o los valores. Si desea que este código para escribir los nombres de los
usuarios, se podría cambiar el iterador para trabajar con estos objetos DictionaryEntry, así:
' VB
Para cada entrada como en emailLookup DictionaryEntry
Console.WriteLine(entry.Value) Siguiente entrada
// C#
Foreach (Entrada de DictionaryEntry emailLookup)
{
Console.WriteLine(entrada.Value);
}
Nombre Descripción
Teclas ICollection obtiene un objeto que contiene una lista de las
claves de la colección
Obtiene valores ICollection object que contiene una lista de los
valores de la colección
Nombre Descripción
Add agrega un par clave/valor a la colección.
Borrar Elimina todos los elementos de la colección.
Contiene pruebas si una tecla específica contenida en la colección.
GetEnumerator devuelve un objeto IDictionaryEnumerator para la colección.
Este método es diferente del método con el mismo nombre en
la interfaz IEnumerable que devuelve una interfaz IEnumer-
ador.
Eliminar Elimina el elemento en la colección que corresponde a
una clave específica.
Nombre Descripción
ContainsKey determina si la colección contiene una clave específica
ContainsValue determina si la colección contiene un valor específico
La comprensión de la igualdad
La clase Hashtable es un tipo específico de la clase de diccionario que utiliza un valor entero
(llamado un hash) para ayudar en el almacenamiento de sus claves. La clase Hashtable utiliza el
hash para acelerar la búsqueda de una clave específica en la colección. Cada uno de los objetos
de .NET se deriva de la clase Object. Esta clase admite el método GetHash, que devuelve un
número entero que identifica el objeto.
¿Por qué el hecho de que la clase Hashtable es almacenar un valor hash importa el desarrollador?
La Hashtable permite hash únicos de valores, no valores únicos. Si intenta almacenar la misma
tecla dos veces, la segunda llamada que sustituye a la primera llamada, tal como se muestra en este
ejemplo:
// C#
Duplicados = new Hashtable Hashtable();
Duplicados["Primer"] = "1st";
Duplicados["Primer"] = "la primera";
Console.WriteLine(duplicados.Count); // 1
// C#
Clase pública de pescado
{
Nombre de cadena.
Peces pública(string) theName
{
Nombre = el nombre;
}
}
Ahora si queremos crear dos instancias de la clase de peces con el mismo nombre, la Hashtable
Los trata como objetos diferentes, como se muestra en el siguiente código:
// C#
Duplicados = new Hashtable Hashtable();
Pescar peces nuevos key1 =(""); arenque
pescado key2 = new pescararenque("");
Duplicados[clave1] = "Hola";
Duplicados[clave2] = "Hola";
Console.WriteLine(duplicados.Count); // 2
¿Por qué hay dos elementos en la colección que tienen el mismo nombre? La colección duplicados
almacena dos elementos en este ejemplo porque la clase Object la implementación
de GetHashCode crea un hash que es probable que sea único para cada instancia de una clase.
Usted podría invalidar el GetHashCode en la clase de peces a tratar y deje la Hashtable sepa que
son iguales, de la siguiente manera:
// C#
Anulación pública int GetHashCode()
{
Volver nombre.GetHashCode();
}
Si devuelve el valor hash del nombre del pez, las dos instancias de los peces tendrán el mismo
código hash. Pero eso es suficiente para la Hashtable para determinar son objetos idénticos?
Desafortunadamente, no. Si la Hashtable encuentra dos objetos con el mismo hash, se llama a
su método Equals para ver si los dos objetos son en realidad iguales. De nuevo, la implementación
predeterminada del objeto.Equals devolverá false si los dos objetos son dos instancias diferentes
de la misma clase. Por lo tanto necesitamos agregar también un reemplazo del método Equals para
nuestra clase de pescado:
// C#
Anulación pública bool Equals(object obj)
{
Fish otherFish = obj como peces;
Si (otherFish == null) return false;
Volver otherFish.name == nombre;
}
Aquí podemos probar para ver si el otro objeto es también un pescado y, en caso afirmativo,
comparar el nombre para probar si los dos objetos son iguales. Sólo entonces la clase Hashtable
pueda determinar si dos teclas son idénticos.
Utilizando la interfaz IEqualityComparer
Además de poder cambiar sus clases para proporcionar igualdad, usted podría encontrar que es
necesario proporcionar la igualdad fuera de la clase. Por ejemplo, supongamos que desea
almacenar las claves en la Hashtable como cadenas, pero la necesidad de ignorar el caso de la
cadena. Cambiar la clase String para admitir esto o crear su propia clase String que se distingue
entre mayúsculas y minúsculas sería una solución dolorosa. Esta situación es donde la Hashtable's
capacidad de usar una clase que calcula la igualdad entra en juego.
La clase Hashtable admite un constructor que puede aceptar una instancia de la interfaz
IEquality- Comparer como argumento. Muy parecida a la interfaz IComparer mostrado en la
lección 1 que te permitía ordenar colecciones, la interfaz IEqualityComparer admite dos métodos:
GetHashCode y Equals. Estos métodos permiten que el comparador clase para manejar la igualdad
para los objetos en lugar de depender de los objetos para proveerlos. Por ejemplo, el código
siguiente crea un sencillo comparador insensible a mayúsculas y minúsculas, de modo que usted
puede hacer sus claves de cadena no distingue entre mayúsculas y minúsculas:
// C#
Public Class InsensitiveComparer : IEqualityComparer
{
CaseInsensitiveComparer _comparer = new CaseInsensitiveComparer();
Dehash("Primero") = "1st"
dehash("Segundo") = "2nd"
dehash("tercera") = "3rd"
dehash("Cuarta") = "4th" dehash("cuarta")
= "4th"
Console.WriteLine(dehash.Count) ' 4
// C#
= new dehash Hashtable Hashtable(new InsensitiveComparer());
Dehash["Primer"] = "1st";
dehash["Segundo"] = "2nd";
dehash["Tercera"] = "3rd";
dehash["Cuarta"] = "4th"; dehash["cuarta"]
= "4th";
Console.WriteLine(dehash.Count); // 4
Porque usted está utilizando este case-insensitive igualdad en la creación del objeto Hashtable se
termina con sólo cuatro elementos en la colección. Se trata de "cuarto" y "cuarto" como idénticos.
La Hashtable es una gran clase para crear tablas de búsqueda, pero hay veces cuando lo que
realmente necesita es ordenar un conjunto de elementos por algún valor de clave. Cuando se
procesa una iteración
A través de la clase Hashtable, devuelve los elementos en el orden de su valor hash. Ese orden no
es práctico para la mayoría de las situaciones. La SortedList es una clase de diccionario que admite
la ordenación.
Nombre Descripción
Capacidad obtiene o establece el número de elementos asignados
actualmente para la colección. Este es el número total de franjas
horarias asignadas actualmente para los elementos, no el número
de elementos de la colección. (Conde le dará el número de
elementos de la colección).
Nombre Descripción
ContainsKey determina si la colección contiene una clave
específica ContainsValue determina si la colección contiene un valor
específico GetByIndex recupera el valor a un índice específico de la
colección GetKey recupera la clave en un índice específico de la
colección GetKeyList recupera una lista ordenada de las teclas.
GetValueList recupera una lista de valores.
IndexOfKey obtiene el índice de una clave de la colección
IndexOfValue obtiene el índice de la primera ocurrencia del valor especificado
en la colección
RemoveAt quita un valor específico en la colección por
index SetByIndex sustituye un valor a un índice específico de la
colección TrimToSize utiliza para liberar la capacidad no utilizada en
la colección
Como se puede observar en estas tablas, SortedList agrega una serie de métodos de acceso a los
datos por el número de índice. La clase es compatible con la recuperación de las claves y los
valores de índice, y también admite mirando para recuperar su índice. Porque esta clase está
ordenada, el índice de un elemento puede cambiar a medida que se agregan o eliminan elementos.
Puede utilizar el mismo proceso que aprendió en la lección 1 para ordenar una
colección SortedList. En lugar de requerir que usted llame a Ordenar para ordenar
elementos, SortedList realiza cuando se agregan elementos de ordenación. Con esto en mente, se
puede especificar un IComparer al crear el SortedList, de modo que puede controlar la forma en
que ocurre la ordenación. Si usted pide prestada la clase DescendingComparer que fue explicado
en la lección 1, puede modificar el código para incluir la clase DescendingComparer, así:
// C#
SortedList ordenar = new SortedList(new DescendingComparer());
Ordenar["Primer"] = "1st";
ordenar["Segundo"] = "2nd";
ordenar["Tercera"] = "3rd";
sort["Cuarta"] = "4th";
Ahora la clasificación está en orden descendente (recuerde que el orden es el orden alfabético por
el nombre, no el número):
Tercera = 3er
segundo = 2º
Cuarto = 4A
Primera = 1
Diccionarios especializados
Hay momentos en los diccionarios estándar ( ) y Hashtable SortedList limita- ciones, ni las
limitaciones funcionales o de rendimiento relacionados. Para cerrar esa brecha, el .NET
Framework admite otros tres diccionarios: ListDictionary HybridDictionary OrderedDictionary, ,
y
ListDictionary
La clase Hashtable es una colección muy eficiente en general. El único problema con la clase
Hashtable es que requiere un poco de sobrecarga, y para colecciones pequeñas (menos de 10
elementos) los gastos generales pueden obstaculizar el desempeño. Ahí es donde la lista- viene en
el diccionario. Está implementado como una simple matriz de elementos debajo del Capó, así que
es muy eficiente para pequeñas colecciones de elementos. La ListDictionary clase tiene la misma
interfaz que la clase Hashtable, así que puede ser utilizado como reemplazo. Para demostrar, aquí
está el ejemplo usado Hashtable con anterioridad. Esta vez, sin embargo, estamos
utilizando ListDictionary. Tenga en cuenta que ninguno de los código es diferente excepto para los
con- struction del objeto:
// C#
HybridDictionary
OrderedDictionary
Hay veces cuando desee disponer de la funcionalidad de Hashtable pero usted necesidad de con-
trol el orden de los elementos en la colección. Cuando se agregan elementos a una Hashtable, dos
cosas son ciertas: no hay forma de acceder a los elementos por index; y si utiliza un enumerador
para superar esta limitación, los elementos están ordenados por su valor hash. Usted podría utilizar
un SortedList, pero que asume que desea los elementos se ordenan en el orden proporcionado por
las teclas. Quizás sólo hay un ordinal orden?
Para dar cabida a usted cuando usted necesita un diccionario rápido sino también a la necesidad de
mantener los elementos en forma ordenada, el .NET Framework admite la OrderedDictionary.
Un OrderedDictionary es mucho como una Hashtable excepto que tiene métodos adicionales y
prop- erties-como se ve en la tabla 4-18 y la tabla 4-19, respectivamente, para permitir el acceso a
los elementos de índice.
La tabla 4-18
OrderedDictionary propiedades Extra
Nombre Descripción
Tema sobrecargado para respaldar el acceso por índice
La tabla 4-19
OrderedDictionary Métodos
adicionales
Nombre Descripción
Insert inserta un par clave/valor a un índice específico de la colección
RemoveAt quita un par clave/valor a un índice específico de la
colecció
Estas adiciones a la interfaz de la clase le permiten tratar con la colección como si la clase eran una
mezcla de ArrayList y Hashtable.
Programa de clase
{
Static void main(String[] args)
{
Consulta de Hashtable = new Hashtable();
Lookup["0"] = "Cero";
lookup["1"] = "uno";
lookup["2"] = "dos";
lookup["3"] = "tres";
lookup["4"] = "cuatro";
lookup["5"] = "5"; lookup["6"] =
"6"; lookup["7"] = "7";
lookup["8"] = "8"; lookup["9"] =
"9";
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba su conocimiento de la información en la
lección 3, "trabajar con diccionarios." Las preguntas también están disponibles en los com- panion
CD si usted prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final del
libro.
1. Cuando se agrega una clave para una Hashtable, lo que se puede llamar a métodos
en la clave para determinar si la clave es única? (Seleccione todos los que
correspondan).
A. GetType
B. GetHashCode
C. ToString
D. Es igual a
2. Cuál de las siguientes afirmaciones es verdadera?
A. Puede pasar una instancia de una clase que admite la interfaz
IEqualityComparer cuando construya una Hashtable para cambiar la forma
de claves se eval- uated de unicidad.
B. Puede asignar un IEqualityComparer objeto Hashtable existente.
C. No puede utilizar un IEqualityComparer con una Hashtable.
D. Una Hashtable implementa IEqualityComparer.
Lección 4: Uso de las Colecciones Especializadas
Las tres primeras lecciones en este capítulo presenta una serie de colecciones que se pueden
utilizar para almacenar cualquier objeto en .NET. Aunque estas son herramientas valiosas,
utilizando a menudo puede llevar a tener que convertir objetos cuando se recupere de las
colecciones. El .NET Framework admite un nuevo espacio de nombres
llamado System.Collections.Specialized que incluye colecciones que están diseñados para
trabajar con tipos específicos de datos.
// C#
BitArray bits = nuevo BitArray(3).
Bits[0] = false; bits[1] = true;
los bits[2] = false;
BitArray moreBits = new BitArray(3).
Bits[0] = true; los
bits[1] = true; los
bits[2] = false;
// C#
Console.WriteLine("{0} debe ser de 3", vector.data).
BitVector32 le permite crear secciones de la estructura que se utilizará para almacenar los números
de ciertos tamaños. Así que antes de empezar, necesitará crear las secciones. Esto se hace en
mucho la misma manera como usted crear máscaras, pero necesitará especificar el número más
grande que la sección puede almacenar. Por lo tanto, si usted utiliza el ejemplo anterior de 10, 50 y
500, tendría que crear las secciones así:
// C#
BitVector32.Sección = firstSection
BitVector32.CreateSection(10);
BitVector32.Sección secondSection =
BitVector32.CreateSection(50); firstSection
BitVector32.Sección thirdSection =
BitVector32.CreateSection secondSection(500).
Al igual que el , el CreateSection CreateMask utiliza la última sección para determinar dónde
"Pack" el nuevo número.
Una vez que tienes las secciones, puede establecer y obtener mediante el indizador y la nueva
sección variables, como se muestra aquí:
// C#
BitVector32 = new packedBits BitVector32(0).
PackedBits[firstSection] =
10; packedBits[secondSection] =
1; packedBits[thirdSection] = 192;
Console.WriteLine(packedBits[firstSection]);
Console.WriteLine([secondSection packedBits]);
Console.WriteLine([thirdSection packedBits]);
Después de haber trabajado con las secciones, puede obtener la propiedad Data 'sitVector32 para
mantener el número subyacente que contiene los tres números empaquetados en:
// C# Console.WriteLine(packedBits.data).
// 98314
Console.WriteLine(packedBits);
BitVector32 //{00000000000000011000000000001010}
Usted podría hacer los cálculos para averiguar que el número 98314 puede almacenar 10, 1 y 192,
pero el BitVector32 puede hacerlo por usted con mucho menos trabajo.
Las cadenas de recolección
Probablemente el tipo más común de objeto que necesita almacenar en una colección son cadenas.
Para satisfacer esta necesidad, el .NET Framework admite dos col especializados- ciones que son
fuertemente tipados para almacenar cadenas: StringCollection y StringDictionary.
// C#
StringCollection coll = new StringCollection();
Coll.Add("Primero");
coll.Add("Segundo");
coll.Add("tercera");
coll.Add("Cuarta");
coll.Add("cuarta");
// Coll.Add(50); <- no compila...no una cadena
Las líneas que agregue las cadenas a la colección tiene el mismo aspecto que los anteriores
ejemplos utilizando el ArrayList. La única diferencia es que la adición de un nonstring genera un
error de compilación. (Véase la línea comentada.) Además, cuando se recupera la cadena, usted ya
no está trabajando con objetos sino con cadenas. Esto reduce la necesidad de conversión al
recuperar los elementos.
// C#
StringDictionary dict = new StringDictionary();
Dict["Primer"] = "1st";
dict["Segundo"] = "2nd";
dict["Tercera"] = "3rd";
dict["Cuarta"] = "4th";
dict["cuarta"] = "cuarto".
// Dict[50] = "51"; <- no se compilará...no una cadena
Es importante entender que las claves son sensibles a mayúsculas y minúsculas por omisión
para la cadena- objetos de diccionario, por lo que las teclas "cuarto" y "cuarto" son
equivalentes.
Colecciones Case-Insensitive
Como vimos anteriormente en este capítulo, puede controlar la comparación o la igualdad
mediante la interfaz IComparer y IEqualityComparer. Uno de los usos más comunes de
estas interfaces es crear case-insensitive colecciones de diccionarios. Como éste es un uso
común, el .NET Framework tiene una clase CollectionsUtil que admite la creación
de Hashtable SortedList y objetos que son insensibles a mayúsculas y minúsculas. Su uso es
tan sencillo como llamar o
CreateCaseInsensitiveHashtable CreateCaseInsensitiveSortedList. El siguiente fragmento de
código proporciona un ejemplo:
// C#
Tabla Hashtable =
CollectionsUtil.CreateCaseInsensitiveHashtable();
Tabla["hello"] = "Hola"; la tabla["Hola"] =
"Heya"; Console.WriteLine(Tabla.Count); // 1
SortedList inList =
CollectionsUtil.CreateCaseInsensitiveSortedList();
InList["hello"] = "Hola"; inList["Hola"] =
"Heya"; Console.WriteLine(inList.Count); // 1
Colecciones Culture-Invariant
El comportamiento predeterminado de las colecciones es utilizar la cultura actual del
subproceso. Esto significa que las comparaciones son dependientes en las normas de la cultura
actual. Cuando se utilizan comparaciones, asegurándose de que los objetos son únicos ingenio
hin colecciones así como al ordenar elementos en colecciones ordenadas (o al insertar
elementos en ordenados colectores- ciones como SortedList).
Dependiendo de sus necesidades específicas, podría ser importante para hacer las
comparaciones en una cultura-invariante, sin tener en cuenta la cultura actual o de cualquier
cultura. Esta situación surge con las aplicaciones Web y las aplicaciones que necesitan
almacenar infor- mación a través de las culturas. ¿Qué piensa que sucedería si usted almacena
una lista que tenía el inglés, español, hebreo y persa llaves? ¿Cómo se puede esperar que la
serie se producen. En la mayoría de estos casos, usted debe crear colecciones que no son
afectados por el (invariantes) con respecto a la cultura actual. A diferencia de case-insensitive
colecciones, métodos CollectionsUtil no se puede utilizar para crear sus colecciones. En su
lugar, debe especificar la nueva colección con nuevas instancias de un objeto
StringComparer que per- para ms una cadena que distingue entre mayúsculas y minúsculas
comparación utilizando t él palabra R eglas comparación invariantes de la cultura. Por
ejemplo, es posible que desee crear una nueva y Hashtable SortedList con ambos casos la
insensibilidad y la invariante de la cultura. El código debe tener este aspecto:
/
/
C
#
Hashtable Hashtable = nuevo
hash( StringComparer.InvariantCulture);
SortedList list = new
SortedList( StringComparer.InvariantCul
ture);
Con la clase NameValueCollection, puede almacenar varios valores por clave. Puede hacerlo
con el método Add. Para recuperar todos los valores de una clave determinada, puede utilizar
el método GetValues así:
/
/
C
#
NameValueCollection nv = new NameValueCollection();
Nv.Añadir("Key", "Texto");
Nv.Añadir("Key", "Más texto");
// C#
Nv["Primer"] = "1st";
Nv["Primer"] = "primera".
Nv.Add("Segundo", "2nd");
Nv.Add("Segundo", "Segundo");
Console.WriteLine(nv.GetValues("Primero").Length);
// 1
Console.WriteLine(nv.GetValues("Segundo").Length);
// 2
// C#
NameValueCollection nv = new NameValueCollection();
Nv.Add("primero", "1st");
nv.Add("Segundo", "2nd");
nv.Add("Segundo", no "Primera");
Programa de clase
{
Static void main(String[] args)
{
Console.Read();
}
}
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba su conocimiento de la información
en la lección 4, "Uso de colecciones especializadas." Las preguntas también están disponibles
en el CD complementario si prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final
del libro.
MyInts.Add(1);
myInts.Add(2);
myInts.Add(3).
Todo es bueno; puede crear una colección y agregar números enteros. Usted puede conseguir su
enteros de la colección lanzando desde el objeto que devuelve su colección. Pero lo que si se añade
una línea como la siguiente:
// C#
MyInts.Add("4");
Este compilará bien, pero en el bucle foreach se producirá una excepción porque el 4 es una
cadena y no un entero. Tratar con tales excepciones menores es problemático. Sería mejor si usted
podría tratar con la colección de modo que sólo puede almacenar inte- Gers. Usted podría escribir
una nueva clase que tiene este comportamiento, como se muestra en el siguiente fragmento de
código:
// C#
Public Class IntList : ICollection, IEnumerable
{
ArrayList privado _innerList = new ArrayList();
Para resumir, se crea una nueva colección que apoya la colección básica inter- faces
(ICollection e IEnumerable). Se utiliza un ArrayList para realmente hacer la recolección de
elementos. Por último, haces un método Add y un indizador que son fuertemente tipados en
enteros. Ahora puede utilizar esta clase de la siguiente manera:
'// C#
Nueva IntList IntList myIntegers =();
Esta clase es idéntica a la colección creada anteriormente en el capítulo, pero en lugar de hacer una
colección de enteros, usaremos un parámetro de tipo genérico T. En cada lugar que habíamos
enteros, vamos a poner ahora el parámetro T. Esta T es reemplazado con el nombre de tipo
durante la compilación. Por lo tanto, podemos usar esta clase para crear colecciones con
establecimiento inflexible de tipos que son válidos para cualquier tipo de .NET, como se muestra
en el ejemplo siguiente:
// C#
MyList<int> myIntList = new MyList<int>();
MyIntList.Add(1).
// MyIntList.Add("4"); no compila!
MyList<String> myStringList = new MyList<String>();
MyStringList.Add("1");
// MyStringList.Add(2); // no compila!
Cuando se usa esta clase genérica, usted simplemente tiene que incluir el parámetro genérico (el
nombre de un tipo) en la creación de la instancia. En el primer ejemplo se crea el inte- ger
colección queríamos, pero la misma clase genérica puede también crear una cadena colección o
una colección de cualquier tipo en .NET, incluso su propio.
Los medicamentos genéricos son utilizados en diferentes lugares dentro de .NET Framework, pero
los medicamentos genéricos, verá con más frecuencia son las clases de colecciones genéricas.
Observe que no necesitará a cre- comió su propia lista genérica collection-las clases de colección
genéricas en el marco ya tienen uno…y muchos más.
Mejora de la seguridad y el rendimiento
En .NET Framework, los equivalentes genéricos existen para la mayoría de las clases ya
examinadas en este capítulo. Además, existen varias nuevas colecciones que están disponibles sólo
como tipos genéricos. En esta sección se proporcionan ejemplos de cómo utilizar cada uno de estos
tipos. Tabla 4-20 enumera los tipos discutidos, junto con una asignación a sus equivalentes de tipo
genérico.
Tabla 4-20 tipos genéricos
equivalentes
Tipo tipo genérico
Lista de ArrayList<> Cola<> pila
Stack<><> Diccionario Hashtable
SortedList SortedList<> ListDictionary
Dictionary<><> OrderedDictionary
HybridDictionary Diccionario Dictionary<>
SortedDictionary SortedDictionary<>
NameValueCollection DictionaryEntry
KeyValuePair Dictionary<><>
Como se puede ver en la tabla 4-20, la mayoría de las clases que han aprendido a utilizar en este
capítulo tienen un equivalente genérico. El único tipo de colección que es nuevo es la clase
LinkedList, que será cubierto en breve.
IntList.Add(1).
IntList.Add(2).
IntList.Add(3).
Int número = intList[0];
La clase de lista genérica es tan fácil de usar como el ArrayList, pero de tipo seguro basado en el
parámetro de tipo genérico. Como vimos la lección 1, podemos ordenar una lista llamando
al método Sort. No es diferente para la clase de lista genérica, pero hay una nueva sobrecarga que
vale la pena mencionar. El método de clasificación en la lista genérica clase admite un delegado
genérico.
¿Qué son los delegados genéricos? Son simplemente como estructuras o clases genéricas, pero
parámetros genéricos sólo se utilizan para definir la convención de llamada del delegado. Por
ejem- plo, el método Sort de la clase genérica List tiene una comparación genérica delegado.
La comparación genérica delegado se define de la siguiente manera:
// C#
Delegado público int comparación><T ( T x,
Ty
)
Suponga que desea ordenar la lista en orden inverso. Usted podría escribir todo
un com- parer clase para hacer esto. O usted puede hacer las cosas más fáciles y acaba de escribir
un método que coincide con el delegado genérico, como se muestra aquí:
// C#
Static int ReverseIntComparison(int x, int y)
{
Volver y - x;
}
Observe que este método no es genérico, pero coincide con el genérico Delegado de comparación.
(La lista se compone de números enteros, así que tu comparación debe utilizer Los números
enteros para los dos parámetros.) Esta coherencia le permite llamar a la función sort con su método
para llamar a cada comparación:
// C#
ReverseIntComparison intList.Sort();
Este enfoque es mucho más fácil que escribir toda una clase de comparación para comparaciones
poco utilizados.
// C#
Cadena Queue<> q = nueva cola<> String();
Q.Enqueue("Hello");
Cadena = cola cola.Dequeue();
Un tipo de pila genérico es igual de fácil de usar. Puede crear una instancia de la pila Clase y
realice una de las siguientes acciones:
■ Puede utilizar Push para agregar elementos a la pila, pero los elementos debe
coincidir con el tipo especificado en el parámetro de tipo genérico de la pila.
■ también puede usar Pop para recuperar elementos del tipo de pila. Por ejemplo,
esta pila Almacena enteros:
// C#
Stack<int> series = new Stack<> int();
Serials.Push(1).
SerialNumber = int serials.Pop();
// C#
Dictionary<int, string> dict = new Dictionary<int, string>();
Dict[3] = "tres"; dict[4] =
"cuatro"; dict[1] = "uno";
dict[2] = "dos"; String str =
dict[3];
En este ejemplo se muestra cómo utilizar un entero para la clave del diccionario y cómo utilizar
una cadena para el contenido. Una diferencia importante entre la clase Dictionary genérica y sus
homólogos no genéricos es que no utilice un objeto DictionaryEntry para mantener el par
clave/valor. Así que cuando usted recupera objetos individuales o iterar sobre la colección,
necesitará trabajar con un nuevo tipo genérico llamado KeyValuePair.
La clase KeyValuePair genérico tiene dos tipos al igual que la clase Dictionary genérica.
Normalmente, no será crear instancias de este tipo; en su lugar, volverá de clases genéricas del
diccionario. Por ejemplo, si iterar sobre un objeto Dictionary, la devuelve un
enumerador KeyValuePair atado al nombre clave y tipos de valor especificado en El tipo de
diccionario. Puede iterar sobre los elementos de una clase Dictionary genérica- mente por siga
estos pasos:
1. Cree un bucle foreach, especificando una clase KeyValuePair genérico como el tipo
de objeto que se devuelve en cada iteración. Los tipos especificados en
el KeyValuePair deben coincidir con los tipos usados en el diccionario original.
2. En el interior del bloque foreach, puede utilizar el KeyValuePair para recuperar las
claves y valores con propiedades llamado clave y valor, respectivamente. Este ejemplo
contin- ues el diccionario ejemplo mostrado anteriormente:
// C#
ForeachKeyValuePair (<int, string> i en dict)
{
Console.WriteLine("{0} = {1}", i.Key, i.Value);
}
La clase Dictionary genérica conserva el orden en que los elementos se agregan a la lista.
La tabla 4-22
LinkedList métodos
Nombre Descripción
Agrega un nuevo nodo AddAfter después un nodo existente
en LinkedList AddBefore agrega un nuevo nodo antes de un nodo
existente en LinkedList AddFirst agrega un nuevo nodo al comienzo
de LinkedList AddLast agrega un nuevo nodo al final de LinkedList
Borrar Elimina todos los nodos desde LinkedList
Contiene pruebas para ver si un valor está contenida dentro de LinkedList
CopyTo copia todo el LinkedList a una matriz
Buscar Localiza el primer nodo que contenga el valor especificado
FindLast busca el último nodo que contenga el valor especificado
La tabla 4-22 LinkedList métodos
Nombre Descripción
Quitar Quita la primera aparición de un valor o un nodo de
LinkedList
RemoveFirst elimina el primer elemento de LinkedList
RemoveLast elimina el último elemento de LinkedList
Nombre Descripción
Lista obtiene el LinkedList que el nodo pertenece a
Obtiene el siguiente nodo siguiente en
el LinkedList anterior Obtiene el nodo anterior en
el LinkedList valor obtiene el valor contenido en
el nodo.
■ también puede usar la construcción foreach para iterar sobre los valores en
el LinkedList.
Tenga en cuenta que el tipo puede enumerar son los valores, no los nodos de la
lista. Este ejemplo almacena cadenas en el LinkedList:
// C#
LinkedList<> Enlaces cadena = new LinkedList<string>(); LinkedListNode<string> Primera =
links.AddLast("First"); LinkedListNode<cadena> última = links.AddFirst("Último");
LinkedListNode<string> segundo = links.AddBefore(último, "Segundo");
links.AddAfter(segundo, "Terceros");
// ...
La interfaz IList no genéricos es apoyada por la lista genérica colección. Pero en las operacio-
nes, hay una interfaz IList genérico que puede utilizarse para obtener datos de la interfaz de un
modo seguro, así:
// C#
IList<String> typeSafeList = (IListstringList<String> );
Cadena = typeSafeList firstString[0];
Este es el mismo para la interfaz ICollection, IDictionary, IEnumerable, y así sucesivamente. En
general, si se trabaja con colecciones genéricas, pero también desea trabajar con las interfaces en
lugar de la clase específica, debe utilizar la versión genérica de la interfaz compatible con
seguridad de tipos.
// C#
List<string> stringList = new List<string>();
// ...
List<string>.enumerador e = stringList.GetEnumerator();
Mientras (e.MoveNext())
{
// Typesafe acceso al elemento actual
String s = e.Current;
}
// C#
Clase MyComparer<T> : Comparer<T>
{
Anulación pública int Compare(T , T y x)
{
Volver x.GetHashCode() - y.GetHashCode();
}
}
Escribir sus propias colecciones
Las interfaces de la colección que se mencionan en este capítulo (por ejemplo, IList e
ICollection) se puede usar para implementar sus propias colecciones. Puede empezar
de cero y escribir sus propias colecciones que implementan estas interfaces, y el resto
de .NET Framework reconocerá tus clases como colecciones.
Gran parte de la labor necesaria para escribir sus colecciones es común a muchos
colectores- ciones. .NET Framework expone varias clases base para concluir este
comportamiento común:
■ CollectionBase
■ ReadOnlyCollectionBase
■ DictionaryBase
En este ejercicio, puede crear un diccionario genérico para mantener los códigos de llamada con
sus nombres completos.
1. Crear una nueva aplicación de consola denominada GenericCollections.
2. En el método Main del proyecto, crear una nueva instancia del diccionario
genérico
Clase, especificando la clave para ser un entero y el valor a una cadena.
3. Agregar elementos a la colección mediante códigos de país para las claves y los
nombres de países, como los valores.
4. Intente agregar cadenas para las claves de los códigos de país para asegurarse de
que el diccionario
Es de tipo seguro. Si no compila, elimínelos en código o comentarlos.
5. Escribir en la consola de uno de los códigos de país utilizando el indizador sintaxis
del diccionario.
6. Iterar sobre la colección, y escribir el código del país y el nombre del país para
cada KeyValuePair en el diccionario. El código podría tener este aspecto:
// C#
Programa de clase
{
Static void main(String[] args)
{
Dictionary<int, String> countryLookup =
Nuevo diccionario<int, String>();
Console.Read();
}
}
Resumen de la lección
■ lascolecciones genéricas pueden utilizarse para crear más tipos seguros y
potencialmente las versiones más rápidas de sus homólogos no genéricos.
■ La lista genérica, Diccionario, Cola, Stack, SortedList SortedDictionary , y las
clases son de tipo versiones seguras de las colecciones que fueron discutidas en las
Clases 1 a 3.
■ La nueva clase genérica LinkedList es una colección para almacenar elementos
que conocen su propia relación en la lista, y permite la iteración sin tener acceso a
la colección en sí misma.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba su conocimiento de la información en
la lección 5, "colecciones genéricas." Las preguntas también están disponibles en el CD
complementario si prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de respuesta
es correcta o no se encuentran en la sección "Respuestas" al final del libro.
Términos clave
¿ Sabes lo que significan estos términos clave? Puede verificar sus respuestas mediante la
búsqueda de los términos en el glosario al final del libro.
■ colección
■ tipo genérico
■ iteración
Casos
En los siguientes casos, podrá aplicar lo que ha aprendido acerca de cómo utilizar las
colecciones. Usted puede encontrar las respuestas a estas preguntas en la sección de
"respuestas" al final de este libro.
Caso práctico 1: Usar un ArrayList para almacenar códigos de
estado
Usted es un desarrollador para un departamento de TI en una empresa grande. Usted escribir
pequeñas apli- caciones que ayudan a los usuarios a ver los pedidos en el sistema. Su jefe le dice
que usted necesita para agregar un campo de código de estado a una aplicación existente. Ella dice
que los códigos de estado son estáticos y no van a ser al menos cinco, aunque ese número podría
cambiar más adelante.
Preguntas
Responda las siguientes preguntas para el administrador.
1. ¿Cómo vas a almacenar los códigos de estado para utilizar en el formulario?
2. Si los códigos de estado deben ser ordenados de forma distinta para diferentes
usuarios, ¿es eso un problema?
Entrevistas
La siguiente es una lista de personal de la empresa entrevistados y sus declaraciones:
■ Su Manager "no estamos seguros de cuántos nuevos vendedores que tenemos,
pero tenemos que ser capaces de utilizar un código de ventas y el nombre completo
de la persona de ventas en dif erentes- partes de la aplicación".
■ "la persona de ventas en la actualidad, la aplicación no muestra el agente de
lista respon- sable. Pero si la adición de este comportamiento va a ralentizar la
aplicación, podemos vivir sin él".
Preguntas
Responda las siguientes preguntas para el administrador:
1. La colección que se utilizará, a sabiendas de que el tamaño de la lista cambiará y
puede ser pequeño o grande?
2. Cómo mostrar el agente de lista afecta al rendimiento de la aplicación?
Hipótesis 3: Reescribir para utilizar una colección Type-Safe
Usted es un desarrollador principal en una gran entidad bancaria. El departamento de TI
trabaja para tiene un montón de desarrolladores junior. Uno de los programadores junior
escribió una colección para mantener una lista de toda la actividad de la cuenta bancaria para
un año. Varios desarrolladores están usando y teniendo algunos problemas con los errores en
tiempo de ejecución porque un ArrayList se utiliza para almacenar toda la actividad.
Entrevistas
La siguiente es una lista de personal de la empresa entrevistados y sus
declaraciones:
■ Su Manager "Tenemos que cambiar la colecta para ayudar a nuestro
personal a desarrollar sus aplicaciones más rápido y las aplicaciones deben ser
más fiable".
■ Programador Junior "cuando utilizo la colección, intento agregar
actividad y algunas veces me accidentalmente agregar el tipo equivocado de
objeto en la colección. Desde que compila bien, no nos enteramos de
un problema hasta que uno de los escrutadores tiene la apli-
Catión crash".
Preguntas
Responda las siguientes preguntas para el administrador.
1. ¿Cómo van a volver a implementar esta colección para resolver estas
cuestiones?
2. La nueva colección va a ser más lenta que la actual?
Prácticas recomendadas
Que le ayudarán a dominar los objetivos contemplados en el presente capítulo, complete las
siguientes tareas.
Práctica 1
■ Crear un nuevo objeto ArrayList.
■ añadir algunos objetos de diferentes tipos.
Práctica 2
■ Crear una lista genérica de un tipo específico.
■ añadir algunos objetos del tipo correcto e incorrecto.
■ ver cómo funciona de manera diferente en cada situación.
Práctica 3.
■ Crear un diccionario genérico Object.
■ agregar varios elementos.
■ iterar sobre los elementos y ver cómo la clase KeyValuePair genérico
funciona.
Práctica 1
■ Crear Hashtable ListDictionary HybridDictionary , y objetos.
■ Almacenar cinco objetos en cada diccionario.
■ prueba la velocidad de búsquedas con los distintos diccionarios y ver cómo
difieren en función del tamaño de la lista de almacenes.
Práctica 2
■ cambiar los objetos que ha creado en la práctica 1 para almacenar 100
objetos, y ver si los resultados son similares.
Práctica 3.
■ cambiar los objetos que ha creado en la práctica 1 para almacenar 10.000
objetos, y ver si los resultados son similares.
Tomar un Test de práctica
Los tests de práctica en este libro's Companion CD ofrecen muchas opciones. Por ejemplo,
puede hacerse la prueba en un solo examen objetivo, o puede probar usted mismo en todos los
Contenido del examen de certificación 70-536. Puede configurar la prueba tan estrechamente
que simula la experiencia de tomar un examen de certificación, o puede configurarlo en modo
de estudio, de modo que usted puede mirar las respuestas correctas y explicaciones después de
responder a cada pregunta.
Antes de empezar
Para completar las lecciones de este capítulo, debe estar familiarizado con Microsoft Visual Basic
o en C# y se sienten cómodos con las siguientes tareas:
■ Crear una aplicación de consola en Microsoft Visual Studio, usando Visual Basic o
C#.
■ Sistema de agregar referencias a bibliotecas de clases para un proyecto.
■ escribir en archivos y objetos stream.
¿Qué es la serialización?
Serialización, tal como se implementa en el espacio de nombres System.Runtime.Serialization, es
el proceso de serializar y deserializar los objetos de modo que puedan almacenarse o trasladarse y
posteriormente re-creado. La serialización es el proceso de convertir un objeto en una secuencia
lineal de bytes que pueden ser almacenados o transferidos. Deserialización es el proceso de
convertir una secuencia de bytes serializada previamente en un objeto.
Mundo Real
Tony Northrup
La serialización puede ahorrar un montón de tiempo de desarrollo. Antes de que se
dispusiera de serialización, tuve que escribir código personalizado sólo para
almacenar o transferir información. Por supuesto, este código tiende a romperse
cuando he realizado cambios en otras partes de la aplicación. Hoy en día, con .NET
Framework, puedo almacenar y transferir datos con sólo un par de líneas de
código. De hecho, pocas veces me he encontrado la necesidad de modificar el
comportamiento predeterminado alization seri--simplemente funciona.
Básicamente, si usted desea almacenar un objeto (o varios objetos) en un archivo para su posterior
recuperación, puede almacenar el resultado de la serialización. La próxima vez que desee leer los
objetos, puede llamar a los métodos de deserialización, y su objeto es re-creado exactamente como
lo había sido anteriormente. De manera similar, si desea enviar un objeto a una aplicación que se
ejecuta en otro equipo, puede establecer una conexión de red, serializar el objeto a la secuencia y, a
continuación, deserializar el objeto en la aplicación remota. La teletransportación en la ciencia
ficción de ence es un buen ejemplo de serialización (aunque la teletransportación no es actualmente
compatible con .NET Framework).
// Usar el objeto BinaryFormatter para serializar los datos para el archivo bf.Serialize(fs, datos);
Figura 5-1 Serializar objetos pueden guardarse como archivos pero no son archivos de texto.
Si sólo es necesario para almacenar una sola cadena en un archivo, no sería necesario utilizar
serializa- ción-simplemente puede escribir la cadena directamente a un archivo de texto. La
serialización resulta útil al almacenar información más compleja, como la fecha y la hora actuales.
Como demuestra el ejemplo de código siguiente, la serialización de objetos complejos es tan
simple como serializar una cadena:
// C#
// Crear un archivo para guardar los datos en
FileStream fs = new FileStream("SerializedDate.Data", FileMode.Create);
// Usar el objeto BinaryFormatter para serializar los datos para el archivo bf.Serialize(fs,
System.DateTime.Now);
// Cerrar el archivo
fs.Close();
Cómo deserializar un objeto
Deserializar un objeto le permite crear un nuevo objeto basado en los datos almacenados. Essen-
considerablemente, deserializar restaura un objeto guardado. En un nivel alto, los pasos para
deserializar un objeto son como sigue:
1. Crear un objeto Stream para leer la salida serializados.
2. Crear un objeto BinaryFormatter.
3. Crear un nuevo objeto para almacenar los datos deserializado.
4. Llamar al método BinaryFormatter.deserializar para deserializar el objeto, y lo
echó al tipo correcto.
En el nivel de código, los pasos para deserializar un objeto son fáciles de implementar. La fol-
bajar la consola que requiere la aplicación System.IO, System.Runtime.Serialization y
System.Runtime.Serialization.formateadores.Binary namespaces demuestra cómo leer y mostrar la
cadena serializada datos guardados en un ejemplo anterior:
// C#
// Abrir un archivo para leer los datos desde
FileStream fs = new FileStream("SerializedString.Data", FileMode.Open);
// Usar el objeto BinaryFormatter para deserializar los datos desde el archivo de datos = (string)
bf.deserializar(fs);
// Cerrar el archivo fs.Close();
// Usar el objeto BinaryFormatter para deserializar los datos desde el archivo previousTime = (DateTime)
bf.deserializar(fs);
// Cerrar el archivo
fs.Close();
También puede controlar la serialización de sus clases para mejorar la eficiencia de su clase o para
satisfacer los requisitos personalizados. Las secciones siguientes describen cómo personalizar
cómo se comporta su clase durante la serialización.
// C# [serializable]
Clase ShoppingCartItem
{
Int productId público; público precio
decimal; public int cantidad decimal;
pública total.
ShoppingCartItem pública(int _productID, decimal, int __precio cantidad)
{
ProductId = _productID;
Precio = _precio; cantidad =
_cantidad; total = precio * cantidad;
}
}
La ShoppingCartItem incluye tres miembros que deberán ser facilitados por la aplica- ción cuando
se crea el objeto. El cuarto miembro, total, se calcula dinámicamente multiplicando el precio y la
cantidad. Si esta clase se serializa como está, el total sería almacenada con el objeto serializado,
perder una pequeña cantidad de espacio de almacenamiento. Para reducir el tamaño del objeto
serializado (y por lo tanto reducir los requisitos de almacenamiento al escribir la seri- alized objeto
a un disco, y los requisitos de ancho de banda al transmitir el objeto serializado a través de la red),
agregue el atributo NonSerialized al total del miembro:
// C#
[NonSerialized] decimal público total.
Ahora, cuando el objeto está serializado, el total de los estados serán omitidos. Asimismo, el total
de los Estados no se inicializa cuando se deserializa el objeto. Sin embargo, el valor
de total todavía debe calcularse antes el objeto deserializado es utilizado.
Para activar tu clase para inicializar automáticamente un miembro nonserialized, utilice el
IDeserializationCallback interfaz y, a continuación, implementar IDeserializationCallback
.OnDeserialization. Cada vez que tu clase se deserializa el runtime, llamará al método
OnDeserialization IDeserializationCallback.Después de la deserialización es completa. El siguiente
ejemplo muestra la clase modificada ShoppingCartItem no serializar el valor total, y para calcular
automáticamente el valor en la deserialización:
// C# [serializable]
Clase IDeserializationCallback ShoppingCartItem : {
Int productId público; público precio
decimal; public int cantidad;
[NonSerialized] decimal público total.
ShoppingCartItem pública(int _productID, decimal, int __precio cantidad)
{
ProductId = _productID;
Precio = _precio; cantidad = _cantidad; total
= precio * cantidad;
}
Void IDeserializationCallback.OnDeserialization(object sender)
{
// Después de la deserialización, calcular el total total = precio *
cantidad;
}
}
// C# [serializable]
Clase IDeserializationCallback ShoppingCartItem :
{
Int productId público; público
precio decimal; public int
cantidad;
[NonSerialized] decimal público total.
[Público] OptionalField bool tributable;
Si usted necesita para inicializar los miembros opcional, implementan la interfaz IDeserialization-
la devolución de llamada como se describe en la sección "Cómo deshabilitar la serialización de
determinados países miem- bros" anteriormente en esta lección, o responder a los eventos de
serialización, como se describe en la Lección 3.
Cómo utilizar SoapFormatter
Utilizar SoapFormatter, agregar una referencia a System.Runtime.Serialization.formateadores
.Soap.dll general a su proyecto. (A diferencia de BinaryFormatter, no se incluyen por defecto.) a
continuación, se escribe el código exactamente como lo haría para utilizar BinaryFormatter, pero
sustituyendo la clase SoapFormatter para la clase BinaryFormatter.
Al escribir código para BinaryFormatter SoapFormatter y es muy similar, la serie- izado de
datos es muy diferente. El ejemplo siguiente es un objeto serializado de tres miembros
con SoapFormatter que ha sido ligeramente editada:
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-
ENV:Body>
<A1:ShoppingCartItem id="ref-1">
<productId>100</productId>
<precio>10,25</precio>
<cantidad>2</cantidad>
</a1:ShoppingCartItem>
</SOAP-
ENV:Body>
</SOAP-
ENV:Envelope>
// C#
Private static void serialize(Persona sp)
{
// Crear un archivo para guardar los datos en
FileStream fs = new FileStream("Persona.dat", FileMode.Create);
// Usar el objeto BinaryFormatter para serializar los datos para el archivo bf.Serialize(fs, sp);
// Usar el objeto BinaryFormatter para deserializar los datos desde el archivo dsp =
(Persona)bf.deserializar(fs);
// Cerrar el archivo
fs.Close();
Volver dsp;
}
// C#
[NonSerialized] public int edad;
// C#
Serialize_namespace personas
{
[Serializable]
Clase de persona : IDeserializationCallback
// C#
Void IDeserializationCallback.OnDeserialization(object sender)
{
// Después de la deserialización, calcular la edad
CalculateAge();
}
Resumen de la lección
■ La serialización es el proceso de convertir la información en una secuencia de
bytes que pueden ser almacenados o transferidos.
■ para serializar un objeto, primero debe crear un objeto Stream. A continuación,
cree un objeto BinaryFormatter y llamar al método.Serialize BinaryFormatter.
Para deserializar un objeto, siga los mismos pasos pero llame al método
BinaryFormatter.deserializar.
■ Para crear una clase que se puede serializar, agregue el atributo Serializable.
También puede utilizar atributos para desactivar la serialización de miembros
específicos.
■ SoapFormatter proporciona una menos eficientes pero más interoperables,
alternativa a la
Clase BinaryFormatter.
■ utilizar SoapFormatter,siga el mismo proceso que para BinaryFormatter, pero
usar System.Runtime.Serialization.formateadores.Soap. clase SoapFormatter.
■ Puede controlar la serialización SoapFormatter mediante atributos para
especificar los nombres de elementos serializados y especificar si un miembro se
serializa como un elemento o un atributo.
■ Es una buena práctica para hacer todas las clases serializables incluso si no
inmediata- ately requieren la serialización. Debe deshabilitar la serialización de
calculada y miembros temporales.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba su conocimiento de la información en la
lección 1, "Serialización de Objetos." Las preguntas también están disponibles en el CD
complementario si prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final del
libro.
// Cerrar el archivo
fs.Close();
// Cerrar el archivo
fs.Close();
ShoppingCartItem público()
{
}
}
Serializar una instancia de esta clase con valores de ejemplo crea el siguiente XML (que ha sido
ligeramente simplificado para mejorar la legibilidad):
<?xml version="1.0" ?>
<ShoppingCartItem>
<productId>100</productId>
<precio>10,25</precio>
<total>20,50</total>
</ShoppingCartItem>
Si se define el esquema XML, esto podría ser suficiente. Sin embargo, si usted necesita para crear
documentos XML que se ajustan a normas específicas, usted puede ser que necesite para controlar
cómo está estructurada la serialización. Puede hacerlo utilizando los atributos que aparecen en la
Tabla 5-2.
Tabla 5-2 atributos de serialización XML
Puede utilizar estos atributos para hacer una clase serializada se ajustan a los requisitos
XML específico. Por ejemplo, considere los atributos requeridos para realizar las
siguientes tres cambios en el documento XML serializado:
■ Cambiar el nombre al elemento ShoppingCartItem CartItem.
■ Hacer un atributo de productId CartItem, en lugar de un elemento separado.
ShoppingCartItem público()
{
}
}
Esto daría como resultado el siguiente archivo XML, que cumple con los requisitos especificados:
<?xml version="1.0" ?>
<CartItem productId="100">
<precio>10,25</precio>
<cantidad>2</cantidad>
</CartItem>
Aunque los atributos le permitirá satisfacer la mayoría de requisitos de serialización XML, puede
tomar el control completo sobre la serialización XML implementando la interfaz IXmlSerializ-
poder en su clase. Por ejemplo, puede separar los datos en bytes en lugar de búfer de grandes
conjuntos de datos, y también evitar la inflación que se produce cuando los datos se codifican
utilizando la codificación Base64. Controlar la serialización, implementar el ReadXml WriteXml
y métodos para el control de las clases XmlReader y XmlWriter utilizado para leer y escribir los
datos XML.
Si usted tiene un esquema XML, puede ejecutar la herramienta de definición de esquema XML
(XSD.exe) para producir un conjunto de clases con establecimiento inflexible de tipos en el
esquema y se anota con atributos. Cuando una instancia de esa clase es serializado, el XML
generado se adhiere al esquema XML. Esta es una alternativa más simple con el uso de otras clases
en el marco de .NET, como las clases XmlReader y XmlWriter, analizar y escribir una secuencia
XML.
Para generar una clase basada en un esquema, siga estos pasos:
1. Crear o descargar el archivo .xsd esquema XML en su equipo.
2. Abra un símbolo del sistema de Visual Studio 2005.
3. Desde el símbolo del sistema de Visual Studio 2005, ejecutar el esquema
Xsd.exe.xsd /Clases/Language:[CS | VB]. Por ejemplo, para crear una nueva clase
basada en un archivo de esquema denominado C:\library\schema.xsd, debe
ejecutar el siguiente comando:
// C#
Xsd C:\library\schema.xsd /Clases /language:CS
// Usar el objeto XmlSerializer para serializar los datos al archivo xs.Serialize(fs, sp);
// Cerrar el
archivo
fs.Close();
}
// Usar el objeto XmlSerializer para deserializar los datos para el archivo dsp =
(Persona)xs.deserializar(fs);
// Cerrar el archivo
fs.Close();
Volver dsp;
}
8. Examine los datos serializados para verificar que la información que haya
proporcionado en la línea de comandos se ha capturado. ¿Por qué la edad aparecen
en la serie- izado archivo aunque la edad NonSerialized miembro tiene el atributo?
La NonSerialized atributo se aplica a la serialización binaria, pero no afecta a
La serialización
XML.
9. Ahora ejecute el comando sin parámetros para comprobar que la deserialización
funciona correctamente.
Resumen de la lección
■ la serialización XML proporciona la interoperabilidad para comunicarse con
diferentes plataformas y flexibilidad para ajustarse a un esquema XML.
■ No se puede utilizar la serialización XML para serializar los datos privados o
gráficos de objetos.
■ para
serializar un objeto, primero debe crear una
secuencia, TextWriter XmlWriter , o. A continuación, cree un objeto
XmlSerializer y llamar al método.Serialize XmlSerializer. Para deserializar
un objeto, siga los mismos pasos pero llame el XmlSerializer.deserializar
el método.
■ Paracrear una clase que se puede serializar, especificar la clase y todos los
miembros como públi- ca, y crear un constructor sin parámetros.
■ Puede controlar la serialización XML mediante atributos. Los atributos
pueden cambiar los nombres de los elementos, serializar miembros como
atributos en lugar de elementos, y excluir a los miembros de la serialización.
■ Utilicela herramienta Xsd.exe para crear una clase que se adaptará
automáticamente a un XML Esquema cuando se serializa.
■ Datasets,
matrices, colecciones y las instancias de una clase XmlNode o
XmlElement pueden todos ser serializadas con XmlSerializer.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba tus conocimientos de la
información Les- hijo 2, "serialización XML." Las preguntas también están disponibles en el
CD complementario si prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final
del libro.
1. Cuál de los siguientes son los requisitos para una clase que se va a serializar
con XML
La serialización? (Seleccione todos los que correspondan).
A. La clase debe ser pública.
B. La clase debe ser privado.
C. La clase debe tener un constructor sin parámetros.
D. La clase debe tener un constructor que acepta un parámetro
SerializationInfo.
2. Cuál de los siguientes atributos que usaría para causar un miembro a ser serie- izado
como un atributo, en lugar de un elemento?
A. XmlAnyAttribute
B. XMLType
C. XMLElement
D. XMLAttribute
3. La herramienta que se debe utilizar para ayudarle a crear una clase que, a la hora de
serializar, produciría un documento XML que se ajustaban a un esquema XML?
A. Xsd.exe.
B. Xdcmake.exe C. X
Padsi90.exe D.
Xcacls.exe.
4. Cuál de los siguientes atributos se debe agregar a un miembro para impedir que se
serializaron serialización XML?
A. XMLType
B. XMLIgnore C.
XMLElement D.
XMLAttribute
Lección 3: Serialización personalizada
Serialización personalizada es el proceso de controlar la serialización y deserialización de un
tipo. Al controlar la serialización, es posible garantizar la serialización compatibil- lidad, que
es la capacidad de serializar y deserializar entre versiones de un tipo sin romper la
funcionalidad básica del tipo. Por ejemplo, en la primera versión de un tipo, es posible que
sólo haya dos campos. En la próxima versión de un tipo, varios campos son añadidos. Pero la
segunda versión de la aplicación debe ser capaz para serializar y deserial- ize ambos tipos.
Esta lección describe cómo controlar la serialización implementando sus propias clases de
serialización.
[OnSerializin [OnDeserializing]
g]
IDeserializationCallb
[OnSerialize
ack,
d] OnDeserializatio
n
Completada la [OnDeserialized]
serialización
La deserialización completado
La figura 5-2 puede utilizar la serialización eventos para ejecutar métodos durante las diferentes
fases de la serializa- ción y proceso de deserialización.
// C# [serializable]
Clase ShoppingCartItem
{
ProductId Int32 público; público
precio decimal; public Int32; la
cantidad total de decimales;
[OnSerializing]
Void StreamingContext CalculateTotal(SC)
{
Total = precio * cantidad;
}
[OnDeserialized]
Void StreamingContext CheckTotal(SC)
{
Si (total == 0) { CalculateTotal(SC); }
}
}
// C#
Persona pública(SerializationInfo info, StreamingContext contexto)
{
Nombre = info.GetString("Nombre");
Fechadenacimiento = info.GetDateTime
("DOB"); CalculateAge();
}
Resumen de la lección
■ Puede implementar ISerialization para realizar la serialización personalizada.
■ BinaryFormatter proporciona cuatro eventos que se pueden utilizar para el
control de partes de la Seri- alization OnSerializing OnSerialized proceso: ,, ,
y OnDeserialized OnDeserializing.
■ El StreamingContext , una instancia de la clase que se ofrece a los métodos
llamados durante la serialización de eventos, le da información sobre el
origen o el destino previsto del proceso de serialización. El método de
realizar la serialización debe especificar esta información para que sea útil.
■ aunque pocos desarrolladores requerirá un control total sobre la
serialización, usted puede implantar el IGenericFormatter IFormatter
o interfaces para crear formateadores personalizados.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba su conocimiento de la
información en la lección 3, "Serialización personalizada." Las preguntas también
están disponibles en el CD complementario si prefiere revisarlos en forma
electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final
del libro.
Términos clave
¿ Sabes lo que significan estos términos clave? Puede verificar sus respuestas mediante la
búsqueda de los términos en el glosario al final del libro.
■ BinaryFormatter
■ La deserialización
■ La serialización
■ SoapFormatter
Entrevistas
La siguiente es una lista de personal de la empresa entrevistados y sus
declaraciones:
■ Sistema de Facturación Development Manager "Ya tengo mi chico
que trabaja sobre esto, y él ha construido métodos con .NET que aceptan
el uso de clases de objeto y agregar la información de facturación para la
base de datos. Tan solo tenemos que crear esos
Objetos y enviarlos a través de la red interna a nosotros".
■ Network Manager "Toda la contabilidad y la facturación de los servidores
están en la misma sub-red, así no tienes que preocuparte por el tráfico de la
red va a través de los firewalls. Me gustaría que para intentar minimizar el
ancho de banda utilizado, tenemos mil-
Los leones de cuentas, y que está a punto de subred ya saturada".
Preguntas
Responda las siguientes preguntas para el administrador:
1. Método de serialización que usas?
2. ¿Qué cambios se necesitan para hacer de tu clase para habilitar la
serialización?
3. Acerca de cuántas líneas de código se necesita escribir para realizar la
serialización?
Preguntas
Responda las siguientes preguntas para el administrador:
1. En Incident 1.0, sé que usted guardar algunas de las preferencias del usuario,
como la ventana de posi- ción, a un archivo mediante la serialización
tus preferencias objeto utilizando BinaryFormatter. Puede deserializar los
ajustes directamente en incidente 2.0 si no realiza ningún cambio en
las preferencias de clase?
2. Tenemos algunas solicitudes de funciones que requieren que usted agregue
más preferencias. Si desea agregar más miembros a la clase de preferencias,
que todavía pueda deserializar directamente esos ajustes en incidente 2.0? En
caso afirmativo, ¿qué adaptaciones especiales tendrá que hacer?
3. El departamento de TI ha solicitado podemos pasar a utilizar archivos de
configuración basado en XML para que puedan editarlos más fácilmente.
¿Cómo podría usted deserializar la existen- tes en formato binario objeto,
mientras que serializar un objeto XML?
Prácticas recomendadas
Que le ayudarán a dominar la "Implementación de la serialización y la funcionalidad de
entrada/salida en una aplicación .NET Framework" examen objetivo, completar el
seguimiento de las tareas.
Antes de empezar
Para completar las lecciones de este capítulo, debe estar familiarizado con Microsoft Visual
Basic o en C# y se sienten cómodos con las siguientes tareas:
■ Crear una aplicación de Windows Forms en Microsoft Visual Studio
utilizando Visual Basic o C#.
■ escribir archivos y arroyos.
Clase Descripción
Encapsula un mapa de bits GDI+ Bitmap, que consta de los datos
de píxeles de una imagen gráfica y sus atributos. Un objeto
Bitmap es un objeto que se utiliza para trabajar con
imágenes definidas por los datos de los píxeles. Esta es la
clase que se utilizará cuando necesite cargar o guardar
imágenes.
Tabla 6-1 clases System.Drawing
Clase Descripción
Cepillo clases derivadas de esta clase base abstracta, descritos en la
sección "Cómo rellenar formas", definir los objetos utilizados
para rellenar el inte- riors de formas gráficas tales como
rectángulos, elipses, tartas, poli- gons y trazados.
Pinceles Pinceles para todos los colores estándar. Esta clase puede ser
inher- ited. Utilice esta clase para evitar la creación de una
instancia de una clase Brush.
ColorConverter convierte los colores de un tipo de datos a otro. Tener acceso a
esta clase mediante el TypeDescriptor.
Traduce ColorTranslator colores en y desde las estructuras de color GDI+.
Esta clase no se puede heredar.
Font define un formato concreto para el texto, incluida la fuente,
el tamaño y los atributos de estilo. Esta clase no se puede
heredar.
FontConverter convierte los objetos Font de un tipo de datos a otro. Acceder a
la
Clase FontConverter mediante el objeto TypeDescriptor.
FontFamily define un grupo de tipo se enfrenta con un diseño básico
similar y ciertas variaciones en los estilos. Esta clase no se
puede heredar.
Graphics encapsula una superficie de dibujo de GDI+. Esta clase no se
puede heredar. Podrá utilizar esta clase en cualquier momento
si necesita dibujar líneas, dibujar formas o añadir texto a un
control gráfico o imagen.
Icono Represiente un icono de Microsoft Windows, que es una
pequeña imagen de mapa de bits que se usa para representar un
objeto. Los iconos pueden ser pensadas como trans- padre
bitmaps, aunque su tamaño es determinado por el sistema.
IconConverter convierte un objeto Icon de un tipo de datos a otro. Tener
acceso a esta clase mediante el objeto TypeDescriptor.
Imagen de una clase base abstracta que proporciona la funcionalidad para
el mapa de bits
Y Metafile clases descendientes.
ImageAnimator anima una imagen que tiene tramas basadas en tiempo.
ImageConverter ImageConverter es una clase que se puede utilizar para
convertir objetos de imagen de un tipo de datos a otro. Tener
acceso a esta clase mediante el objeto TypeDescriptor.
Clase Descripción
ImageForm ImageFormatConverter es una clase que puede ser usado para
at- convertir col- ors de un tipo de datos a otro. Tener acceso a
Converter esta clase mediante el objeto TypeDescriptor.
Pen define un objeto que se utiliza para dibujar líneas, curvas y
flechas. Esta clase no se puede heredar.
Plumas Plumas de todos los colores estándar. Esta clase no se
puede heredar.
Utilice esta clase para evitar la creación de una instancia de
la clase Pen.
PointConverter convierte un objeto de punto de un tipo de datos a otro.
Tener acceso a esta clase mediante el objeto
TypeDescriptor.
Rectáng Convierte los rectángulos de un tipo de datos a otro. Tener
ulo- acceso a esta clase mediante el objeto TypeDescriptor.
Convert
er
Región Describes el interior de una forma gráfica compuesta de rectan-
gles y rutas. Esta clase no se puede heredar.
SizeConverter SizeConverter la clase se utiliza para convertir de un tipo de
datos a otro. Tener acceso a esta clase mediante el objeto
TypeDescriptor.
SolidBrush define un pincel de un solo color. Los pinceles se usan para rellenar
el gráfico- ics formas, como rectángulos, elipses, tartas, polígonos
y rutas. Esta clase no se puede heredar.
StringFormat encapsula la información de diseño de texto (tales como la
alineación y el espaciado entre líneas), mostrar las manipulaciones
(como la inserción de puntos suspensivos y sustitución de cifras
nacionales), y las funciones OpenType. Esta clase no se puede
heredar.
SystemBrushes cada propiedad de la clase SystemBrushes es un objeto
SolidBrush que es el color de un elemento de pantalla de
Windows.
SystemColors cada propiedad de la clase SystemColors es una estructura de
color que es el color de un elemento de pantalla de Windows.
SystemFonts especifica las fuentes que se utilizan para mostrar texto en los
elementos de pantalla de Windows.
Clase Descripción
SystemIcons cada propiedad de la clase SystemIcons es un objeto Icon para
Iconos de todo el sistema Windows. Esta clase no se puede heredar.
SystemPens cada propiedad de la clase SystemPens es un objeto Pen que es el
color de un elemento de la pantalla en Windows y que tiene una
anchura de 1.
TextureBrush cada propiedad de la clase TextureBrush es un objeto Brush que
utiliza una imagen para rellenar el interior de una forma. Esta clase
no se puede heredar.
- Atributo ToolboxBitmap
Puede aplicar un ToolboxBitmapAttribute a un control de manera que los contenedores, como
diseñador de formularios de Visual Studio de Microsoft, puede recuperar un icono que representa el
control. El mapa de bits para el icono puede estar en un archivo por sí mismo o incrustado en el
ensamblado que contiene el control.
El tamaño del mapa de bits que desea incrustar en el ensamblado del control (o almacenar en un
archivo independiente) debe ser de 16 por 16. El método GetImage de un objeto
ToolboxBitmapAttribute puede devolver el pequeño
16-por-16 o una gran imagen de 32-por-32 que crea la imagen mediante el escalado de la
imagen pequeña.
De estas clases, se utilizarán los gráficos más a menudo porque proporciona métodos para dibujar
en la pantalla del dispositivo. La clase Pen se utiliza para dibujar líneas y curvas, mientras que las
clases derivadas de la clase abstracta Brush se utiliza para rellenar el interior de formas. Además,
debe estar familiarizado con la clase PictureBox, que puede utilizar en aplicaciones de Windows
Forms para mostrar una imagen como parte de la interfaz de usuario. El espacio de nombres
System.Drawing incluye las estructuras que se muestran en la Tabla 6-2.
Tabla 6-2
System.Drawing estructuras
Clase Descripción
CharacterRange especifica un rango de posiciones de caracteres dentro de una cadena.
Color representa un color.
Representa el punto entero de un par ordenado de coordenadas x e y que
define un punto en un plano bidimensional.
Clase Descripción
PointF representa un par ordenado de punto flotante de coordenadas x e
y que define un punto en un plano bidimensional.
Rectangle almacena un conjunto de cuatro números enteros que representan
la ubicación y el tamaño de un rectángulo. Para las funciones
más avanzadas de la región, utilizar un objeto de región.
RectangleF almacena un conjunto de cuatro números de punto flotante que
representan la ubicación y el tamaño de un rectángulo. Para las
funciones más avanzadas de la región, utilizar un objeto de
región.
Tamaño almacena un par ordenado de números enteros,
normalmente el ancho y el alto de un rectángulo.
SizeF almacena un par ordenado de números de punto flotante,
normalmente el ancho y el alto de un rectángulo.
La más importante de estas estructuras y las estructuras que se utilizan con mayor frecuencia son
Color, punto, Rectánguloy Tamaño.
Button1.ForeColor = Color.Red);
Button1.BackColor = Color.azul;
El ejemplo siguiente ilustra cómo especificar color proporcionando tres enteros para rojo, verde y
azul:
// C#
Button1.ForeColor = Color.FromArgb(10, 200, 200);
Button1.BackColor = Color.FromArgb(200, 5, 5).
// Dibujar la línea
G.DrawLine(p, 1, 1, 100, 100);
Figura 6-1 utilice Graphics.DrawLine para crear líneas rectas
Asimismo, el siguiente código dibuja un azul pastel con un ángulo de 60 grados, como se muestra
en la Figura 6-2:
// C#
Graphics g = this.CreateGraphics(); p = new Pen
Pen(Color.Blue, 3).
// C#
Graphics g = this.CreateGraphics();
Bolígrafo p = new Pen(Color.MediumPurple, 2).
P.DashStyle = DashStyle.dot;
G.DrawLine(p, 50, 25, 400, 25).
P.DashStyle = DashStyle.Dash;
G.DrawLine(p, 50, 50, 400, 50);
P.DashStyle = DashStyle.DashDot;
G.DrawLine(p, 50, 75, 400, 75);
P.DashStyle = DashStyle.DashDotDot;
G.DrawLine(p, 50, 100, 400, 100);
P.DashStyle = DashStyle.sólido;
G.DrawLine(p, 50, 125, 400, 125);
Figura 6-5 La clase Pen proporciona opciones para startcaps y endcaps
Figura 6-6 Utilice el cepillo con la clase Graphics.diversos métodos de relleno para dibujar objetos
sólidos.
Puede dibujar objetos rellenos con un esquema por llamar primero a la clase Graphics método de
relleno y, a continuación, llamar al método draw de la clase Graphics. Por ejemplo, el siguiente
código dibuja un polígono con un esquema y un patrón de relleno, como se muestra en la Figura 6-
7:
// C#
Graphics g = this.CreateGraphics(); p = new Pen
Pen(Color.granate, 2).
B = nuevo pincel LinearGradientBrush(nuevo punto(1,1), el nuevo punto(100,100), Color.Blanco,
Color.Red);
Punto[] Puntos = new punto[]
{Nuevo Punto(10, 10)
Nuevo punto (10, 100), el nuevo
punto(50, 65),
G.FillPolygon(B, puntos).
G.DrawPolygon(p, puntos).
Figura 6-7 Combinar gráficos.Fill con gráficos. métodos Draw para crear objetos sólidos con
contornos
Puede utilizar t él mismo técnicas para dibujar sobre controles, como botones o las instancias de
la clase PictureBox. Si usted necesita para llenar todo un objeto Graphics con un pecado- gle
color, llame al método Graphics.Clear.
7. En este punto, el proyecto se compila, pero no se dibuja el gráfico de tarta. Antes de
poder crear un gráfico de tarta de las PieChartElement objetos en el ArrayList, debe
determinar cuántos grados utiliza cada elemento. Para ello, debe calcular el total de
todos los PieChartElement. objetos de valor. Por ejemplo, el código siguiente:
// C#
// Calcular el valor total de todas las filas total flotación = 0.
9. A continuación, defina un objeto Pen para dibujar el gráfico de tarta. Esto puede
ser un proceso sencillo, negro, 1 píxel de pluma:
// C#
Bolígrafo p = new Pen(Color.Black, 1).
10. Por último, cree un bucle foreach que calcula los grados para cada sección del
gráfico circular, y dibuja los gráficos de tarta. Hay muchas maneras de hacerlo,
como en el siguiente código:
// C#
// Dibujar la primera sección a 0 grados float startAngle
= 0.
11. Ejecute la aplicación y corregir cualquier error. Cambiar el tamaño del formulario y
observe que el gráfico circular se redimensiona automáticamente; el evento Paint
llama al método draw cuando cambia el tamaño del formulario.
Ejercicio 2: Mejorar la apariencia del gráfico circular
En este ejercicio, mejorar el proyecto creado en el ejercicio 1 para realizar el gráfico de tarta más
atractiva visualmente. Específicamente, usted va a llenar en cada sección con un color diferente y
habilitar el anti-aliasing para suavizar las líneas.
1. Copiar el capítulo06\LECCION1-ejercicio2-PieChart carpeta desde el CD a tu disco
duro y abrir la versión en C# o Visual Basic versión del PieChart proyecto.
Alternativamente, usted puede continuar trabajando en el proyecto creado en el
ejercicio 1.
2. En primer lugar, en el método drawPieChart, crear una matriz que contenga los
colores que desea utilizar en el gráfico circular. Podrá asignar los colores de forma
secuencial, por lo que no coloque colores similares, uno detrás del otro. En aras de la
simplicidad, lanzar una excep- ción si el gráfico tiene más elementos de los que tiene
los colores de su matriz. Por ejemplo:
// C#
Colores Color[] = { Color.Red, Color.Naranja, Amarillo, Color.Color.Verde, Color.Blue, Color.añil,
Color.Violeta, Color.DarkRed, Color.DarkOrange, Color.DarkSalmon, Color.Verdeoscuro,
Color.DarkBlue, Color.color lavanda,.LightBlue, Color.Coral };
Nota mantenerlo
simple
En aras de mantener el ejercicio centrado, algunos aspectos de este proyecto no
son exactamente como lo haría el diseño en el mundo real. Por ejemplo,
normalmente se desea dar a la aplicación que llama la opción de especificar
colores para las diferentes secciones, que podría llevarse a cabo mediante la
adición de un objeto Color a la clase PieChartElement. Además, elementos
como la captura de las excepciones, la validación de las entradas, y afirmando
se omiten en los ejemplos.
3. Usted tendrá que seguir el color en uso. Antes de que el bucle foreach, inicialice
una inte- ger a cero para actuar como un contador:
// C#
Int colorNum = 0.
4. Dentro del bucle foreach, agregue dos líneas: una para crear un nuevo objeto
Brush, y un segundo para llamar al método Graphics.FillPie. Llame
a Graphics.FillPie inmediatamente antes de llamar a Graphics.DrawPie de modo
que el contorno se dibuja sobre el sector relleno. En el siguiente ejemplo de código
se utiliza la clase LinearGradientBrush, que requiere la adición de
la System.Drawing.Drawing2D namespace para el proyecto:
// C#
// Dibujar la primera sección a 0 grados float startAngle
= 0.
Int colorNum = 0.
5. Ahora, ejecute la aplicación. Experimente con los diferentes tipos de pincel para
encontrar uno que es más atractivo. Observe que las líneas aparecen un poco
irregulares; puede hacer que las líneas aparezcan más suaves,
estableciendo Graphics.SmoothingMode, como demuestra la siguiente línea:
' VB
G.SmoothingMode = SmoothingMode.HighQuality
// C#
G.SmoothingMode = SmoothingMode.HighQuality;
Resumen de la lección
■ El espacio de nombres System.Drawing proporciona herramientas para dibujar
gráficos y edición de imágenes existentes. Las clases son más útiles , Imageny
gráficos de mapa de bits.
■ Utilice el punto y clases de tamaño para especificar la ubicación y el tamaño de
los controles.
■ El System.Drawing.Color estructura proporciona propiedades predefinidas de
colores comunes.
■ Para dibujar líneas y formas, cree una instancia de la clase Graphics, crear
un objeto Pen y, a continuación, llame a uno de los métodos miembro de gráficos
para dibujar una línea o una forma de usar la pluma de instancia.
■ Las plumas pueden personalizarse añadiendo endcaps o cambiando el patrón de
línea diferentes combinaciones de puntos y rayas.
■ para dibujar formas sólidas, cree una instancia de la clase Graphics, cree
un objeto Brush y, a continuación, llame a uno de los métodos miembro de
gráficos para dibujar la forma utilizando el pincel instancia.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba su conocimiento de la información en la
lección 1, "Dibujar gráficos." Las preguntas también están disponibles en el CD complementario si
prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final del
libro.
1. Cuál de los siguientes métodos se puede utilizar para dibujar un cuadrado con un
color sólido?
A. Graphics.DrawLines
B. Graphics.DrawRectangle
C. DrawPolygon Graphics.
D. Graphics.DrawEllipse
E. Graphics.FillRectangle
F. Graphics.FillPolygon
G. Graphics.FillEllipse
2. Cuál de los siguientes métodos se puede utilizar para dibujar un triángulo vacío?
A. Graphics.DrawLines
B. Graphics.DrawRectangle
C. DrawPolygon Graphics.
D. Graphics.DrawEllipse
E. Graphics.FillRectangle
F. Graphics.FillPolygon
G. Graphics.FillEllipse
C
#
I = Imagen Image.FromFile(@"C:\windows\Gone Fishing.bmp");
PictureBox1.BackgroundImage = i;
C
#
B = new Bitmap Bitmap(@"C:\windows\Gone Fishing.bmp");
PictureBox1.BackgroundImage = b;
Como alternativa, puede mostrar una imagen como fondo de un formulario o control mediante
el método Graphics.DrawImage. Este método tiene 30 sobrecargas, así que tiene una amplia
variedad de opciones para especificar la ubicación y el tamaño de la imagen. El código
siguiente utiliza este método para establecer una imagen como fondo de un formulario,
independientemente de las dimensiones del formulario son:
/
/
C
#
Bitmap bm = new Bitmap(@"C:\WINDOWS\web\wallpaper\Azul.jpg"); Gráficos g
= this.CreateGraphics();
G.DrawImage(BM, 1, 1, this.Width, este.de altura);
C
#
Bm = new Bitmap Bitmap (600, 600);
Gráficos g = Graphics.FromImage(BM);
G.FillPolygon(B, puntos).
Bm.Save("bm.jpg", ImageFormat.jpeg);
C
#
Graphics g = this.CreateGraphics();
G.DrawIcon(SystemIcons.Pregunta, 40, 40).
Si no (saveDialog.ShowDialog DialogResult.Cancel =)
' Guardar la imagen en el archivo especificado en formato JPEG
chart.Image.Save(saveDialog.FileName, ImageFormat.jpeg)
End If
// C#
// Mostrar el cuadro de diálogo Guardar
SaveDialog SaveFileDialog = new SaveFileDialog();
SaveDialog.DefaultExt = ".jpg".
SaveDialog.Filter = "archivos JPEG (*.jpg)|*.jpg;*.jpeg|Todos los archivos (*.*)|*.*".
Si (saveDialog.ShowDialog() != DialogResult.Cancel)
{
// Guardar la imagen en el archivo especificado en formato JPEG
chart.Image.Save(saveDialog.FileName, ImageFormat.jpeg);
}
Resumen de la lección
■ las clases Image y Bitmap le permiten editar o crear imágenes, y guardar
los resultados como un archivo.
■ Para mostrar una imagen en un conjunto de formularios Windows Forms,
cargar la imagen en una instancia de la clase de imagen o mapa de bits,
crear una instancia del control PictureBox, y luego utilizar la imagen o
el objeto de mapa de bits para definir los controles PictureBox.Background-
image la propiedad.
■ para crear y guardar una imagen, crear un objeto Bitmap, modificarla
utilizando un objeto Graphics y, a continuación, llamar al método Save.de
mapa de bits.
■ Paramostrar un icono, llame al
método Graphics.DrawIcon o Graphics.DrawIconUnstretched
Métodos utilizando una de las propiedades de la clase SystemIcons.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba tus conocimientos de la
información Les- hijo 2 "Trabajo con imágenes." Las preguntas también están disponibles en
el CD complementario si prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final
del libro.
1. Cuál de las siguientes clases se puede utilizar para mostrar una imagen JPEG a
partir de un archivo existente en un formulario? (Seleccione todos los que
correspondan).
A. System.Drawing.Image
B. System.Drawing.Bitmap
C. System.Drawing.Imaging.metaarchivo
D. System.Windows.Forms.Control PictureBox
2. ¿Cómo se puede dibujar un borde negro alrededor de la imagen JPEG que
hayas guardado en el disco y, a continuación, guardar la imagen actualizada
de vuelta al disco?
A. Crear un objeto Graphics cargando la imagen JPEG desde el disco.
Dibujar el borde llamando Graphics.DrawRectangle. Por último, guarde
la imagen actualizada llamando Graphics.Guardar.
B. Crear un objeto Bitmap al cargar la imagen JPEG desde el disco.
Dibujar la- bor der llamando Bitmap.DrawRectangle. Por último, guarde
la imagen actualizada llamando Bitmap.Guardar.
C. Crear un objeto Bitmap al cargar la imagen JPEG desde el disco. Crear
un objeto Graphics llamando Graphics.FromImage. Dibujar el borde
llamando Graphics.DrawRectangle. Por último, guarde la imagen
actualizada llamando - mapa de bits.Save.
D. Crear un objeto Bitmap al cargar la imagen JPEG desde el disco. Crear
un objeto Graphics llamando Bitmap.CreateGraphics. Dibujar el borde
por call- ing Graphics.DrawRectangle. Por último, guarde la imagen
actualizada llamando - mapa de bits.Save.
3. Qué formato debe elegir guardar una fotografía que podría ser inaugurada por
una amplia variedad de aplicaciones?
A.
ImageFormat.bm
p B.
ImageFormat.gif
C.
ImageFormat.JP
EG D.
ImageFormat.pn
g
4. Qué formato debe elegir guardar un gráfico circular que podría ser inaugurada
por una amplia variedad de aplicaciones?
A.
ImageFormat.bm
p B.
ImageFormat.gif
C.
ImageFormat.JP
EG D.
ImageFormat.pn
g
Lección 3: formato de texto
A menudo los desarrolladores agregar texto a las imágenes para etiquetar objetos o crear
informes. Esta lección describe cómo agregar texto con formato a las imágenes.
Mundo Real
Tony Northrup
Cuando no estoy codificación, estoy tomando fotos. Puedo vender las fotos en
la Web para cubrir el costo indignante de mi equipo de la cámara.
Lamentablemente, si bien tienen DRM (digital rights management) para
música y vídeo, nadie ha averiguado DRM para imágenes. Así, hasta que
alguien desarrolla una buena imagen sistema DRM, su mejor apuesta es
agregar entrometido y filigranas visibles copyright notificaciones a las
imágenes publicadas en la Web. Esto no va a detener a alguien de copiar su
pic- tures y violar los derechos de autor, pero el texto del copyright hace que
las imágenes más difíciles de usar.
Cómo crear un objeto Font
La clase Font ofrece 13 diferentes constructores. La forma más sencilla de crear un objeto
Font es pasar el nombre de la familia de fuentes (como una cadena), el tamaño de la fuente
(como un integer o float) y estilo de fuente ( System.Drawing. propiedad FontStyle). Por
ejemplo, el siguiente constructor crea una Arial de 12 puntos en negrita:
/
/
C
#
Fuente f = new Font("Arial", 12, FontStyle.Bold);
C
#
FontFamily ff = new FontFamily("Arial"); font f =
Nueva Fuente(ff, 12);
Si necesita leer el tipo de fuente a partir de una cadena, puede usar la clase
FontConverter. Este no es el método preferido, sin embargo, porque utiliza una cadena para
describir un font es menos confiable. (Es menos confiable porque el compilador no puede
detectar errores o errores tipográficos). Por lo tanto, no se descubre un error en el nombre de
la fuente hasta un argumento en tiempo de ejecución- se produce la excepción. En el siguiente
ejemplo se crea una fuente Arial de 12 puntos:
/
/
C
#
Convertidor FontConverter = new FontConverter();
Fuente f = (Fuente)converter.ConvertFromString("Arial, 12 pt");
/
/
C
#
Graphics g = this.CreateGraphics();
Fuente f = new Font("Arial", 40, FontStyle.Bold);
G.DrawString("Hello, World!", f, Pinceles.azul, 10, 10).
Figura 6-9 llamada Graphics.DrawString para agregar texto a un objeto Graphics.
Por supuesto, es mucho más fácil de añadir texto a un formulario utilizando objetos Label.
Sin embargo, el gráfico- ics.DrawString también le permite agregar texto a las
imágenes y mapas de bits. Esto resulta útil para añadir información de copyright visible a una
imagen, añadir marcas de tiempo para las imágenes, gráficos y anotación.
Cómo controlar el formato del texto
.NET Framework permite controlar la alineación y la dirección del texto, utilizando la clase
StringFormat. Después de crear y configurar un objeto StringFormat, puede proporcionar
el método DrawString de Graphics.para controlar la forma en que el texto está formateado.
Los miembros más importantes de la clase StringFormat son:
■ La alineación obtiene o establece la alineación horizontal del texto. Las
opciones posibles son:
❑ StringAlignment.Center centra el texto horizontalmente
❑ StringAlignment.Cerca de Alinea el texto a la izquierda
❑ StringAlignment.Ahora alinea el texto a la derecha
■ FormatFlags obtiene o establece una enumeración StringFormatFlags
que contiene la información de formato- ting. Las posibles opciones son
StringFormatFlags
❑ DirectionRightToLeft se muestra el texto de derecha a izquierda.
❑ DirectionVertical texto alineado verticalmente.
❑ DisplayFormatControl caracteres de control como la marca de
izquierda a derecha se muestran en la salida con un representante de los
glifos.
❑ FitBlackBox partes de caracteres permitidos para la cadena del
diseño voladizo del rectángulo. Por defecto, los caracteres se reubica
para evitar cualquier pendiente.
❑ LineLimit sólo líneas enteras están establecidos en el formato del
rectángulo. Por defecto, el diseño sigue hasta el final del texto o hasta
que no haya más líneas son visibles como resultado de recortes, lo que
ocurra primero. Observe que la opción predeterminada
Permitir la configuración de la última línea para ser parcialmente oscurecida por un rectángulo
de formato que no es un múltiplo entero de la altura de la línea. Para garantizar que sólo se
observan líneas enteras, especificar este valor y tener cuidado para proporcionar un formato de
ángulo rect- al menos tan alto como la altura de una línea.
❑ MeasureTrailingSpaces incluye el espacio final al final de cada
línea.Por defecto, el rectángulo delimitador devuelto por el método
MeasureString Excluye el espacio al final de cada línea. Establecer este
indicador para incluir ese espacio en la medición.
❑ NoClip sobresaliendo por partes de pictogramas y texto sin envolver
llegando- lado el rectángulo de formato están autorizados a mostrar. De
forma predeterminada, todo el texto y el glifo partes alcanzar fuera del
rectángulo de formato se recortan.
❑ NoFontFallback Suplencia a fuentes alternas para caracteres no
admitidos en la fuente solicitada está desactivada. Cualquier faltan
caracteres se muestran con las fuentes que faltan en el glifo,
normalmente una plaza abierta.
❑ NoWrap entre líneas de ajuste de texto dentro de un rectángulo de
formato cuando está desactivado. Esta bandera está implícita cuando se
pasa de un punto en lugar de un rectan- gle, o cuando el rectángulo
especificado tiene una longitud de línea cero.
■ LineAlignment obtiene o establece la alineación de texto vertical. Las
opciones posibles son:
❑ StringAlignment.Center centra el texto verticalmente
❑ StringAlignment.Cerca de Alinea el texto a la parte superior
❑ StringAlignment.Ahora alinea el texto a la parte inferior
■ Recorte obtiene o establece la enumeración StringTrimming para
este StringFormat
Objeto. Las opciones posibles son:
❑ carácter especifica que el texto se ajusta al carácter más cercano.
❑ EllipsisCharacter Especifica que el texto está cortado con el
carácter más cercano, y los puntos suspensivos se inserta al final de una
línea recortada.
❑ EllipsisPath El centro se retira de líneas recortadas y sustituido por
puntos suspensivos. El algoritmo mantiene como mucho del último
segmento delimitado por barras de la línea como sea posible.
❑ EllipsisWord Especifica que el texto se recorta a la palabra más
cercana, y los puntos suspensivos se inserta al final de una línea
recortada.
❑ No especifica ningún recorte.
❑ Palabra Especifica que el texto se recorta más cercano a la palabra.
El código siguiente muestra el uso de la clase StringFormat y produce el resultado que se
muestra en la Figura 6-10:
// C#
Graphics g = this.CreateGraphics();
// C#
Si (saveDialog.ShowDialog() != DialogResult.Cancel)
{
// Definir el mapa de bits, gráficos, Font y Brush para derechos de autor LOGO
Bitmap (Mapa de bits bm =)chart.imagen;
Graphics g = Graphics.FromImage(BM); font f =
new Font("Arial", 12).
Cepillo b = new SolidBrush(Color.Blanco);
3. Ejecute la aplicación y guardar una imagen. Observe que el aviso de copyright son
difíciles de leer cuando se superpone a la imagen. Una manera de resolver esto es
dibujar el texto con un color contrastante detrás de la cadena, y el desplazamiento
en un píxel en cada di- ción. Por ejemplo, el siguiente código añade un fondo
negro al blanco, texto de copyright:
// C#
// Definir el mapa de bits, gráficos, Font y Brush para derechos de autor LOGO
Bitmap (Mapa de bits bm =)chart.Imagen gráfica; g
= Graphics.FromImage(BM); font f = new
Font("Arial", 12).
// Dibujar un cuadro negro con un fondo blanco para la leyenda. Cepillo lb = new
SolidBrush(Color.Blanco);
Lp = pluma Pluma nueva(Color.Black, 1);
g.FillRectangle(lb, lRect); g.DrawRectangle(lp,
lRect);
// Calcular la anchura del cuadro de leyenda, ya que el 20% del total de ancho de leyenda int = lRect
legendWidth.Width / 5.
// Calcular la altura de la caja de la leyenda como el 75% de la altura de elemento de leyenda
legendHeight int = (int) (vert * 0,75);
// Dibujar el texto
G.DrawString(e.name + " " + e.value, TF, TB, textRect, sf);
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba su conocimiento de la información
en la lección 3, "Formateo de texto." Las preguntas también están disponibles en el CD
complementario si prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final
del libro.
Términos clave
¿ Sabes lo que significan estos términos clave? Puede verificar sus respuestas mediante la
búsqueda de los términos en el glosario al final del libro.
■ Bitmap
■ Cepillo
■ Graphics
■ Pen
Casos
En los siguientes casos, podrá aplicar lo que ha aprendido en este capítulo. Usted puede
encontrar las respuestas a estas preguntas en la sección de "respuestas" al final de este libro.
Caso práctico 1: Elección de técnicas gráficas
Usted es un desarrollador de aplicaciones internas de Contoso, Inc. Usted y su equipo son
responsables de una aplicación interna Contoso usa para seguimiento de pedidos y gestión de
inventario. Recientemente, una persona en el grupo de relaciones públicas pidió a su director
para discutir los cambios que son necesarios para la apariencia y el funcionamiento de sus
aplicaciones internas. Su administrador delegado la discusión para usted.
Entrevistas
La siguiente es una lista de personal de la empresa entrevistados y sus
declaraciones:
■ Representante de Relaciones Públicas "Estamos en el proceso de re-
inventar nuestro corpo- tipo imagen. Hay muchos elementos a nuestra nueva
imagen, incluidas las imágenes, el uso de determinados colores y fuentes y
logotipos. Para la gestión de marcas coherente tanto inter-
Nally y externamente, todo lo que producimos debe ajustarse a estas normas.
Concretamente, en nuestra aplicación interna, me gustaría mostrar una
pantalla de bienvenida que muestra una foto de nuestra sede corporativa con
nuestro logo en la esquina superior izquierda. Cuando el programa se carga,
me gustaría que el logotipo aparezca en la parte superior izquierda cor- ner.
Además, todas las fuentes de la aplicación debe ser Arial 12. Oh, legal todavía
está en el proceso de aprobar nuestro logotipo, así que es probable que
cambie. Puedo proporcionarle el logotipo actual y la imagen de nuestra sede
en formato .JPEG".
■ IT Manager "Estos PR chicos cambiará el logotipo y la imagen alrededor
de una docena de veces antes de decidir lo que desea utilizar, por lo que le
sugiero almacena las imágenes como archivos en el directorio de instalación y
cargarlos dinámicamente con
La aplicación. No quiero dar nada por descontado, incluido el tamaño de las
imágenes".
Preguntas
Responda las siguientes preguntas para el administrador:
1. La foto de la Sede es de 6 megapíxeles, y es demasiado grande para la pantalla
de bienvenida. ¿Cómo se puede cambiar su tamaño?
2. ¿Cómo se puede mostrar el logotipo de la empresa a través de la fotografía de
la sede corporativa?
3. Si el tamaño de los cambios en el logotipo corporativo, ¿cómo se puede
garantizar que no cubra la totalidad de la foto de la sede y sólo consume la
esquina superior izquierda de la imagen?
4. ¿Cómo puede cambiar las fuentes utilizadas en la aplicación?
Entrevistas
La siguiente es una lista de personal de la empresa entrevistados y sus
declaraciones:
■ Vicepresidente de Ventas "La aplicación de seguimiento de ventas que
usted escribió es excelente, realmente ha mejorado la eficiencia de nuestra
organización de ventas. Ahora que tenemos datos almacenados en una base de
datos, me gustaría la posibilidad de acceso para proporcionar más
Una visión de la forma en que diferentes equipos de ventas se realizan a lo
largo del tiempo. Quiero ser capaz de ver un gráfico de línea o un gráfico de
barras que muestra el rendimiento de ventas para cada quar- ter del año, con el
rendimiento del equipo en cada una de un color diferente. También necesito
ser capaz de guardar el gráfico para poder agregarlo a una presentación que
tengo que hacer antes de que la junta de directores".
Preguntas
Responda las siguientes preguntas para el administrador:
1. ¿Qué tipo de control se puede utilizar para mostrar un gráfico en un formulario
Windows Forms de apli- cación?
2. ¿Qué método se utiliza para dibujar un gráfico de línea?
3. ¿Qué método se utiliza para dibujar un gráfico de barras?
4. ¿Cómo guardar el gráfico a un archivo?
Prácticas recomendadas
Que le ayudarán a dominar la "Mejora de la interfaz de usuario de una aplicación de .NET
Framework usando el espacio de nombres System.Drawing" objetivo del examen, complete
las siguientes tareas.
Mejorar la interfaz de usuario de una aplicación de .NET
Framework El uso de pinceles, lápices, colores y fuentes
Para esta tarea, deberá completar las prácticas de al menos 1 a 3 para ganar experiencia en el
uso de pinceles, colores y fuentes. Si desea un conocimiento en profundidad del uso de
plumas, com- pleta Práctica 4.
■ La Práctica 1 Cree una aplicación de formularios Windows Forms para
demostrar los diferentes gráficos.SmoothingMode técnicas disponibles.
Dibuje un círculo, y mostrar el nombre de la actual SmoothingMode. Cada
cinco segundos, vuelva a dibujar el círculo, y
Mostrar el nuevo SmoothingMode. Examine los bordes del círculo con las
dife- rentes SmoothingMode ajustes.
■ La Práctica 2 dibujar un círculo sólido en un formulario y cambiar el color
cada dos segundos mientras se muestra el nombre del color en la parte inferior
del formulario.
■ La Práctica 3 dibujar un círculo sólido en un formulario y cambiar el
cepillo cada 5 seg.- productos de limpieza abrasivos de ningún tipo mientras
se muestra el nombre de la brocha en la parte inferior del formulario.
■ La Práctica 4 Crear una aplicación que utiliza
la pluma.DashOffset y Pen.DashPat- tern propiedades para definir un modelo
de guión personalizado.
Capítulo 7
Rosca
Rosca es un concepto importante en el desarrollo de software. La idea básica detrás de
subprocesos es para realizar varias operaciones simultáneamente. Cada una de estas oper-
nizaciones puede ser pensado como un subproceso independiente de la lógica. La mayoría de
las operaciones tienen tiempos de inactividad, cuando una operación está a la espera de que
ocurra algo (por ejemplo, a la espera de una respuesta de un servidor Web o esperando un
recurso a ser disponible). Con rosca, usted puede tener el procesador o procesadores de una
máquina con- tinuar a hacer otras tareas durante ese tiempo.
Es cada vez más común para ejecutar código en las máquinas que tengan múltiples
procesadores. Cuando se escribe una aplicación que no utilice los múltiples subprocesos, su
aplicación es wast- ing estos procesadores adicionales. Mediante el sistema de enhebrado en el
.NET Framework, puede crear aplicaciones multiproceso robusto y fiable.
Antes de empezar
Para completar las lecciones de este capítulo, debe estar familiarizado con
Microsoft Visual Basic o en C# y se sienten cómodos con las siguientes tareas:
■ Crear una aplicación de consola en Microsoft Visual Studio, usando Visual
Basic o C#.
■ Sistema de agregar referencias a bibliotecas de clases para un proyecto.
■ Crear archivos de texto.
■ Agregar eventos en el registro de eventos.
Lección 1: Crear subprocesos
Los subprocesos son la base de aplicaciones de alto rendimiento. En .NET Framework, el espacio
de nombres System.Threading contiene los tipos que se utilizan para crear y gestionar múltiples
subprocesos en una aplicación.
Hilos sencillos
Para empezar a trabajar con hilos, debe familiarizarse con la clase Thread. Esta clase ejemplifica
un único subproceso. La clase Thread se utiliza para crear e iniciar subprocesos. La clase Thread
más importante de propiedades y métodos se describen en la Tabla 7-1 y la Tabla 7-2,
respectivamente.
Tabla 7-1 Thread Propiedades
Nombre Descripción
IsAlive obtiene un valor que indica que el subproceso actual se está
ejecutando actualmente.
IsBackground obtiene o establece si el subproceso se ejecuta como un
subproceso en segundo plano.
IsThreadPoolThread obtiene si este es un subproceso del grupo de subprocesos.
ManagedThreadId obtiene un número para identificar el subproceso actual. No
es el mismo que el ID del hilo del sistema operativo.
Nombre obtiene o establece un nombre asociado con la
rosca. Prioridad obtiene o establece la prioridad del
subproceso. ThreadState ThreadState obtiene el valor de la
rosca.
Tabla 7-2 Métodos de rosca
Nombre Descripción
Anular plantea una excepción ThreadAbortException en la
rosca para indicar que la rosca debe ser anulada.
Plantea una interrupción ThreadInterruptedException cuando
un subproceso se encuentra en un estado de bloqueo
(ThreadState.WaitSleepJoin). Si el subproceso nunca
se bloquea, la interrupción no ocurre nunca.
Unirse bloquea el subproceso de llamada hasta que el
subproceso termina.
Reanudar la obsoleta. No utilice.
Inicio establece un hilo a programarse para su ejecución.
Suspender deprecated. No utilice.
Nombre Descripción
Obtiene la actual CurrentContext ThreadContext objeto relacionado con
el subproceso actual
CurrentPrincipal Obtiene y establece el usuario asociado con el subproceso
actual
CurrentThread obtiene el hilo de ejecución actual
Nombre Descripción
BeginCriticalRegion utilizada para notificar al host que la ejecución de código
no puede ser anulada de forma segura. Anulando una
rosca entre un gion y EndCriticalRegion
BeginCriticalRe- podría dejar un AppDomain en un
estado inseguro.
EndCriticalRegion utilizada para notificar al host que ha llegado al final de
una región crítica.
Tabla 7-4 subproceso estático métodos
Nombre Descripción
GetDomain Obtiene el AppDomain asociado con el subproceso de ejecución
actual.
GetDomainID Obtiene un identificador único para el AppDomain asociado con
el subproceso en ejecución actualmente.
ResetAbort cancela una solicitud de anulación para el subproceso en ejecución
actualmente.
Dormir bloquea el subproceso actual para una determinada cantidad de
tiempo.
Renuncia a la ejecución a otros subprocesos para permitirles
trabajar.
SpinWait bloquea el subproceso actual durante un cierto número de
iteraciones.
No renuncie a la ejecución a otros subprocesos.
VolatileRead lee la última versión de un valor de campo independientemente
del procesador en un entorno multiprocesador escribió el valor.
VolatileWrite escribe un valor de campo inmediatamente para asegurarse de
que está disponible para todos los procesadores.
Nombre Descripción
Anulada la rosca se ha detenido.
AbortRequested el hilo ha sido solicitada para abortar, pero la interrupción aún
está pendiente y no ha recibido la excepción
ThreadAbortException.
Antecedentes El subproceso se ejecuta como un subproceso en segundo plano.
Ejecuta el subproceso ha comenzado.
Detenido el subproceso se ha detenido.
La rosca StopRequested está siendo solicitada para detener. Sólo para uso interno.
Tabla 7-5 enumeración ThreadState
Nombre Descripción
Suspende el subproceso ha sido suspendida. Apoyado por
compatibilidad con versiones anteriores, pero
debido suspender/reanudar no debería ser utilizado,
este estado no debería usarse.
La rosca SuspendedRequested ha solicitado que se suspenda. Apoyado por
compatibilidad con versiones anteriores, pero
debido suspender/reanudar no debería ser utilizado,
este estado no debería ser utilizado Tampoco.
Crear un subproceso
Para crear e iniciar un nuevo subproceso, siga estos pasos:
1. Crear un método que no toma argumentos y no devuelve ningún dato (por
ejemplo, utilice el tipo de valor devuelto void en C#). Este método debería
tener un aspecto parecido a este:
' VB
Shared Sub SimpleWork()
Console.WriteLine("Subproceso: {0}", Thread.CurrentThread.ManagedThreadId) End Sub
// C#
Static void SimpleWork()
{
Console.WriteLine("Subproceso: {0}", Thread.CurrentThread.ManagedThreadId);
}
// C#
ThreadStart operación = nuevo ThreadStart(SimpleWork);
// C#
Static void SimpleWork()
{
(Int x = 1; x <= 10; ++x)
{
Console.WriteLine("Subproceso: {0}",
Thread.CurrentThread.ManagedThreadId);
Esto nos permite realizar operaciones como simultáneamente como nuestro hardware lo
permita.
Nota Threading y
procesadores
Creación de aplicaciones multiproceso solía ser el dominio del desarrollador del
lado del servidor. Esto es
Ya no es el caso. Con la inclusión de hyperthreading y procesadores de doble núcleo
en el escritorio
Y en el portátil, en la mayoría de las aplicaciones de
subprocesos encontrarán útil.
Como nuestro trabajo aumenta y el tiempo que se tarda en completar cada subproceso pasa
más tiempo, tendremos que determinar cómo hacer nuestro hilo principal (el que la rosca cre-
ación existe código) espere hasta que todo el trabajo esté completo. Aquí es donde el método
Thread.Join entra en juego.
Usando Thread.Join
Más a menudo que no, necesitará la aplicación espere para un subproceso para finalizar su
ejecución. Para lograrlo, la clase Thread apoya el método join:
// C#
TheThread.join();
El método Join indica al sistema para que la aplicación espere hasta que el hilo se ha
completado. Por supuesto, en este caso simple realmente no necesita un segundo subproceso
porque está esperando a que finalice de todos modos. Un mejor ejemplo para nosotros es tener
cinco subprocesos que todos hacer algunos trabajos y para esperar de ellos. Cuando estamos
trabajando con varios subprocesos, nuestra tarea de programación es un poco más
complicado, ya que tenemos que esperar para todos nuestros hilos. Podemos hacer esto
manteniendo una referencia a todos nuestros hilos y llamar a sumarse en cada uno de los
subprocesos a la espera de las roscas para completar, una a la vez, como se muestra en el
siguiente código:
// C#
ThreadStart operación = nuevo ThreadStart(SomeWork);
Tema[] = new Thread theThreads[5];
Almacenando las roscas en una matriz, podemos esperar a que cada uno de los subprocesos
de a uno por vez. Como cada subproceso finaliza, el método Join devolverá y podemos
continuar.
Nombre Descripción
La más alta prioridad AboveNormal prioridad superior a
la Normal Normal La prioridad predeterminada BelowNormal
inferior a la normal.
La prioridad más baja
Las roscas están programadas sobre la base de esta enumeración. En la mayoría de los casos,
querrá usar el valor predeterminado (Normal). Decidir utilizar subprocesos que tienen menor
prioridad subproceso puede causar que el sistema de operación para privar a un hilo más de lo que
cabría esperar, o si utiliza prioridades mayores (especialmente mayor), puede agotar el sistema.
Aunque es nec esario--Normal no utilice las prioridades de subprocesos a veces, tomar esta
decisión con mucha cautela. Aumenta el rendimiento de un sistema simplemente aumentando la
prioridad del subproceso no es probable para ayudar en el largo plazo, otros subprocesos hambre
tienden a retroceder y provocar consecuencias inesperadas.
// C#
Static void WorkWithParameter(object o)
{
Información = cadena (string) o;
(Int x = 0; x < 10; ++x)
{
Console.WriteLine("{0}: {1}", info,
Thread.CurrentThread.ManagedThreadId);
Este es un método que toma un solo parámetro Object (y por lo tanto puede ser una referencia a
cualquier objeto). Para utilizar esto como punto de partida de un subproceso de llamada, puede
crear un delegado eterizedThreadStart Param- para que apunte a este nuevo método y utilizar
el Thread.Start Sobrecarga del método que toma un único parámetro del objeto. El siguiente
fragmento de código proporciona un ejemplo:
// C#
ParameterizedThreadStart operación =
Nueva ParameterizedThreadStart(WorkWithParameter);
Si (info == null)
{
Tirar InvalidProgramException("parámetro para el subproceso debe ser una cadena");
}
Detener subprocesos
Control de subprocesos en sus aplicaciones a menudo requiere que usted sea capaz de detener
subprocesos. El principal mecanismo para detener subprocesos es utilizar el método
Thread.Abort. Cuando el método Thread.Abort se denomina enhebrado, el sistema se prepara para
lanzar un hilo- AbortException en la rosca. Si la excepción es capturado o no, el subproceso está
detenido después de que éste se produce. El siguiente fragmento de código proporciona un
ejemplo:
// C#
Rosca newThread = new Thread(nuevo ThreadStart(AbortThisThread);
NewThread.Start();
NewThread.Abort();
Static void AbortThisThread()
{
// Datos de configuración
SomeClass.IsValid = true;
SomeClass.Hacompletado = true;
La idea detrás de una región crítica es proporcionar una región de código que debe ejecutarse
como si se tratara de una única instrucción. Cualquier intento de abortar un hilo mientras se
está dentro de una región crítica tendrá que esperar hasta después de que la región crítica está
completa. En ese punto, el hilo se abortará, lanzando la excepción ThreadAbortException. La
diferencia entre un subproceso con y sin una región crítica se ilustra en la figura 7-1.
Nota
.NET 2.0
Un cambio importante en los subprocesos en la versión 2.0 de .NET Framework
es que la rosca.Suspender y Reanudar Thread. métodos han sido retirados (y
marcados como obsoletos). Suspender y reanudar threads, debe utilizar métodos
de sincronización de subprocesos, como se describe en la Lección 2.
Thread Start trabajan más de trabajo Incluso
Más trabajo
Anulación de subproceso
Abortado
Región crítica
El contexto de ejecución
Cada subproceso tiene datos asociados a ella, y que los datos que normalmente se propaga a
nuevas roscas. Estos datos incluyen información de seguridad (la rosca y IPrincipal identidad), los
ajustes de localización (la cultura el subproceso se ejecuta en) y trans- acción información
de System.Transactions. Para acceder a la ejecución actual con- texto, el ExecutionContext clase
proporciona métodos estáticos para controlar el flujo de información de contexto.
Por defecto, el contexto de ejecución fluye a los subprocesos de ayuda, pero lo hace a un costo. Si
desea detener el flujo de la información de contexto (para aumentar el rendimiento, pero perder la
situación actual de la seguridad, la cultura y la información en el contexto de la transacción), puede
utilizar la clase ExecutionContext. Para suprimir el contexto, se
llama ExecutionContext.SuppressFlow;
C
#
= Flujo AsyncFlowControl ExecutionContext.SuppressFlow();
// Restablecer el
flujo
ExecutionContext.RestoreFlow();
// Flujo.También podría
deshacer();
V
B
/
/
C
#
Using System.Threading;
Programa de clase
{
Static void main(String[] args)
{
ThreadStart starter = new ThreadStart(contando); primera rosca
= new Thread(starter);
Enroscar la segunda = new Thread(starter);
Primera.Start();
Segundo.Start();
Primera.join();
Segundo.join();
Console.Read();
}
Resumen de la lección
■ para realizar trabajos simultáneamente, utilice la clase Thread.
■ Para iniciar la ejecución de los subprocesos, utilice el método Start de
la clase Thread.
■ para esperar en las roscas para completar, utilizar el método Join de la
clase Thread.
■ Para cancelar la ejecución de un subproceso, utilice la clase Thread
el método Abort.
■ paracompartir datos a través de los subprocesos, utilice la clase
ExecutionContext.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba tus conocimientos de la
información Les- hijo 1, "Creación de hilos." Las preguntas también están disponibles en
el CD complementario si prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción
de respuesta es correcta o no se encuentran en la sección "Respuestas" al
final del libro.
Evitando colisiones
Antes de enhebrar estuvo disponible, usted podría esperar que cualquier acceso de datos fue
realizada por un objeto a la vez. Ahora que hemos entrado en el mundo multiproceso, tenemos que
afrontar el hecho de que varios subprocesos puedan estar interrogando a nuestros objetos
simultáneamente. Esto causa problemas en algunas maneras engañosas. Por ejemplo, considere la
siguiente clase:
// C#
Contador de clase pública
{
Public static int Count;
}
// C#
Static void UpdateCount()
{
(Int x = 1; x <= 10000; ++x)
{
Counter.Count = Contador.Count + 1;
}
}
No importa cuántas veces corremos este UpdateCount, siempre deberíamos añadir 10.000 al
número en el recuento. Parece lógico entonces que si usamos subprocesos para ejecutar este
método, deberíamos obtener 10.000 multiplicado por el número de subprocesos en nuestra cuenta.
Por ejemplo, este código enhebrado podría ejecutar 10 subprocesos para actualizar la cuenta:
// C#
ThreadStart starter = new ThreadStart(UpdateCount);
Si está trabajando con un único procesador sin compatibilidad con Hyper-Threading, este código
será probablemente siempre funcionan como se espera. Pero si se ejecuta este código varias veces
en un multiprocesador o Hyper-Threaded máquina, verá que a veces el resultado- ing número es
inferior a los 100.000 esperados. ¿Por qué?
Esto sucede debido a la manera en que la actualización del campo count trabaja en el
proces- sor. En la mayoría de los equipos, este código se resuelve en tres pasos:
1. Cargar el valor en un registro dentro del procesador.
2. Aumentar (o disminuir) el valor en el registro.
3. Copiar el valor del registro a la memoria.
El problema es que en el código de subprocesos todos estos tres pasos son tratadas como
atomic oper- nizaciones. Como se muestra en la Figura 7-2, dos subprocesos cada uno
pudiera leer los valores de la memoria y al mismo tiempo actualizar con el mismo valor
actualizado. Esta es la razón por la que el código mostrado pierde algunos de los cargos.
Recuento de la carga en el registro (Count Recuento de la carga en el registro (Count
// C#.Count Contador+
+;
// O
Counter.Count += 1;
Nuestro cambio no importa porque el código compilado todavía necesita realizar las tres
operaciones indicadas anteriormente. ¿Cómo se puede solucionar este problema? Puede
utilizar la clase Interlocked para realizar la operación de incremento. La clase
Interlocked está detallado en la Tabla 7-7.
Nombre Descripción
Agregar Agrega dos enteros como una operación atómica.
Puede ser utilizado para la sustracción agregando un
número entero negativo.
Resta un decremento de un valor como una operación atómica.
Exchange Intercambia dos valores como una operación atómica.
Añade un incremento al valor como una operación atómica.
Read Lee un número de 64 bits como una operación atómica.
Necesario para
Los sistemas de 32 bits porque los números de 64 bits
están representados como dos piezas de información.
Utilizando el método de incremento Interlocked.y que pasa una referencia al valor que desea
incrementar, se garantiza que la operación de incremento es atómico, de modo que el
problema desaparece. El principal problema con la clase Interlocked es que funciona con un
pequeño conjunto de tipos de .NET. ¿Qué puede hacer si necesita sincronizar el acceso a sus
propias clases o tratar los trozos más grandes de código como atomic? ¿Cómo se puede
asegurar que otros tipos de código están protegidos contra el acceso del subproceso múltiple?
Bloqueos de sincronización abordar todas estas cuestiones.
Bloqueos de sincronización
El propósito de bloqueos de sincronización le permite sincronizar el acceso a los objetos de
.NET. Si cambiamos nuestro ejemplo de clase de contador para calcular dos cargos diferentes
(un simple recuento, y un recuento de cuando nuestro contador es un número par), nuestro
código tendrá este aspecto:
// C#
Contador de clase pública
{
Int _Count = 0.
Int _evenCount = 0.
Ahora podemos usar esta clase en una versión modificada de nuestro anterior código:
// C#
Recuento del contador = Contador nuevo();
Como antes, creamos 10 subprocesos para agregar cuenta para nosotros, pero en este caso
estamos compartiendo una instancia de la clase de contador. Cuando se ejecuta este código,
nuestro recuento sencillo siempre tiene razón, pero ocasionalmente nuestro recuento de los
valores es incorrecto. Esto es debido a que dos subprocesos puede venir y actualizar la cuenta
simple derecho uno después de otro, de manera que la línea que comprueba si el recuento es
par o impar puede perder incluso un recuento. Aunque cada una de las operaciones de
incremento es thread-safe, como una unidad, las dos opera- ciones no son.
Para resolver este problema, puede utilizar la sincronización de cerraduras. En C#, debe
utilizar la palabra clave de bloqueo, y en Visual Basic es la palabra clave SyncLock.
Podemos cambiar nuestra clase Counter para utilizar un bloqueo de sincronización para
resolver este problema de la siguiente manera:
/
/
C
#
Public void UpdateCount()
{
Bloqueo (este)
{
_Count = _conde + 1;
Si (recuento % 2 == 0) // un número par
{
_EvenCount = _evenCount + 1;
}
}
}
Nombre Descripción
Entrar crea un bloqueo exclusivo sobre un objeto especificado
Salir libera un bloqueo exclusivo sobre un objeto especificado
TryEnter intenta crear un bloqueo exclusivo sobre un determinado objeto.
Opcionalmente admite un valor de tiempo de espera en la
adquisición del bloqueo
Espere libera un bloqueo exclusivo, y bloquea el subproceso
actual hasta que pueda volver a adquirir el bloqueo
// C#
Public void UpdateCount()
{
Monitor.Enter(this);
Pruebe
{
_Count = _conde + 1;
Si (recuento % 2 == 0) // un número par
{
_EvenCount = _evenCount + 1;
}
}
Finalmente
{
Monitor.Exit(this);
}
}
/
/
C
#
Clase
Deadlocker
{
ResourceA objeto = new Object();
ResourceB objeto = new Object();
Public void First()
{
Bloqueo (ResourceA)
{
Bloqueo (ResourceB)
{
Console.WriteLine("First");
}
}
}
Primera.Start();
Segundo.Start();
Primera.join();
Segundo.join();
Nombre Descripción
IsReaderLockHeld obtiene un indicador que muestra si el lector tiene un
bloqueo
IsWriterLockHeld obtiene un indicador que muestra si un escritor tiene un
bloqueo
Nombre Descripción
AcquireReaderLock obtiene un bloqueo de lectura dentro de un tiempo
especificado. Si un bloqueo no puede concederse
dentro del período de tiempo de espera, se lanza una
excepción de aplicación.
AcquireWriterLock obtiene un bloqueo de escritura dentro de un tiempo
especificado. Si un bloqueo no puede concederse
dentro del período de tiempo de espera, se lanza una
excepción de aplicación.
DowngradeFromWriterLock convierte un bloqueo de escritura a un bloqueo de
lectura.
ReleaseReaderLock libera un bloqueo de lectura.
ReleaseWriterLock libera un bloqueo de escritura.
Actualizaciones UpgradeToWriterLock un bloqueo de lectura a un bloqueo
de escritura.
Pruebe
{
Console.WriteLine(contador);
}
Finalmente
{
RwLock.ReleaseReaderLock();
}
}
Capturas (ApplicationException)
{
Console.WriteLine("Error al obtener un bloqueo de lectura");
}
A veces cuando se necesita cambiar datos, necesitará un bloqueo de escritura. Para adquirir un
bloqueo de escritura, siga estos pasos:
1. Crear una instancia de la clase ReaderWriterLock para ser compartidos a
través de los subprocesos.
2. Cree un bloque try/catch (capturar un ApplicationException). Este bloque
try/catch se utiliza para capturar la excepción si la adquisición del bloqueo del
escritor alcanza el tiempo de espera.
3. Dentro del bloque try/catch, adquirir el bloqueo de escritura
llamando ReaderWriterLock
.AcquireWriterLock.
4. Después de adquirir el bloqueo de escritura, cree un bloque try/finally para
contener cualquier código de escritura.
5. Hacer cualquier trabajo que usted necesita en la parte try del bloque
try/finally.
6. En la parte final del bloque try/finally, suelte el bloqueo de escritura
con ReaderWriter- Lock.ReleaseWriterLock.
Por ejemplo, si desea que los cambios de valores, usted podría utilizar un bloqueo de escritura
para permitir cambiar de forma segura:
// C#
ReaderWriterLock rwLock = new ReaderWriterLock();
Int contador = 0;
Pruebe
{
RwLock.AcquireWriterLock(1000);
La ReaderWriterLock está diseñado para trabajar con dos clases de cerraduras, lectores y
auto- res. Para facilitar aún más la utilidad de estos bloqueos, ReaderWriterLock tam- puerto
actualizar un bloqueo de lectura a un bloqueo de escritura y regresar a un bloqueo de lectura.
Realiza estas dos tareas con el UpgradeToWriterLock y DowngradeFromWriter- Métodos de
bloqueo, respectivamente. Estos métodos deben utilizarse en tándem, tanto
como Monitor.Enter y Monitor.Exit métodos. El método LockCookie UpgradeToWriterLock
devuelve un objeto. Este LockCookie es una estructura que la ReaderWriterLock utiliza para
Permitir el bloqueo de escritura que se degradarán cuando haya terminado de escribir a los
datos bloqueados. El siguiente fragmento de código proporciona un ejemplo:
ejemplo:
// C#
Pruebe
{
Cookie LockCookie = rwLock.UpgradeToWriterLock(1000);
Contador++;
RwLock.DowngradeFromWriterLock(ref cookie);
}
Capturas (ApplicationException)
{
// No pudo obtener un bloqueo, por lo que ignorar la parte de escritura
}
Nombre Descripción
Manejar obtiene o establece el objeto de kernel del sistema nativo del
mango
Nombre Descripción
Cierre libera todos los recursos utilizados por el actual objeto de kernel
WaitOne bloquea el subproceso actual hasta el objeto de kernel se señaliza
// C#
Mutex m = new mutex();
// C#
Si (m.WaitOne(1000, falso)) // espere 1 segundo para bloquear
{
}
V
B
E
l
s
e
' Reaccionar a no obtener el recurso (por ejemplo, reintentando
' O notificar al usuario). End
If
// C#
}
Otra cosa
{
// Reaccionan a no obtener el recurso (por ejemplo, reintentando
// O notificar al usuario).
}
V
B
Dim theMutex como mutex = nada
Pruebe
Mutex.OpenExisting theMutex =("MYMUTEX")
Ex como WaitHandleCannotBeOpenedException capturas
' No se puede abrir el mutex porque no existe.
Intente final
' Se crea si no existe.
Si no es nada theMutex luego
TheMutex = Nuevo Mutex(false, "MYMUTEX")
End If
// C#
Mutex theMutex = null;
Usted necesita usar un bloque try/catch al intentar abrir un mutex existente porque en lugar
de devolver un valor null, una WaitHandleCannotBeOpenedException es lanzado en su
lugar. Utilizando una exclusión mutua con nombre común es una forma de sincronizar los
datos a través de procesos enlazados- aries. El primer proceso para intentar abrir
el mutex acabarán creando, y todos los demás procesos simplemente obtendrá la creada por
el primer proceso.
Clase Semaphore La clase Semaphore se utiliza para acelerar el uso de algún recurso.
Específicamente, un semáforo crea un objeto de kernel que soporta un número determinado
de ranuras válido a la vez. Cuando las ranuras están llenas, el código restante se bloqueará
hasta que esté disponible una ranura por otro subproceso liberar la ranura.
// C#
Semáforo theSemaphore = nueva Semaphore(0, 10).
La mayoría de las operaciones tras la creación del semáforo son exactamente como
las operaciones indicadas oreja- lier para la clase Mutex. La principal diferencia es
que cuando se suelte el sema- phore puede especificar cuántas ranuras desea
liberar, como se muestra en el ejemplo siguiente:
'
V
B
TheSemaphore.Suelte(5).
/
/
C
#
TheSemaphore.Liberación(
5).
Además, como con la clase Mutex, puede especificar un nombre que puede
utilizarse para crear y abrir compartidos a través de los semáforos y los límites del
proceso de AppDomain. El seguimiento fragmento de código proporciona un
ejemplo:
'
V
B
Dim theSemaphore como semáforo = nada
/
/
C
#
Semáforo theSemaphore = null;
Clase de eventos Los eventos son un tipo de objeto de kernel que tiene dos
estados, on y off. Estos estados permiten threads en una aplicación espere hasta que
un evento se señaliza a hacer algo específico. Hay dos tipos de eventos: reinicio
automático y reinicio manual. Cuando un
Evento de restablecimiento automático está señalizado, el primer objeto que espera para el
evento se vuelve a un no- estado señalado. Este comportamiento es similar al de un mutex. A
la inversa, un evento de restablecimiento manual permite todos los subprocesos que están
esperando a ser desbloqueados hasta algo restablece manualmente el evento a un estado
nonsignaled.
Estos eventos son representados como el AutoResetEvent y ManualResetEvent clases de
.NET Framework. Ambas clases heredan de una clase EventWaitHandle común (que
hereda de la clase WaitHandle).
Crear una nueva instancia de una clase de evento permite especificar el estado de la señal del
evento, como se muestra en el ejemplo siguiente:
' VB
Dim autoEvent como nuevo AutoResetEvent(true)
Dim manualEvent como nuevo ManualResetEvent(false)
// C#
AutoResetEvent autoEvent = new AutoResetEvent(true); ManualResetEvent manualEvent =
new ManualResetEvent(false);
La EventWaitHandle clase admite dos nuevos métodos que son específicas para trabajar con
eventos: Set y Reset. Estos métodos se utilizan para cambiar el evento de encendido y
apagado, como se muestra en el ejemplo siguiente:
' AutoEvent VB.set()
manualEvent.reset()
// C# autoEvent.set();
manualEvent.reset();
Al igual que los otros objetos del kernel, eventos le permiten especificar un nombre que
puede utilizarse para crear y abrirlos a través de AppDomain y los límites del proceso. El
apoyo a la denominada eventos está en el EventWaitHandle nivel. Al crear o abrir un evento
con nombre, usted necesitará tratar EventWaitHandle en lugar de las clases
AutoResetEvent y ManualResetEvent. Cuando se crea un nuevo objeto EventWaitHandle,
no sólo especifica el estado de la señal, sino también el tipo de evento es necesario. Por
ejemplo, puede utilizar el siguiente código para crear o abrir un evento con nombre:
' VB
Dim casode como EventWaitHandle = nada
Pruebe
Casode = EventWaitHandle.OpenExisting("CASODE")
Ex como WaitHandleCannotBeOpenedException capturas
' No se puede abrir el AutoResetEvent porque no existe.
Intente final
// C#
EventWaitHandle casode = null;
Programa de clase
Clase final
// C#
Using System.Threading;
Programa de clase
{
Static void main(String[] args)
{
Mutex > Const string = "RUNMEONLYONCE MutexName";
Pruebe // intentar abrir el mutex
{
Mutex.OpenExisting > }
Capturas (WaitHandleCannotBeOpenedException)
{
// No se puede abrir el mutex porque no existe.
}
Console.WriteLine("Nuestra Aplicación");
Console.Read();
}
}
11. Genere el proyecto y resolver cualquier error. Compruebe que sólo una
instancia de la aplicación se puede ejecutar a la vez.
Resumen de la lección
■ para realizar operaciones matemáticas atómico, utilice la clase entrelazadas.
■ Parabloquear los datos, utilice el bloqueo de C# o Visual
Basic SyncLock sintaxis.
■ Para bloquear los datos con un objeto de sincronización, utilice la clase
Monitor.
■ Para bloquear los datos donde varios lectores pueden acceder a los datos a la
vez, pero un escritor en un momento puede cambiar los datos, utilice
un ReaderWriterLock.
■ Parasincronizar subprocesos entre AppDomains o límites de proceso, utilice
un mutex.
■ para roscas de mariposa con un objeto de sincronización basada en recursos,
utilice un semáforo.
■ para roscas de señal entre AppDomains o límites de proceso, utilice un evento.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba su conocimiento de la
información en la lección 2, "Compartir datos". Las preguntas también están
disponibles en el CD complementario si prefiere revisarlos en forma electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de respuesta
es correcta o no se encuentran en la sección "Respuestas" al final del libro.
V
B
Buffer() Dim como byte = Nuevo Byte(100) {}
' Llamar a EndRead se bloqueará hasta que el trabajo esté completo Async
Dim numBytes as Integer = strm.EndRead(resultado)
// C#
Byte[] = new byte buffer[100].
String filename =
String.Concat(Entorno.SystemDirectory, "\\mfc71.pdb");
Para entender cómo funciona esto, echemos un vistazo a la clase FileStream.Leer la firma
del método:
' VB
La función Read(ByVal array() como Byte, _ ByVal offset As
Integer, _
Recuento ByVal As Integer) As Integer
// C#
Read(int matriz byte[], int offset, int count);
/
/
C
#
IAsyncResult BeginRead(matriz byte[], int offset, int numBytes, AsyncCallback
stateObject userCallback, objeto);
V
B
Función EndRead(ByVal asyncResult como IAsyncResult) As Integer
/
/
C
#
Int EndRead(IAsyncResult asyncResult);
Modelos de
Rendezvous
Hay tres estilos de aprendizaje con el APM para lidiar con el manejo de la
finalización de la llamada en una llamada asincrónica: espere hasta el hecho, el
sondeo y la devolución de llamada. Veamos cada uno de estos.
Ait-W El modelo Until-Done espere hasta el hecho modelo le permite iniciar el
asynchro- nous llamada y realizar otros trabajos. Una vez que el otro se hace el
trabajo, usted puede intentar finalizar la llamada y se bloqueará hasta que se
complete la llamada asincrónica. La siguiente
415 Chapter 7 Threading Lesson 3: The Asynchronous Programming Model 415
Fragmento de código
proporciona un ejemplo:
'
V
B
Buffer() Dim como byte = Nuevo Byte(100) {}
' Llamar a EndRead se bloqueará hasta que el trabajo esté completo Async
// C#
Byte[] = new byte buffer[100].
String filename =
String.Concat(Entorno.SystemDirectory, "\\mfc71.pdb");
Cuando se realiza la llamada BeginRead, null (o Nothing en Visual Basic) valores son
speci- zos para la devolución de la llamada y el estado de los objetos. Porque no vamos a
estar utilizando una devolución de llamada, son innecesarios. Después de algunos trabajos se
realiza, el código llama al método EndRead y esto bloqueará la rosca hasta que se realiza la
llamada asincrónica.
417 Chapter 7 Threading Lesson 3: The Asynchronous Programming Model 417
V
B
Buffer() Dim como byte = Nuevo Byte(100) {}
' Acabado, por lo que podemos llamar EndRead y devolverá sin bloquear
Dim numBytes as Integer = strm.EndRead(resultado)
/
/
C
#
Byte[] = new byte buffer[100].
String filename =
String.Concat(Entorno.SystemDirectory, "\\mfc71.pdb");
// Acabado, por lo que podemos llamar EndRead y devolverá sin bloquear int numBytes =
strm.EndRead(resultado);
// C#
Static byte[] = new byte buffer[100].
especificando algún objeto que podamos necesitar como el estado de la llamada. Para este
ejemplo, nosotros
421 Chapter 7 Threading Lesson 3: The Asynchronous Programming Model 421
' Acabado, por lo que podemos llamar EndRead y devolverá sin bloquear
Dim numBytes as Integer = strm.EndRead(resultado)
// C#
Static void CompleteRead(IAsyncResult resultado)
{
Console.WriteLine("Lectura completada");
// Acabado, por lo que podemos llamar EndRead y devolverá sin bloquear int numBytes
= strm.EndRead(resultado);
Excepciones y
APM
Cuando se usa el APM, podría haber operaciones que generan excepciones durante
el procesamiento asincrónico de una solicitud. Para permitir esto, las excepciones
son actu- Aliada lanzada durante la llamada EndXXX. No se genera la excepción
422 Chapter 7 Threading Lesson 3: The Asynchronous Programming Model 422
en el momento en que se produce una excepción. (Si así fuera, ¿cómo podría
coger?) si necesita manejar cualquier
423 Chapter 7 Threading Lesson 3: The Asynchronous Programming Model 423
// C#
Int numBytes = 0.
Pruebe
{
NumBytes = strm.EndRead(resultado);
}
Capturas (IOException)
{
Console.WriteLine("se produjo una excepción de E/S");
}
// C#
Application.ThreadException += new
ThreadExceptionEventHandler(Application_ThreadException);
Application.Run(new Form1();
424 Chapter 7 Threading Lesson 3: The Asynchronous Programming Model 424
Más info
APM
Para obtener más información sobre la APM, ver el libro de Jeffrey
Richter, CLR via C#, segunda edición (Microsoft
Press, 2006), en concreto, en
las páginas 599-620.
Utilizando el ThreadPool
Anteriormente en este capítulo, aprendió a crear sus propios subprocesos para
realizar programación chronous asyn-. En muchos casos, crear su propio hilo no es
necesaria ni sugerido. El sistema de enrollado en .NET admite un conjunto de
subprocesos incorporada que puede utilizarse en muchas situaciones donde usted
podría esperar a crear sus propios hilos. Por ejemplo, tomemos el mismo código
que hemos usado en la lección 1 para realizar algún trabajo en un subproceso:
'
V
B
Shared Sub WorkWithParameter(ByVal o como objeto) Dim
info As String = CType(oh, String)
Para x= 0 a 9
Console.WriteLine("{0}: {1}", info, _
Thread.CurrentThread.ManagedThreadId)
' Ralentizar la rosca y deje que otros subprocesos de trabajo
Thread.Sleep(10)
Siguiente
End Sub
// C#
Static void WorkWithParameter(object o)
{
Información = cadena (string) o;
(Int x = 0; x < 10; ++x)
{
425 Chapter 7 Threading Lesson 3: The Asynchronous Programming Model 425
// C#
Función WaitCallback workItem = nueva función WaitCallback(WorkWithParameter);
Si (!ThreadPool.QueueUserWorkItem, "ThreadPooled(workItem")
{
Console.WriteLine("No se pudo elemento de cola");
}
Este no es un atajo para crear un subproceso para usted, pero en lugar de .NET mantiene un
conjunto de subprocesos que pueden ser reutilizados en su aplicación. Este conjunto de
subprocesos es más rápido, ya que las roscas son reutilizados como necesario, ahorrando
costos de instalación costosa. Además, ayuda a regular el número de subprocesos que se
están ejecutando en cualquier momento en un proceso por la cola de trabajos a ser
realizados. Como subprocesos están disponibles, el grupo de subprocesos puestos el nuevo
trabajo a la rosca.
La clase ThreadPool admite métodos no sólo para la cola de elementos de trabajo, sino
también para manejar el ThreadPool. Los métodos más importantes de la clase ThreadPool
están detalladas en la tabla 7-13.
Tabla 7-13 ThreadPool métodos
estáticos
Nombre Descripción
GetAvailableThreads devuelve el número de subprocesos que están
disponibles para utilizar en la piscina.
GetMaxThreads devuelve el número máximo de threads este
proceso ThreadPool puede soportar.
GetMinThreads devuelve el número mínimo de subprocesos que se
crean en cualquier momento. Esto representa el número
De roscas precompilados para su uso en el grupo de
subprocesos.
427 Chapter 7 Threading Lesson 3: The Asynchronous Programming Model 427
Nombre Descripción
QueueUserWorkItem añade una pieza de trabajo para el grupo
de subprocesos para ser ejecutada por un
subproceso disponible.
RegisterWaitForSingleObject permite una devolución de llamada que se
expidan para una determinada
WaitHandle cuando
ese WaitHandle es señalizado.
SetMaxThreads Establece el número máximo de threads
en este proceso el grupo de subprocesos.
SetMinThreads establece el número mínimo de subprocesos
creados en el grupo de subprocesos.
Pulida Utilizado para la cola de E/S de archivos
UnsafeQueueNativeO asincrónica Completion Ports, utilizando
ver- las estructuras superpuestas y
NativeOverlapped. Consulte el Capítulo 13,
"interoperabilidad", para obtener más
información.
Colas UnsafeQueueUserWorkItem un elemento de trabajo para un
subproceso para escenarios de alto
rendimiento. No propaga la pila de llamadas
o contexto de ejecución información al
nuevo subproceso.
UnsafeRegisterWait Permite una devolución de llamada que se
For- SingleObject expidan para una
determinada WaitHandle cuando
ese WaitHandle es señalizado. Para su uso en
escenarios de alto rendimiento. No
Propagar la pila de llamadas o contexto de
ejecución infor- mación al nuevo subproceso.
// C#
Int los hilos.
Int completionPorts;
En primer lugar, este código obtiene el número máximo de subprocesos y los puertos de
finalización desde el ThreadPool. A los puertos de finalización es un extraordinario nivel de
kernel que objeto subproceso asincrónico se utiliza para realizar operaciones de E/S de
archivo. Normalmente hay muchos más puertos de terminación que el número de
subprocesos administrados. A continuación, puede establecer la cantidad de subprocesos
simplemente especificando el nuevo techo valores que desee utilizar.
En los casos en que los costos de inicio mediante el grupo de subprocesos son caros,
aumentando el número mínimo de subprocesos puede mejorar el rendimiento. El número
mínimo de subprocesos determina cuántos subprocesos se crea inmediatamente y esperar a
nuevos trabajos. Normalmente, el ThreadPool limita el número de hebras que se crean
durante la ejecución de un proceso a dos por segundo. Si las aplicaciones necesitan más
subprocesos creados más rápido, puede aumentar este tamaño. Cambiando el número
mínimo de subprocesos es similar a cambiar el número máximo de subprocesos:
' VB
Los subprocesos como Integer Dim
Dim completionPorts As Integer
/
/
C
#
Int los
hilos.
Int completionPorts;
Este código es idéntica a la del ejemplo anterior, excepto que usa la y
GetMinThreads
Métodos
SetMinThreads.
ThreadPool y Wait
Handle
En la lección 2, se enteró de que todos los objetos de sincronización a nivel de
kernel (Mutex, sema- phore, y evento) utilizar WaitHandle como su clase base. El
grupo de subprocesos también proporciona un mecanismo para utilizar subprocesos
en la piscina a esperar en estos manipuladores y disparar las devoluciones de
llamada a métodos cuando el WaitHandles están señalizados. Esto se hace
llamando a la rosca de la piscina.RegisterWaitForSingleObject, como se muestra
en el ejemplo siguiente:
'
V
B
/
/
C
#
// C#
Static void MutexHasFired(estado de objeto, bool caducado)
{
Si (caducado)
{
Console.WriteLine("Mutex timed out");
}
Otra cosa
{
Console.WriteLine("got señaliza mutex");
}
}
La clase
SynchronizationContext
Escritura de código asincrónico en diferentes ambiente presenta diferentes problemas. Los
modelos de subprocesos en Windows para ms son diferentes t nad t hreading modelos en
ASP.NET. Un modelo de subprocesos de Windows Forms prefiere que cualquier código de
la interfaz de usuario se ejecuta directamente en la interfaz de usuario principal de "hilo".
Esto contrasta con ASP.NET, donde la mayoría del trabajo se realiza dentro de un grupo de
subprocesos para que llamadas asincrónicas puede ocurrir en cualquier subproceso en ese
grupo. Para lidiar con estos diferentes modelos de subprocesos, el marco de trabajo .NET
admite la clase SynchronizationContext, que permite escribir código sin saber el modelo de
subprocesos de la aplicación en particular.
Para usar la clase SynchronizationContext, primero debe obtener una instancia de la clase
nizationContext Synchro- llamando a la propiedad estática Current de
la SynchronizationCon- Clase de texto. Una vez que tenga una instancia de la clase
SynchronizationContext, puede tomar cualquiera de las siguientes acciones:
■ Llame al método Send de la clase SynchronizationContext para llamar a algún
código. Enviar llamadas ejecutará el código (quizá en un subproceso independiente),
sino que se bloqueará hasta que el código de ejecución completa hasta su regreso.
433 Chapter 7 Threading Lesson 3: The Asynchronous Programming Model 433
' VB
Dim As ctx SynchronizationContext = SynchronizationContext.Current
// C#
SynchronizationContext ctx = SynchronizationContext.Current;
// C#
SynchronizationContext ctx = SynchronizationContext.Current;
Hasta que se inicie el temporizador (con cero indicando inmediatamente) y cuánto tiempo
entre disparos de temporizador. Por ejemplo, puede crear un temporizador que
desencadenará un método TimerTick cada segundo, empezando de inmediato, como este:
' VB
Dim tm como temporizador = New Timer(Nueva TimerCallback(TimerTick) _ nada, 0, 1000).
// C#
Tm = nuevo temporizador Timer(nueva TimerCallback(TimerTick), NULL, 0, 1000).
La clase Timer también admite un método de cambio que le permite re-especificar cuándo
Los incendios del temporizador y el intervalo de tiempo entre las garrapatas:
' VB
Dim tm como temporizador = New Timer(Nueva TimerCallback(TimerTick) _ nada, 0, 1000).
' Uso de infinito para especificar para detener el temporizador por ahora
tm.Cambiar(Time.Infinito, 1000).
// C#
Tm = nuevo temporizador Timer(nueva TimerCallback(TimerTick), NULL, 0, 1000).
// El uso de infinito para especificar para detener el temporizador por ahora
cambio(tm.Timeout.Infinite, 1000).
Programa de clase
Shared Sub Main(ByVal args() As String Dim)
devolución de llamada como función
WaitCallback = _
Nueva función WaitCallback(AddressOf ShowMyText)
ThreadPool.QueueUserWorkItem(llamada "Hello")
ThreadPool.QueueUserWorkItem(llamada "Hi")
ThreadPool.QueueUserWorkItem(llamada "Heya")
ThreadPool.QueueUserWorkItem(callback, "Adiós").
Console.Rea
d() End Sub
En
d
Su
b
Clase final
437 Chapter 7 Threading Lesson 3: The Asynchronous Programming Model 437
// C#
Using System.Threading;
Programa de clase
{
Static void main(String[] args)
{
Función WaitCallback callback = nueva función WaitCallback(ShowMyText);
ThreadPool.QueueUserWorkItem(llamada "Hello");
ThreadPool.QueueUserWorkItem(llamada "Hi");
ThreadPool.QueueUserWorkItem(llamada "Heya");
ThreadPool.QueueUserWorkItem(callback, "Adiós");
Console.Read();
}
Resumen de la lección
■ El modelo de programación asincrónica (APM) puede mejorar la experiencia del
usuario al permitir que varias operaciones se realizan simultáneamente, al mismo
tiempo que se mejora la capacidad de respuesta de una aplicación.
■ para realizar operaciones asincrónicas sin la sobrecarga de la clase Thread, utilice
la clase ThreadPool.
■ crear periódicamente llamadas recurrentes, utilice la clase Timer.
■ Para
recuperar el resultado de una operación asincrónica, utilice la interfaz
IAsyncResult.
■ estar
preparados para atrapar excepciones al completar una operación asincrónica
(Generalmente con el método EndXXX).
Examen de la lección
438 Chapter 7 Threading Lesson 3: The Asynchronous Programming Model 438
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final
del libro.
Términos clave
Chapter 7 Review 432
¿ Sabes lo que significan estos términos clave? Puede verificar sus respuestas mediante
la búsqueda de los términos en el glosario al final del libro.
432 Capítulo 7 Comentario
Casos
En los siguientes casos , podrá aplicar lo que ha aprendido acerca de los temas de
este capítulo. Usted puede encontrar las respuestas a estas preguntas en la sección
de "respuestas" al final de este libro.
Entre
vistas
La siguiente es una lista de personal de la empresa entrevistados y sus
declaraciones:
■ es jefe de departamento "hemos notado que cuando se ejecute la
aplicación en nuestro servidor no se consume mucho tiempo de CPU. Más de
una CPU, pero los otros tres CPU son completamente sin utilizar."
Preg
unta
s
Responda las siguientes preguntas para el
administrador:
1. ¿Por qué es la aplicación actual no utiliza todas las CPU?
2. ¿Cómo va a resolver el problema de rendimiento?
3. ¿Cómo sabes que tu aplicación no utilice demasiados subprocesos y traer una
máquina al detener?
Pregunt
as
Responda las siguientes preguntas para el
administrador:
1. ¿Cómo se puede sincronizar las aplicaciones para acceder a la interfaz de a uno por
vez?
2. Cómo esto afectará el rendimiento de las aplicaciones?
Prácticas recomendadas
Que le ayudarán a dominar los objetivos contemplados en el presente capítulo, complete
las siguientes tareas.
Práctic
a 1
■ Crear una aplicación de prueba que escribe los datos en la consola, incluido el
subproceso que está utilizando el código.
■ Utilice el ThreadPool para cola 20 instancias de los datos de escritura de código.
■ Nota cuántos hilos se utilizan y con qué frecuencia son reutilizadas de la piscina
(observando el ManagedThreadId utilizado en diferentes instancias del código).
Práctic
a 2
■ muestran el tamaño mínimo y máximo del ThreadPool llamando a la rosca de la
piscina.GetMinThreads y ThreadPool.GetMaxThreads métodos.
■ Cambiar el número mínimo y máximo de ThreadPool's subprocesos por disminuir
y aumentar las roscas utilizando
el ThreadPool.SetMinThreads ThreadPool.SetMaxThreads y métodos.
■ ejecutarla aplicación con diferentes configuraciones para ver cómo el grupo de
subprocesos funciona de forma diferente.
434 Chapter 7 Review
Prác
tica
3.
■ tomar la aplicación a diferentes configuraciones de CPU (CPU Hyper- CPU,
roscado y varias CPU), y ver cómo funciona el grupo de subprocesos ferently
dif- y cómo el número mínimo y máximo de subprocesos es distinta en
diferentes plataformas de CPU.
Tomar un Test
de práctica
Los tests de práctica en este libro's Companion CD ofrecen muchas opciones. Por
ejemplo, puede hacerse la prueba en un solo examen objetivo, o puede probar usted
mismo en todos los exámenes de certificación 70-536 contenido. Puede configurar
la prueba para que simula cuidadosamente la expe- riencia de tomar un examen de
certificación, o puede configurarlo en modo de estudio, de modo que usted puede
mirar las respuestas correctas y explicaciones después de responder a cada
pregunta.
Las lecciones de
este capítulo:
■ Lección 1: crear dominios de aplicación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437
■ La Lección 2: Configurar dominios de aplicación . . . . . . . . . . . . . . . . . . . . . . . . . . .
448
■ La Lección 3: Crear servicios de Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
457
435
Antes de empezar
Para completar las lecciones de este capítulo, debe estar familiarizado con Microsoft
Visual
Basic o en C# y se sienten cómodos con las siguientes tareas:
■ Crearuna aplicación de consola en Microsoft Visual Studio, usando Visual
Basic o C#.
■ Sistema de agregar referencias a bibliotecas de clases para un proyecto.
■ Crear archivos de texto.
■ Agregar eventos en el registro de eventos.
Lección 1: crear dominios de aplicación
A menudo los desarrolladores necesitan ejecutar un ensamblado externo. Sin embargo,
la ejecución de un ensamblado externo puede conducir al uso de recursos ineficiente y
vulnerabilidades de seguridad. La mejor forma de gestionar estos riesgos es crear un
dominio de aplicación y llame a la Asamblea desde dentro del entorno protegido.
Sistema operativo
Proceso
Figura 8-1 dominios de aplicación mantener Asambleas separadas dentro de un solo proceso
Importante contrastar los dominios de aplicación
y los procesos
El tiempo de ejecución de .NET Framework administra los dominios de
aplicación, mientras que el sistema operativo gestiona los procesos.
Tiempo de
ejecución de .NET
Framework
Dominio de
aplicación
General General
Dominio de aplicación
Dominio de aplicación
Nombre Descripción
Obtiene el dominio DomainManager manager que fue proporcionado
por el host cuando se inicializó el dominio de
aplicación.
Directorio DynamicDirectory obtiene la resolución de la Asamblea que
utiliza para sondear los conjuntos creados
dinámicamente.
Pruebas obtiene las evidencias asociadas con este dominio de
aplicación que se utiliza como insumo para la política
de seguridad. Para obtener más infor- mación sobre las
pruebas, consulte el capítulo 11, "La seguridad de la
aplicación".
FriendlyName Obtiene el nombre descriptivo de este dominio de
aplicación. Para los dominios creados por el .NET
Framework, este nombre descriptivo adopta la forma
"ProjectName.VSHOST.exe". Debe especificar el
nombre descriptivo al crear dominios de aplicación
mediante programación.
Id Obtiene un entero que identifica de forma única el
dominio de aplicación dentro del proceso.
RelativeSearchPath obtiene la ruta relativa al directorio base donde la
asamblea debería solucionador sonda para
ensamblados privados.
SetupInformation obtiene la información de configuración del dominio de
aplicación para esta instancia.
ShadowCopyFiles obtiene una indicación de si todos los ensamblados
cargados en el dominio de aplicación son
instantáneas.
Nombre Descripción
Devuelve el conjunto ApplyPolicy nombre para mostrar
después de una política que se ha aplicado.
CreateComInstanceFrom crea una nueva instancia de un determinado
tipo de COM.
Tabla 8-2 AppDomain métodos
Nombre Descripción
CreateDomain crea un nuevo dominio de aplicación. Utilice este
método en lugar de un constructor de AppDomain.
CreateInstance crea una nueva instancia de un tipo
especificado definido en un ensamblado
especificado.
CreateInstanceAndUnwrap crea una nueva instancia de un tipo especificado.
CreateInstanceFrom crea una nueva instancia de un tipo
especificado definido en el archivo de
ensamblado especificado.
CreateInstanceFromAndWrap crea una nueva instancia de un tipo
especificado definido en el archivo de
ensamblado especificado.
DefineDynamicAssembly define un conjunto dinámico en el dominio de
aplicación actual.
DoCallBack ejecuta el código en otro dominio de aplicación que es
identificado por el delegado especificado.
ExecuteAssembly ejecuta el ensamblado que contiene el archivo
especificado.
ExecuteAssemblyByName Ejecuta un ensamblado.
GetAssemblies Gets las asambleas que se han cargado en el contexto
de ejecución de este dominio de aplicación.
GetCurrentThreadId Obtiene el identificador del subproceso actual.
GetData obtiene el valor almacenado en el dominio de
aplicación actual para el nombre especificado.
InitializeLifetimeService invalidado. El AppDomain da una infinita vida- tiempo
evitando un arrendamiento sea creada.
IsDefaultAppDomain devuelve un valor que indica si la apli- cación de
dominio es el dominio de aplicación predeterminado
para el proceso.
Tabla 8-2 AppDomain métodos
Nombre Descripción
IsFinalizingForUnload indica si este dominio de aplicación se
descarga, y los objetos que contiene son
terminados por el common language
runtime.
Load carga un ensamblado en un dominio
de aplicación.
ReflectionOnlyGetAssemblies devuelve a las asambleas que se han cargado
en el contexto de sólo reflexión del dominio
de la aplicación.
SetAppDomainPolicy Establece el nivel de directiva de
seguridad para este dominio de
aplicación.
SetData asigna un valor a una propiedad del
dominio de aplicación.
SetDynamicBase Establece la ruta del directorio especificado
como la ubicación donde se almacenan los
archivos generados dinámicamente y se
accede a ellas.
Especifica cómo SetPrincipalPolicy principales y objetos de
identidad debe ser conectado a un hilo si el
subproceso intenta enlazar a un principal
mientras se ejecutaba en este dominio de
aplicación.
SetShadowCopyFiles enciende las copias sombra.
SetShadowCopyPath Establece la ruta del directorio
especificado como la ubicación de los
conjuntos de instantáneas.
SetThreadPrincipal establece el objeto principal predeterminado
que se adjunta a las roscas si intentan enlazar
a un principal mientras se ejecutaba en este
dominio de aplicación.
Descargar descarga el dominio de aplicación
especificado.
Cómo crear un dominio de
aplicación
Para crear un dominio de aplicación, llame a uno de los sobrecargados CreateDomain
AppDomain. métodos. Como mínimo, debe proporcionar un nombre para el nuevo
dominio de aplicación. El código siguiente muestra este proceso:
' VB
Dim d como AppDomain.AppDomain CreateDomain =("NewDomain")
// C#
D = AppDomain.AppDomain CreateDomain("NewDomain");
// C#
D = AppDomain.AppDomain CreateDomain("NewDomain");
D.ExecuteAssembly("Assembly.exe");
// C#
D = AppDomain.AppDomain CreateDomain("NewDomain");
D.ExecuteAssemblyByName("General");
Llamar a una asamblea de esta manera proporciona aislamiento de la asamblea pero
no aprovecha la enorme potencia y flexibilidad integradas en los dominios de
aplicación. Lección 2 explica cómo configurar dominios de aplicación en más
detalle.
V
B
Dim d como AppDomain.AppDomain CreateDomain =("NewDomain")
AppDomain.Unload(d)
/
/
C
#
D = AppDomain.AppDomain CreateDomain("NewDomain");
AppDomain.Unload(d);
// C#
D = AppDomain.AppDomain CreateDomain("New Domain");
// C#
D.ExecuteAssembly("ShowBootIni.exe");
// C#
D = AppDomain.AppDomain CreateDomain("New Domain");
D.ExecuteAssemblyByName("ShowBootIni");
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba su conocimiento de la
información en la lección 1, "Creación de dominios de aplicación." Las preguntas
también están disponibles en el CD complementario si prefiere revisarlos en forma
electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final
del libro.
// C#
D = AppDomain.AppDomain CreateDomain("New Domain");
D.ExecuteAssemblyByName("MyAssembly");
A. D.DomainUnload()
B. D = null
C. D.Unload()
D. AppDomain.Unload(d)
Lección 2: Configuración de los dominios de aplicación
Puede configurar dominios de aplicación para crear entornos personalizados para
los pe- Blies. La aplicación más importante de la modificación de la configuración
predeterminada para la apli- cación de dominio es restringir los permisos para
reducir los riesgos asociados a las vulnerabilidades de seguridad. Idealmente,
cuando se ha configurado un dominio de aplicación no sólo proporciona una unidad
de aislamiento, pero limita el daño que los atacantes pueden hacer si se explotan
con éxito un conjunto.
// C#
Objeto [] hostEvidence = {nueva zona(SecurityZone.Internet)}; Evidencia
internetEvidence = nueva evidencia(hostEvidence, null); AppDomain myDomain =
AppDomain.CreateDomain("MyDomain");
midominio.ExecuteAssembly("SecondAssembly internetEvidence.exe");
Nombre Descripción
ActivationArguments obtiene o establece datos acerca de la activación de un
dominio de aplicación.
ApplicationBase obtiene o establece el nombre del directorio raíz que
contiene la aplicación. Cuando el tiempo de ejecución
necesita para satisfacer una solicitud de tipo, busca el
ensamblado que contiene el tipo en el directorio
especificado por la propiedad ApplicationBase.
ApplicationName obtiene o establece el nombre de la aplicación.
ApplicationTrust obtiene o establece un objeto que contiene
información de seguridad y confianza.
ConfigurationFile obtiene o establece el nombre del archivo de
configuración de un dominio de aplicación.
DisallowApplication Especifica si la aplicación ruta base privada y la ruta del
- BaseProbing archivo binario están sondeado al buscar ensamblados
para cargar.
Tabla 8-3 propiedades
AppDomainSetup
Nombre Descripción
DisallowBindi Obtiene o establece un valor que indica si un
ng- redirige dominio de aplicación permite la redirección del
enlace de ensamblados.
- DisallowCode
Descargar Obtiene o establece un valor que indica si la descarga de
HTTP de asambleas es permitido para un dominio de
aplicación. El valor predeterminado es false, lo cual no es
seguro para los servicios (analizó en la lección 3, "Crear
servicios de Windows"). Para ayudar a evitar que los
servicios de descarga de código de confianza parcial,
DisallowPublish
establezca esta propiedad en true.
er- política
Obtiene o establece un valor que indica si la directiva de
editor de la sección del archivo de configuración se aplica
a un dominio de aplicación.
DynamicBase Obtiene o establece el directorio base donde el
directorio para los archivos generados
dinámicamente se encuentra.
LicenseFile Obtiene o establece la ubicación del archivo de licencia
asociado con este dominio.
LoaderOptimization especifica la política de optimización utilizado
para cargar un archivo ejecutable.
PrivateBinPath obtiene o establece la lista de los directorios bajo el
directorio base de aplicación que se probaron para
ensamblados privados.
Para aplicar estas propiedades a un dominio de aplicación, crear y Conf igurar una
Objeto AppDomainSetup, y pasarlo (junto con un objeto de pruebas) para
el AppDomain
.CreateDomain método. En el ejemplo de código siguiente se muestra este proceso:
' VB
' Crear e inicializar los ajustes de un segundo AppDomain
Dim anuncios AppDomainSetup AppDomainSetup = Nuevo
Ads.ApplicationBase = "file://" + System.Environment.CurrentDirectory
ads.DisallowBindingRedirects = False
Ads.DisallowCodeDownload = True
ads.ConfigurationFile = _
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
// C#
Anuncios AppDomainSetup = AppDomain.CurrentDomain.SetupInformation;
Console.WriteLine(ads.ApplicationBase); Console.WriteLine(ads.Nombredeaplicación);
Console.WriteLine(ads.DisallowCodeDownload);
Console.WriteLine(ads.DisallowBindingRedirects);
// C#
// Crear un objeto de pruebas para la zona de Internet
Zona safeZone = new Zone(SecurityZone.Internet);
Object[] = { hostEvidence nueva zona(SecurityZone.Internet) }; Pruebas e =
nueva evidencia(hostEvidence, null);
// C#
// Crear un AppDomain.
D = AppDomain.AppDomain CreateDomain("New Domain", e);
Resumen de la lección
■ La manera más sencilla de utilizar un dominio de aplicación para iniciar una
asamblea con privilegios limitados es especificar una zona restringida, como
la zona de Internet, como medio de prueba.
■ Para configurar las propiedades de un dominio de aplicación, cree una
instancia de la clase AppDomainSetup. A continuación, utilice la instancia al
crear el dominio de aplicación.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba tus conocimientos de la
información Les- hijo 2, "Configuración de dominios de aplicación." Las preguntas
también están disponibles en el CD complementario si prefiere revisarlos en forma
electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final del
libro.
// C#
Objeto [] hostEvidence = {nueva zona(SecurityZone.Internet)}; Pruebas e = nueva
evidencia(hostEvidence, null);
D = AppDomain.AppDomain CreateDomain("MyDomain", e);
D.ExecuteAssembly("Assembly.exe");
B.
' VB
Dim hostEvidence como Object() = {Nueva Zona (SecurityZone.Internet)} Dim d como
AppDomain.AppDomain CreateDomain =("MyDomain")
Dim e como prueba = nuevas pruebas (hostEvidence, nada)
D.Pruebas = e
d.ExecuteAssembly("Assembly.exe").
// C#
Objeto [] hostEvidence = {nueva zona(SecurityZone.Internet)}; D =
AppDomain.AppDomain CreateDomain("MyDomain");
Pruebas e = nueva evidencia(hostEvidence, null); d.Pruebas = e;
d.ExecuteAssembly("Assembly.exe");
C.
' VB
Dim myDomain como AppDomain.AppDomain CreateDomain =("MyDomain")
Midominio.ExecuteAssembly("General.exe", nueva zona (SecurityZone.Internet)
// C#
AppDomain myDomain = AppDomain.CreateDomain("MyDomain");
Midominio.ExecuteAssembly("General.exe", nueva zona(SecurityZone.Internet);
D.
' VB
Dim e como prueba = Nueva Evidencia e.AddHost(Zona
nueva (SecurityZone.Internet)
Dim myDomain como AppDomain.AppDomain CreateDomain =("MyDomain")
Midominio.ExecuteAssembly("Assembly.exe", e)
// C#
Pruebas e = nueva evidencia();
E.AddHost(nueva zona(SecurityZone.Internet);
AppDomain myDomain = AppDomain.CreateDomain("MyDomain");
Midominio.ExecuteAssembly("Assembly.exe", e);
■ a diferencia de usted hacer con algunos tipos de proyectos, debe crear la
instalación compo- nentes para aplicaciones de servicios. Los componentes de
instalación instalar y registrar el servicio en el servidor y crear una entrada
para el servicio con el administrador de control de servicios de Windows.
■ El método principal para su aplicación de servicio debe emitir el comando
Ejecutar para los servicios que su proyecto contiene. El método Run carga
los servicios en el Administrador de control de servicios en el servidor
correspondiente. Si utiliza Windows Ser- vicios plantilla de proyecto, este
método se escribe automáticamente para usted.
■ aplicacionesde servicios de Windows se ejecute en una ventana diferente
puesto que el inter- estación activa del usuario en sesión. Una estación de
ventana es un objeto seguro que con- mantiene un portapapeles, un conjunto
de átomos globales, y un grupo de objetos de escritorio. Debido a que la
estación de servicio de Windows no es una estación interactiva, cuadros de
diálogo planteadas desde dentro de una aplicación de servicio de Windows no
será visto y puede provocar que el programa deje de responder. Del mismo
modo, los mensajes de error deben ser registrados en el registro de sucesos de
Windows en lugar de planteadas en la interfaz de usuario.
■ aplicaciones de servicios de Windows se ejecutan en su propio contexto de
seguridad y que se inician antes de que el usuario inicia sesión en el equipo
con Windows en el que están instalados. Usted debe planear cuidadosamente
de qué cuenta de usuario para ejecutar el servicio dentro; un servicio que se
ejecuta bajo la cuenta de sistema tiene más permisos y privilegios que una
cuenta de usuario. El su servicio tiene más privilegios, los atacantes pueden
hacer más daño si logran explotar una vulnerabilidad de seguridad en su
servicio. - Das, debe ejecutar su servicio con los menores privilegios posibles
para minimizar los posibles daños.
Mundo
Real
Tony
Northrup
Comencé a usar .NET Framework tan pronto como los betas de la primera versión
estuvieron disponibles. Sin embargo, las versiones anteriores no admiten la
creación de servicios con el
.NET Framework. Yo no quería volver a otro entorno de desarrollo, así que me
apoyé en hacks para habilitar los ensamblados .NET que se ejecutan en segundo
plano. Habitualmente, me gustaría crear una aplicación de consola y, a
continuación, utilice Tareas programadas para configurarlo para que se inicie
automáticamente a una cuenta de usuario especial. Este sistema ha permitido que
el proceso se ejecuta continuamente en segundo plano, pero la técnica era difícil de
gestionar porque no pude utilizar el complemento Servicios para iniciar o detener
el servicio.
Cómo instalar un
servicio manualmente
Después de implementar y construir su servicio, puede instalarlo manualmente.
Para instalar un servicio manualmente, ejecute InstallUtil.exe desde la línea de
comandos con el nombre del servicio como un parámetro. Para instalar el servicio,
ejecute yourservice InstallUtil.exe. Para desinstalar el servicio,
ejecute /u yourservice InstallUtil.exe.
// C#
// Conectarse al servicio de servidor
ServiceController sc = new ServiceController("Server");
// Detener el servicio
sc.stop();
// C#
Temporizador privado t = null;
// C#
T = new timer(10000);
T.Transcurrido nueva ElapsedEventHandler +=(t_transcurrido);
// C#
T.Start();
// C#
T.stop();
// C#
Protected override void OnContinue()
{
T.Start();
}
// C#
Void t_transcurrido(object sender, ElapsedEventArgs e)
{
Pruebe
{
// Enviar la solicitud HTTP
String url = "http://www.microsoft.com";
HttpWebRequest HttpWebRequest (g =)WebRequest.Create(url); r =
(HttpWebResponse HttpWebResponse)g.GetResponse();
}
Catch (Exception ex)
{
System.Diagnostics.EventLog.WriteEntry("application", "la excepción:
" + ex.Message.ToString());
}
}
Resumen de la lección
■ un servicio de Windows es un proceso que se ejecuta en segundo plano, sin
interfaz de usuario, en su sesión de usuario.
■ Para crear un servicio de Windows, utilice Visual Studio para crear un proyecto
utilizando el Win- dows plantilla Aplicación de servicio. A continuación, escriba
el código para el OnStart y OnStop procedimientos y anular cualquier otros
métodos que desee redefinir.
Agregar la necesaria instaladores para su aplicación de servicio. Por último,
crear un proyecto de instalación para instalar el servicio.
■ Para implementar un servicio, especifique el nombre del servicio, descripción
y tipo de inicio.
Entonces reemplazar el OnStart OnStop OnPause , ,, , y OnShutdown
OnContinue pro- cedimientos como sea necesario.
■ Para crear un proyecto para instalar un servicio, primero debe definir las
propiedades de un servicio- objeto Installer para especificar la descripción del
servicio, el nombre para mostrar, el nombre del servicio y el tipo de inicio. A
continuación, defina las propiedades de un ServiceProcessInstaller para
especificar la configuración de la cuenta de servicio. En este punto, puede
instalar manualmente el servicio, o crear un proyecto de instalación para el
servicio.
■ Para controlar manualmente un servicio, puede usar la herramienta de línea
de comandos Net o los ser- vicios snap-in. Alternativamente, puede
usar System.ServiceProcess.ServiceController clase para controlar un servicio
desde un ensamblado.
Examen de la lección
Puede utilizar las siguientes preguntas para poner a prueba tus conocimientos de la
información Les- hijo 3, "Crear servicios de Windows." Las preguntas también
están disponibles en el CD de iones complementaria si prefiere revisarlos en forma
electrónica.
Nota Respuestas
Las respuestas a estas preguntas y explicaciones de por qué cada opción de
respuesta es correcta o no se encuentran en la sección "Respuestas" al final
del libro.
1. Que tipo de cuenta debe usted elegir para minimizar los riesgos de seguridad?
A. LocalService
B. NetworkService
C. LocalSystem
D. Usuario
2. Que tipo de cuenta debe usted elegir para minimizar la posibilidad de
problemas causados por permisos excesivamente restrictivos en el equipo
local?
A. LocalService
B. NetworkService
C. LocalSystem
D. Usuario
3. Cuáles de las siguientes son maneras válidas para instalar un servicio en un equipo?
(Seleccione todos los que correspondan).
A. Agregue un acceso directo a la asamblea al grupo Inicio del usuario.
B. Usar InstallUtil para instalar el servicio.
C. Configurar Tareas Programadas para lanzar su ensamblado en el inicio.
D. Utilice Visual Studio para crear un instalador para su servicio.
4. Las herramientas que puede utilizar para cambiar la cuenta de usuario de un servicio
después de que el servicio está instalado?
A. Mi equipo
B. Administración de equipos
C. Net
D. Configuración de Microsoft .NET Framework 2.0
Repaso del cap tulo
A nuevas prácticas y reforzar las habilidades aprendidas en este capítulo, puede
com- pleta las siguientes tareas:
■ Revisar el resumen del capítulo.
■ Revisar la lista de términos clave que se introdujo en este capítulo.
■ Complete los casos. Estos escenarios configurar situaciones del mundo real
involv- ción de los temas de este capítulo, y le pedimos a usted para crear una
solución.
■ completar las prácticas sugeridas.
■ tomar un examen de práctica.
Términos clave
¿ Sabes lo que significan estos términos clave? Puede verificar sus respuestas
mediante la búsqueda de los términos en el glosario al final del libro.
■ El dominio de la aplicación
■ general pruebas
■ una defensa en profundidad
Chapter 8 Review 473
■ pruebas
■ LocalService
■ LocalSystem
■ NetworkService
■ service
Casos
En los siguientes casos, podrá aplicar lo que ha aprendido sobre cómo utilizar los
dominios de aplicación y servicios. Usted puede encontrar las respuestas a estas
preguntas en la sección de "respuestas" al final de este libro.
Entrevis
tas
La siguiente es una lista de personal de la empresa entrevistados y sus
declaraciones:
■ Customer Support Manager "Estamos recibiendo muchas llamadas de clientes
que quieren desplegar nuestra app desde un servidor Web. Parece que esto no
funciona por alguna razón, aunque. Los usuarios terminan recibiendo errores
diferentes. Desde la manera en que
Describir los errores, parece que la aplicación se bloquea en momentos diferentes,
dependiendo de si la aplicación es lanzada desde la Internet pública o la intranet
local del usuario. Ahora que acabamos de decirles a copiarlo a su com- puters local
y ejecutarlo, y que parece resolver el problema. La gente no le gusta este trabajo
temporal, aunque, y quieren saber por qué no podemos hacer que funcione desde
un servidor Web".
■ Desarrollo Manager "Hablé con el Gerente de Atención al Cliente, y
parece que los usuarios están teniendo problemas debido a la seguridad de
acceso a código restringir- ciones. Necesitamos comenzar a probar nuestra
aplicación en distintas zonas, de modo que podamos
Identificar los problemas cuando están restringidos los permisos. Hágame un
favor, y escribir una aplicación que permite a nuestro equipo de
Aseguramiento de calidad para ejecutar nuestra aplicación en distintas zonas".
Preg
unta
s
Responda a las siguientes
preguntas:
1. A un alto nivel, describen cómo crear la aplicación.
2. Crear una aplicación que crea un dominio de aplicación y se inicia
la asamblea CASDemands en el nuevo dominio de aplicación con permisos
de zona de Internet.
Entre
vistas
La siguiente es una lista de personal de la empresa entrevistados y sus
declaraciones:
■ IT Manager "Gracias a la más reciente ronda de actualizaciones de
aplicaciones producidas por su equipo, todas nuestras aplicaciones soportan
archivos de configuración basado en XML. Esto es genial, porque permite a
nuestros usuarios más avanzados para afinar el conjunto de configuración-
Tings. Sin embargo, nos dimos cuenta de que uno de nuestros usuarios, hizo
un cambio que deshabilita la característica integrada en las funciones de
seguridad. Quiero que los usuarios puedan hacer algunos cambios, pero quiero
ser notificado si cambian la configuración que controla las funciones de
seguridad. Auditoría de archivos no es lo suficientemente precisa, porque
noti- fies de mí cuando el usuario realiza cualquier cambio en el archivo de
configuración. Necesito ser capaz de implementar el servicio a través de
nuestra infraestructura de Systems Management Server, así que por favor
proporcione un archivo MSI".
■ Desarrollo Manager "no necesitamos para impedir que los usuarios
realicen cambios, y no sé cómo podemos hacer que de todos modos sin
bloquear todo el acceso al archivo de configuración. Sólo tenemos que añadir
un evento al registro de eventos si detectamos
Capítulo 8 Revisión 475
Preguntas
Responda las siguientes preguntas para el administrador:
1. ¿Qué tipo de aplicación se puede crear para atender la necesidad del departamento
de TI?
2. ¿Cómo va a abordar la necesidad de implementar la aplicación con un archivo MSI?
3. ¿Qué tipo de inicio podrás especificar?
4. ¿Qué tipo de cuenta le especifique?
Prácticas recomendadas
Que le ayudarán a dominar los objetivos contemplados en el presente capítulo, complete
las siguientes tareas.
❑ ComponentInstaller class
❑ Configurar
una aplicación de .NET Framework mediante el uso de .NET
Framework
(Mscorcfg.msc)
❑ ManagedInstallerClass class
❑ InstallContext class
❑ InstallerCollection class
❑ InstallEventHandler delegado
Antes de empezar
Para completar las lecciones de este capítulo, debe estar familiarizado con
Microsoft Visual
Basic o en C# y se sienten cómodos con las siguientes
tareas:
■ Crear una consola o aplicación Winforms en Microsoft Visual Studio
utilizando
Visual Basic o C#.
■ La salida directa a la ventana de depuración o la ventana de la consola.
■ Establecer un punto de interrupción en el depurador.
■ El paso a un segmento de código.
479 Chapter 9 Installing and Configuring Applications Before You Begin 479
Mundo Real
William Ryan
La tarea de configuración de software en los últimos años era muy diferente de lo que
supone hoy en día. No hace mucho, no hubo un espacio de nombres
System.Configuration, y no hay un registro de Windows o el almacenamiento aislado.
Aun con la llegada de .NET Framework, la creación y personalización de una
aplicación la configu- ración era típicamente una tarea ardua. Al escribir mi primera
producción .NET de apli- cación, pasé más de seis horas en crear los archivos de
configuración, crear las clases para manejar esos archivos y probar el código. Sólo para
obtener una línea de base comparativa, me reescribió la configuración de los elementos
de esa misma aplicación utilizando las nuevas herramientas que se incluyen con Visual
Studio. La tarea que me tomó más de seis horas para com- pleta de entonces se realiza
en menos de 15 minutos!
481 Chapter 9 Installing and Configuring Applications Before You Begin 481
Con esto en mente, las principales ventajas de utilizar Configuración de .NET son
como sigue:
■ lepermite establecer y conservar la configuración sin tener que saber cuáles
son esos ajustes serán de antemano.
■ lepermite manejar su configuración en una intuitiva forma orientada a
objetos.
■ le permite leer y escribir la configuración sin dependencia en el registro de
Windows. Esto hará que su aplicación mucho menos intrusivas para seguridad y
administradores de red (ya que no habrá necesidad de modificar o conceder
privilegios en el registro de Windows). También ayudará a garantizar la
compatibilidad multiplataforma. (Otros sistemas operativos, como Linux y Mac
OS, no tienen un registro).
Configuración de .NET
Framework 2.0
El espacio de nombres System.Configuration sirve como repositorio de todas las clases
que utilizan los desarrolladores para administrar la configuración.
Nombre Descripción
Guardar este método escribe la configuración contenida en
este objeto de configuración a la actual config- uración archivo
XML
Este método SaveAs escribe la configuración contenida en este objeto
de configuración especificado a la con- figuración archivo XML
Nombre Descripción
AppSettings Obtiene los datos AppSettingsSection del actual aplica- ción
la configuración predeterminada
ConnectionStrings ConnectionStringsSection obtiene los datos de la
configuración predeterminada de la aplicación actual
GetSection Retrieves una sección de configuración especificado
por la configuración predeterminada de la aplicación
actual
OpenExeConfiguration abre la configuración de cliente especificado como un
Objeto System.Configuration.Configuration
OpenMachine- Abre el archivo de configuración de la máquina en el equipo
Configuración actual como un objeto System.Configuration.Configuration
- OpenMappedExe Abre la configuración de cliente especificado como
Configuración un objeto System.Configuration.Configuration
utilizando el archivo especificado y asignación de nivel
de usuario
OpenMappedMachine-
Configuración Abre el archivo de configuración de la máquina
especificada como un objeto
System.Configuration.Configuration mediante la
asignación del archivo especificado.
Dos cosas debe ser evidente en este punto. En primer lugar, ambas clases tienen dos
propiedades idénticas (AppSettings y ConnectionStrings). En segundo lugar, cada una de las
propiedades de la clase ConfigurationManager devuelve objetos de configuración. Estos
hechos deberían darle alguna sugerencia en cuanto a cómo interactúan estas dos clases. Para
recuperar la configuración, siga estos pasos:
1. Declarar un objeto de configuración.
2. Utilizar los distintos métodos en ConfigurationManager con el prefijo "Abrir"
para abrir la aplicación o el archivo de configuración de la máquina. El
siguiente código muestra esto:
"VB
Dim cs como Configuration = _
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
// C#
Configuración cs = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.ninguno);
' VB
Dim cs como Configuration = ConfigurationManager.OpenMachineConfiguration()
// C#
Configuración cs = ConfigurationManager.OpenMachineConfiguration();
' VB
Dim myMap como nuevo ExeConfigurationFileMap
MyMap.ExeConfigFilename = "DBConnectionStringDemo.exe.config" Dim cs
como Configuration = _
ConfigurationManager.OpenMappedExeConfiguration(myMap, _
ConfigurationUserLevel.None)
// C#
MyMap ExeConfigurationFileMap = new ExeConfigurationFileMap();
MyMap.ExeConfigFilename = @"DBConnectionStringDemo.exe.config";
configuración cs =
ConfigurationManager.OpenMappedExeConfiguration(myMap,
ConfigurationUserLevel.ninguno);
"VB
Dim myMap como nuevo ExeConfigurationFileMap myMap.ExeConfigFilename =
"DBConnectionStringDemo.exe.config"
// C#
MyMap ExeConfigurationFileMap = new ExeConfigurationFileMap();
MyMap.ExeConfigFilename = @"DBConnectionStringDemo.exe.config".
Configuración cs =
ConfigurationManager.OpenMappedMachineConfiguration(myMap);
Nombre Descripción
Ninguno Obtiene el objeto System.Configuration.Configuration
que se aplica a todos los usuarios
Roaming PerUserRoaming Obtiene el objeto
System.Configuration.Configuration que se aplica al usuario
actual
PerUserRoaming- Local obtiene el objeto System.Configuration.Configuration
AndLocal que se aplica al usuario actual
La principal cuestión a tener en cuenta es que el valor por defecto es Ninguno, que podría
parecer ilógico a algunos.
La siguiente cuestión que podría necesitar elaboración implica
la ExeConfigurationFileMap objeto o "Archivo Mapa." No es sorprendente que, si desea
utilizar un archivo de mapas, el tiempo de ejecución necesita algún mecanismo para
informarle de que desea hacerlo, así como un mecanismo para diciendo donde se puede
encontrar dicho archivo. Este proceso se ve facilitado por la ExeConfig- propiedad
Filename.
Cuando llame el raton- OpenMappedMachineConfigu OpenMappedExeConfiguration
o método, estás informando a la ejecución de su intención de utilizar un archivo asignado. El
constructor lo exige, por lo que el único otro requisito mínimo es para especificar
una ubicación para el archivo. La aplicación que consume necesitará los permisos adecuados
para tener acceso a este archivo, por lo que deberá asegurarse de que el archivo existe y que
tiene permiso para acceder a él.
Además de asegurar que el usuario tiene permisos de acceso al archivo, será necesario
comprobar la ubicación del archivo. Si se especifica una cadena vacía o en blanco para
el ExeConfig- propiedad Filename, el tiempo de ejecución generará una ArgumentException.
La figura 9-1 muestra el resultado de un intento de establecer la propiedad
ExeConfigFilename de String.Empty.
Figura 9-1 al intentar establecer ExeConfigFilename a una
cadena vacía
/
/
C
#
MyMap ExeConfigurationFileMap ExeConfigurationFileMap = new
String();"DBConnectionString ExeFileName = @.exe.config";
Debug.Assert(File.Exists(ExeFileName)
"El archivo o ruta asignada está ausente o es incorrecto!");
MyMap.ExeConfigFilename = ExeFileName;
Ajustes
comunes
El término ajustes comunes se refiere a unas pocas áreas que determinan cómo se
ejecutan las aplicaciones.
Un ejemplo de esta funcionalidad es configurar una aplicación para que se ejecute
en una versión específica de .NET Framework. Por ejemplo, puede crear una
aplicación con una determinada versión de Framework, pero elegir ejecutarlo con
una diferente. Para poder hacerlo, debe especificar el supportedRuntime versión en
la sección de inicio. Si desea ejecutar la aplicación bajo la versión 1.1 de
Framework, debe escribir el siguiente código en la sección de configuración de la
aplicación o el archivo de configuración Web:
<?xml version="1.0"?>
<Configuració
n>
<Inicio>
<supportedRuntime version="1.1.4322" />
</startup>
</configuration
>
Sin embargo, puede haber casos donde la versión que desee ejecutar bajo no está presente en
la máquina. Existen normas estrictas que son seguidas en estas circunstancias:
■ Si la versión de Framework que con la que se construyó la aplicación está presente,
esa versión será utilizado por la aplicación.
■ Si la versión de Framework que la aplicación fue construida con no está presente y no
se especifica nada en la etiqueta supportedRuntime versión, la aplicación se ejecutará
en la última versión del marco que está disponible en la máquina. Por lo que se
ejecutan en .NET Framework 2.0, si esa era la única versión presente, incluso si la
aplicación fue construido en virtud de las versiones 1.x.
■ Si la versión de Framework que la aplicación fue construida con no está presente, pero
el archivo de configuración especifica una etiqueta supportedRuntime, .NET
Framework usará la versión en tiempo de ejecución especificado aunque la versión
especificada debe estar presente en el equipo.
Estas reglas son intuitivos. Si no dispone de la versión correcta del motor en tiempo de
ejecución que una aplicación necesita y no especifica una versión diferente, el tiempo de
ejecución hará todo lo posible para ejecutar la aplicación. Si el tiempo de ejecución no se
puede ejecutar el ensamblado con la versión disponible, tienes un problema.
Otro escenario común implica el uso de un ensamblado compartido y comprobar que
funciona con múltiples aplicaciones. La instalación de este determinado ensamblado en la
caché de ensamblados global (GAC) y desinstalarlo desde el GAC puede ser engorroso. Para
dar cabida a esta tarea, existe una variable denominada DEVPATH que pueden configurarse.
Para tomar ventaja de esto, dos cosas que hacer:
1. Agregar una variable de entorno denominada DEVPATH que apunte a la ubicación de
la Asamblea.
2. Establecer el valor true para developmentMode. El siguiente fragmento de código
muestra cómo hacerlo:
<Configuración>
<runtime>
<developmentMode developerInstallation="true"/>
</runtime>
</configuration>
Otra tarea común implica especificar dónde una determinada versión de un ensamblado se
encuentra. Puede hacerlo mediante la herramienta Configuración de .NET Framework 2.0
(que se tratan en profundidad en la lección 3) o editando manualmente el archivo de
configuración del equipo. Hay un elemento específico, codeBase, que le permite especificar
la ubicación
Y la versión de un ensamblado de modo que cuando se carga el motor en tiempo de
ejecución, utilice lo que usted ha especificado. El código siguiente proporciona un
ejemplo de cómo hacerlo:
<Configuració
n>
<runtime>
<assemblyBinding xmlns="schemaname">
<dependentAssembly
>
<assemblyIdentity name="miprograma"
publicKeyToken="xxxxxxxxx" cultura="en-us" />
<codeBase version="x.0.0.0"
Href="http://www.adatum.com/myprogram.dll"/>
</dependentAssembly
>
</assemblyBinding>
</runtime>
</configuration
>
Otras opciones comunes son los valores de configuración que ya están definidos
por el .NET Framework. Consta de dos secciones principales, appSettings y
connectionStrings. En muchos sentidos, estos valores de configuración sean
utilizados de forma idéntica a cualquier otro componente de configuración; sin
embargo, no contienen algunos matices que les dan ventajas sobre otros temas.
Porque son tratados de manera diferente a otros valores, tienen una ubicación
predefinida en el archivo de configuración donde deben colocarse. El siguiente
fragmento de código muestra un ejemplo de archivo de configuración que incluye
tanto una sección appSettings y connectionStrings:
<?xml version="1.0" encoding="utf-8" ?>
<Configuració
n>
AppSettings <>
<add key="foo" value="Hello World!"/>
</appSettings>
<connectionStrings>
<claro/>
<add name="" AdventureWorksString
providerName="System.Data.SqlClient"="Datos
connectionString Source=localhost;
Initial Catalog=AdventureWorks; Integrated Security=true"/>
</connectionStrings>
</configuration
>
// C#
Cadena HelloWorldVariable = ConfigurationSettings.AppSettings["foo"];
// C#
NameValueCollection AllAppSettings = ConfigurationManager.AppSettings;
Console.WriteLine(AllAppSettings["foo"]); Console.WriteLine(AllAppSettings[0]);
/
/
C
#
NameValueCollection AllAppSettings =
ConfigurationManager.AppSettings.
Int32 contador = 0;
= AllAppSettings SettingsEnumerator IEnumerator.Keys.GetEnumerator();
Mientras (SettingsEnumerator.MoveNext())
{
Console.WriteLine("elemento: el valor {0}: {1}", AllAppSettings.Keys[contador],
AllAppSettings[Contador]);
}
En las versiones anteriores de Framework, realmente no se hace distinción entre una cadena
de conexión y cualquier otra cadena. Una mejora importante con respecto a la config-
uración en .NET Framework 2.0 es el soporte de tipado fuerte (aunque hay otras razones que
tipado fuerte fue agregado). Esta mejora de la capacidad de configuración incluye una
disposición específica para acomodar el tipo de proveedor. (Consultar el espacio de
nombres System.Data para más información).
De forma predeterminada, puede acceder a la propiedad ConnectionStrings casi
idénticamente a cómo tiene acceso AppSettings. La principal diferencia es que en lugar de
usar un objeto de colección: NOMBRE;valor-, se utiliza un objeto
ConnectionStringSettingsCollection en conjunción con el objeto ConnectionStringSettings.
En primer lugar veremos cuál es la configuración del archivo de configuración tendrá que
parecerse. En aras de la exhaustividad, este archivo de configuración alberga las siguientes
bibliotecas: SqlClient, OracleClient, OleDby Odbc:
<?xml version="1.0" encoding="utf-8" ?>
<Configuración>
<connectionStrings>
<claro/>
<add name="AdventureWorksString" providerName="System.Data.SqlClient"="Datos
connectionString Source=localhost;Initial Catalog=AdventureWorks; Integrated
Security=true"/>
<add name="MarsEnabledSqlServer2005String"
providerName="System.Data.SqlClient"= "connectionString
server=Aron1;database=
Pubs;Trusted_Connection=True;MultipleActiveResultSets=true" />
<add name="OdbcConnectionString"
providerName="System.Data.Odbc"
ConnectionString=
"Driver={Microsoft Access Driver (*.mdb)};DBQ=C:\adatabase.mdb;
uid=admin;pwd=R3M3emberToUseStrongPasswords;"/>
<add name="AccessConnectionString"
providerName="System.Data.OleDb"="connectionString
Provider=Microsoft.Jet.OLEDB.4.0; Origen de
datos=\PathOrShare\mibd.mdb;
User Id=admin;Password=Rememb3rStr0ngP4sswords;" />
<add name="OracleConnectionString"
providerName="System.Data.OracleClient"
ConnectionString="Fuente de datos=MyOracleDB;Integrated Security=yes;" />
</connectionStrings>
</configuration
>
Para configurar cada uno de los anteriores (bibliotecas de datos OLEDB, ODBC,
OracleClient, SqlClient), realice los siguientes pasos:
1. Especificar el elemento evidente para eliminar cualquier conexión existente de
cadenas.
2. Para cada cadena de conexión (por ejemplo, SqlClient, OracleClient, etc.),
agregar un elemento Nombre. Este elemento permite el valor a ser
referenciado por su nombre sin que el desarrollador tenga que recordar los
índices.
3. Especificar un atributo providerName para cada uno de los elementos de
nombre (por ejemplo,
System.Data.OracleClient).
4. Especificar un atributo connectionString con la cadena de conexión
apropiada para conectarse al origen de datos.
En el ejemplo mostrado anteriormente, para cada tipo de biblioteca, he agregado
una cadena de conexión específica que le corresponda. Para la biblioteca de
SqlClient, he añadido dos diferentes cadenas de conexión sólo para ilustrar que no
hay ningún problema asociado a hacerlo. La segunda cadena de conexión
SqlClient difiere de la primera principalmente en que permitió a Multiple Active
Result Sets (MARS).
Ahora que tienes los valores establecidos en el archivo de configuración, a
continuación se explica cómo acceder a ellos:
"
V
B
Dim como MySettings ConnectionStringSettingsCollection _ =
ConfigurationManager.ConnectionStrings
Si no es nada entonces MySettings
Dim sb como StringBuilder nuevo
Dim individualSettings como ConnectionStringSettings
Para cada individualSettings en sb
MySettings.append("cadena de conexión completa:
"&_
IndividualSettings.ConnectionString)
Sb.append("Nombre de proveedor: " & individualSettings.ProviderName)
Sb.append("Nombre de sección: " & individualSettings.Name)
Siguiente
Console.WriteLine(sb.ToString) End
If
// C#
MySettings ConnectionStringSettingsCollection =
ConfigurationManager.ConnectionStrings;
Si (MySettings != null)
{
Sb = new StringBuilder StringBuilder();
(Foreach en individualSettings ConnectionStringSettings MySettings)
{
Sb.append("cadena de conexión completa: " +
IndividualSettings.ConnectionString + "\r\n");
Sb.append("Nombre de proveedor: " + individualSettings.ProviderName + "\r\n");
Sb.append("Nombre de sección: " + individualSettings.Name + "\r\n");
} Console.WriteLine(sb.ToString());
}
// C#
IDbConnection MyConnection = null;
Interruptor (individualSettings.ProviderName)
{
Caso "System.Data.SqlClient":
MyConnection = new SqlConnection(individualSettings.ConnectionString);
Break;
Caso "System.Data.OracleClient":
MyConnection = nuevo(individualSettings OracleConnection.ConnectionString);
Break;
Caso "System.Data.OleDb":
MyConnection = new OleDbConnection(individualSettings.ConnectionString);
Break;
Caso "System.Data.Odbc":
MyConnection = new OdbcConnection(individualSettings.ConnectionString);
Break;
}
Aunque el código anterior ilustra cómo recuperar los diferentes tipos de cadenas de
conexión almacenada en un archivo de configuración, típico de las aplicaciones que
no utilizan varios proveedores de bases de datos. El escenario más típico es
utilizando una sola base de datos o utilizando múltiples bases de datos del mismo
tipo, por ejemplo, múltiples bases de datos de SQL Server. Como tal, si usted sabe
lo que usted está buscando, la iteración de una colección es innecesario y
posiblemente ambigua. En consecuencia, es posible que desee recuperar
directamente la cadena de conexión para el proveedor que sabe que existe. Hay dos
formas de hacerlo. El primer enfoque consiste en utilizar el nombre de sección de la
sección Acceso a la biblioteca, como se muestra aquí:
'
V
B
Dim como MySettings ConnectionStringSettings _ =
ConfigurationManager.ConnectionStrings("AdventureWorksString")
Si no es nada entonces MySettings
Dim MyConnection como nueva SqlConnection(MySettings.ConnectionString)
Console.WriteLine(MySettings.ConnectionString)
E
n
d
I
f
/
/
C
#
MySettings ConnectionStringSettings =
ConfigurationManager.ConnectionStrings["AdventureWorksString"];
Si (MySettings != null)
{
SqlConnection cn = new SqlConnection(MySettings.ConnectionString);
Console.WriteLine(MySettings.ConnectionString);
}
/
/
C
#
MySettings ConnectionStringSettings =
ConfigurationManager.ConnectionStrings[0];
Si (MySettings != null)
{
SqlConnection cn = new SqlConnection(MySettings.ConnectionString);
Console.WriteLine(MySettings.ConnectionString);
}
Del mismo modo, si usted tenía varias bases de datos del mismo tipo (y de nuevo,
usaremos el ejem- plo de SQL Server), se pueden enumerar los valores por tipo y, a
continuación, cargarlos por consi- guiente. En el ejemplo siguiente, el archivo de
configuración proporciona dos cadenas de conexión a bases de datos de SQL Server, y
AdventureWorksString MarsEnabledSqlServer2005String. Así que podemos buscar el
tipo (System.Data.SqlClient) y responder en consecuencia.
"V
B
Dim MyTypeSettings como ConnectionStringSettingsCollection _ =
ConfigurationManager.ConnectionStrings
Si no es nada entonces MyTypeSettings
Para cada typeSettings como en MyTypeSettings ConnectionStringSettings
Si typeSettings.ProviderName = "System.Data.SqlClient" Luego
Dim MyConnection como nuevo _(typeSettings
SqlConnection.ConnectionString)
Console.WriteLine("cadena de conexión: " & _
TypeSettings.ConnectionString)
End If
Siguiente
End If
// C#
MyTypeSettings ConnectionStringSettingsCollection =
ConfigurationManager.ConnectionStrings;
Si (MyTypeSettings != null)
{
(Foreach en MyTypeSettings typeSettings ConnectionStringSettings)
{
Si (typeSettings.ProviderName == "System.Data.SqlClient")
{
SqlConnection MyConnection = new
SqlConnection(typeSettings.ConnectionString);
Console.WriteLine("cadena de conexión " +
TypeSettings.ConnectionString);
}
}
}