Professional Documents
Culture Documents
EJEMPLO................................................................................................................56
BLOQUE TRY..........................................................................................................80
BLOQUE CATCH....................................................................................................80
BLOQUE FINALLY.................................................................................................82
CAPTURA DE ERRORES NO CONTROLADOS...................................................83
........................................................................................................................................................................86
Clases usadas para E/S de archivos...........................................................................................................86
Clases usadas para leer y escribir en secuencias.......................................................................................86
Clases comunes de secuencias de E/S..............................................................................................................87
E/S y seguridad.................................................................................................................................................87
8.2 Operaciones bsicas en archivos texto y binario.....................................................................................87
8.2.1 Crear y 8.2.2 Abrir................................................................................................................................87
8.2.4 Lectura y escritura, 8.2.5 Recorrer y 8.2.3 Cerrar................................................................................89
Lista es el nombre
[ i ] es el ndice
lista[1]
lista[2]
lista[3]
double[ ] miLista;
float[ ] temperatura;
Ejemplo
miLista [7] representa el ltimo elemento del arreglo
Regla: En C#, un ndice del arreglo es siempre un entero que comienza en cero y termina
en tamao-1.
Precaucin: Tenga cuidado ya que, al contrario que en otros lenguajes de programacin,
los ndices siempre se encierran entre corchetes: temperaturas [15] .
Un arreglo completo se puede inicializar con una sintaxis similar a:
double[ ] miLista = { 1.5, 2.45, 3.15, 7.25, 8.4 };
esta sentencia crea el arreglo miLista que consta de cinco elementos. Tambin podran
haberse utilizado
double[ ] miLista = new int[5] { 1.5,2.45,3.15,7.25,8.4 };
double[ ] miLista = new int[ ] { 1.5, 2.45, 3.15, 7.25, 8.4 };
Clculo del tamao
El tamao de un arreglo se obtiene con la propiedad Length. As, por ejemplo, si se crea
un arreglo miLista, la sentencia miLista.Length devuelve el tamao del arreglo miLista
(10, por ejemplo).
Utilizacin de los elementos del arreglo
Las variables que representan elementos de un arreglo se utilizan de igual forma que
cualquier otra variable. Por ejemplo:
int[ ] n = new int[50];
int j =0;
//...
j = n[j] + n[10];
Algunas sentencias permitidas en C#
temperatura [5] = 45;
temperatura [8] = temperatura [5] + 10;
Los elementos de un arreglo se suelen procesar mediante bucles (por ejemplo for) por las
siguientes razones:
Todos los elementos del arreglo son del mismo tipo y tienen las mismas
propiedades; por esta razn, se procesan de igual forma y repetidamente utilizando
un bucle.
Ejemplos
1. El bucle for siguiente introduce valores en los elementos del arreglo. El tamao del arreglo
se obtiene en miLista.Length.
for (int i = i; i < miLista.Length; i++)
miLista[i] = i;
2. foreach (double i in miLista)
{
MessageBox.Show("El valor es:"+ i);
}
3. int[ ] cuenta = new int[100];
int i;
for (i = 0; i < cuenta.Length; i++)
cuenta[i] = 0;
COPIA DE ARREGLOS
Con frecuencia se necesita duplicar un arreglo o bien una parte de un arreglo. Existen dos
mtodos para copiar arreglos: copiar elementos individuales utilizando un bucle y utilizar
el mtodo Arreglo.Copy.
Mtodo 1
Un mtodo para copiar arreglos es escribir un bucle que copia cada elemento desde el
arreglo origen al elemento correspondiente del arreglo destino.
Ejemplo
Este cdigo copta arregloFuente en arregloDestino
Nota: Crear un proyecto, poner un botn en la forma, hacer doble clic en el botn,
declarar e inicializar los arreglos, escribir el siguiente cdigo.
for (int i = 0; i < arregloFuente.Length; i++)
arregloDestino[i] = arregloFuente[i];
Mtodo 2
Otra forma de copiar arreglos es usar el mtodo Arreglo.Copy que tiene los siguientes
formatos:
public static void Copy(Array arregloOrigen,Array arregloDestino, int longitud)
public static void Copy (Array arregloOrigen, int pos_ini, Array arregloDestino, int pos_fin,
int longitud)
La sintaxis del mtodo Copy ( ) es:
Array.Copy(arregloOrigen, arregloDestino, longitud);
Array.Copy(arregloFuente, pos_ini, arregloDestino, pos_fin, longitud) ;
Pos_ini = Posicin donde comienza la copia.
Pos_fin = Posicin donde comienza el almacenamiento.
Longitud = Nmero de elementos a ser copiados.
Ejemplo
object[ ] arregloOrigen = {4, 5, 1, 25, 100};
int[ ] arregloDestino1 = new int[arregloOrigen.Length];
Array.Copy(arregloOrigen,0, arregloDestino1,0, arregloOrigen.Length);
for (int i = 0; i < arregloDestino1.Length; i++)
MessageBox.Show(arregloDestino1[i]);
int[ ] arregloDestino2 = new int[arregloOrigen.Length];
for (int i = 0; i < arregloOrigen.Length; i++)
arregloDestino2[i] = (int)arregloOrigen[i];
for (int i = 0; i < arregloDestino2.Length; i++)
MessageBox.Show(arregloDestino2[i]);
0
1
2
3
0
1
2
3
(b) Arreglo bidimensional
Figura 1.3. Arreglos: (a) Una dimensin; (b) Dos dimensiones.
La Figura 1.4 ilustra un arreglo de doble subndice, a, que contiene tres filas y cuatro
columnas (un arreglo de 3 x 4). Un arreglo con m filas y n columnas se denomina arreglo
m_por _n.
Columna 0
Columna 1
Columna 2
Columna 3
Fila 0
Fila 1
Fila 2
a[0,0]
a[1,0]
a[2,0]
a[0,1]
a[1,1]
a[2,1]
a[0,2]
a[1,2]
a[2,2]
a[0,3]
a[1,3]
a[2,3]
Figura 1.4. Un arreglo de dos dimensiones con tres filas y cuatro columnas.
Cada elemento del arreglo a se identifica como tal elemento mediante el formato a [i, j]; a
es el nombre del arreglo, e i,j son los subndices que identifican unvocamente la fila y la
columna de cada elemento de a; obsrvese que todos los elementos de la primera fila
comienzan por un primer subndice de 0 y los de la columna cuarta tienen un segundo
subndice de 3 (4 -1).
La inicializacin puede efectuarse en el momento de la declaracin especificando los
valores iniciales entre { }.
Ejemplos
1. Un arreglo b de 2x2 dimensiones se puede declarar e inicializar con:
int[ , ] b= {{5,6}, {7,8}};
b [0, 0]
(5)
b [1, 0]
(7)
b [0,1]
(6)
b [1,1]
(8)
y tambin con
int[ , ] b=new int[2, 2] {{5, 6}, {7, 8}};
o con
int[ , ] b=new int[ , ] {{5, 6}, {7, 8}};
2. La declaracin
int[ , ] b = {{4,5,6}, {7,8,9}};
crea un arreglo de dos filas y tres columnas, en el que la primera fila contiene 4 , 5, 6 .
Un medio rpido para asignar valores a los elementos de un arreglo de dos dimensiones
es utilizar bucles for
for (int x = 0; x < 3; ++x) {
for (int y = 0; y < 3; ++y) {
tabla[x , y] = 5;
}
}
Los bucles anidados funcionan del modo siguiente. El bucle externo, el bucle x, arranca
estableciendo x a 0. Como el cuerpo del bucle x es otro bucle, a continuacin arranca
dicho bucle interior, bucle y, fijando y a 0. Todo esto lleva al programa a la lnea que
10
1
0
4
8
12
2
1
5
9
13
3
2
6
10
14
3
7
11
15
11
12
13
Ejemplo
//Creacin, instanciacin e inicializacin en una nica sentencia
int[,,] numeres = new int[2,3,4] {{{1,2,3,4},{2,3,4,5},{3,4,5,6}},{{6,S,4,3},{S,4,3,2},{4,3,2,1}}};
MessageBox.Show(numeros.Length);
// Resultado: 24
MessageBox.Show(numeros.Rank);
// Resultado: 3
MessageBox.Show(numeros.GetLength(0));
// Resultado: 2
Importante: La propiedad Arreglo.Rank devuelve el nmero de dimensiones de
un.arreglo.
El mtodo Arreglo.GetLength devuelve el nmero de elementos en una determinada
dimensin de un arreglo.
1.3 Arreglo Multidimensional
Los elementos de un arreglo en C# pueden ser de cualquier tipo, incluidos otros arreglos.
En los arreglos de arreglos cada fila puede contener un nmero diferente de columnas y
se pueden asignar dinmicamente, como sigue:
int[ ] [ ] b;
b = new int[3] [ ];
b[0] = new int[5];
b[1] = new int[4];
b[2] = new int[3];
// asigna filas
// asigna 5 columnas a la fila 0
// asigna 4 columnas a la fila 1
// asigna 3 columnas a la fila 2
14
// asigna filas
// asigna 5 columnas a la fila 0
// asigna 7 columnas a la fila 1
// asigna 3 columnas a la fila 2
15
II Mtodos y Mensajes
2.0 Clases y Objetos
2.0.1 Clases
Las clases son estructuras o plantillas que sirven para definir un objeto. En C# una clase
puede tener los siguientes miembros: campos de datos (constantes, campos de slo
lectura o variables), declaraciones de tipos anidadas, eventos, indexadores, operadores,
constructores, destructores, propiedades y mtodos; y, habitualmente, una clase de un
objeto contiene una coleccin de mtodos y definiciones de datos. Si se disea una clase
que representa a un cliente, no se ha creado un objeto. Un objeto es una instancia
(ejemplar, caso) de la clase Cliente y, por consiguiente, puede, naturalmente, haber
muchos objetos de la clase Cliente. La creacin de una variable especfica de un tipo
particular de clase se conoce como instanciacin (creacin de instancias) de esa clase.
Una clase describe la constitucin de un objeto y sirve como plantilla para construir
objetos, especificando la interfaz pblica de un objeto. Una clase tiene un nombre y
especifica los miembros que pertenecen a la clase. Una vez que se define una clase, el
nombre de la clase se convierte en un nuevo tipo de dato y se puede utilizar para:
16
El siguiente ejemplo representa una clase Circulo que se utilizar para construir objetos
del tipo Crculo:
class Circulo
{
public double radio =5.0;
public double CaleularSuperficie()
{
return radio*radio*3.141592;
}
}
Esta clase Circulo es, simplemente, una definicin que se utiliza para declarar y crear
objetos Circulo.
Las clases se declaran con el siguiente formato:
class Nombre
{
// cuerpo de la clase
}
El cuerpo de la clase define los miembros. Excepto en el caso de sobrecarga, todos los
miembros deben tener nombres distintos.
2.0.2 Objeto
Un objeto es una coleccin de datos y una serie de rutinas miembros, entre las que
destacan los mtodos. Los objetos representan cosas fsicas o abstractas, pero que
tienen un estado y un comportamiento. Por ejemplo, una mesa, un estudiante, un crculo,
una cuenta corriente, un prstamo, un automvil,... se consideran objetos. As, ciertas
propiedades definen a un objeto y ciertas propiedades definen lo que hace. Las
propiedades que definen el objeto se conocen como campos de datos y el
comportamiento de los objetos, es decir las acciones que deseamos que efecten, se
define como mtodos.
La sintaxis para declarar un objeto es:
NombreClase NombreObjeto;
Circulo myCirculo;
2.1 Atributos Const y Static
Es importante el lugar donde se efecta la declaracin de las variables, pues ste
determina su mbito. Las variables miembros de una clase se denominan campos y,
17
18
Pueden declararse constantes tanto campos como variables locales. El tipo de una
constante puede ser cualquiera, pero a una constante de un tipo referencia, que no sea
una cadena, slo se le podr asignar el valor null.
Cuando se necesite un nombre simblico para un valor constante que no pueda
establecerse en tiempo de compilacin, en lugar de una constante, se declarar una
variable de slo lectura (readonly). Las constantes de clase se declaran en el cuerpo de la
clase y fuera de todos los mtodos; la declaracin de una constante puede ir acompaada
por un conjunto de atributos, el modificador new y alguno de los siguientes modificadores
de acceso: public, protected internal, protected, internal, o private. Las constantes son
miembros estticos, pero no pueden llevar el modificador static. La sintaxis para declarar
una constante es:
const tipoDato NOMBRE CONSTANTE = valor;
Ejemplos
1. const double PI = 3.141592;
superficie = radio * radio * PI;
2. class Prueba
public const string CADENA = "O."; void Mtodo ( )
{
/ / ...
/ / ...
}
3. using System;
class EjConstSLect
{
//Compara constantes y campos de slo lectura
class ConstSLect
{
//no se puede modificar el valor de una constante
const int X = 1;
//se establece el valor en una declaracin de inicializacin
readonly int y = 200;
public readonly int z;
//Constructores
public ConstSLect()
{
// se establece su valor en el constructor
z = 6;
}
public ConstSLect(int pl, int p2)
{
// se anula el valor establecido en la declaracin de inicializacin
y = pl; z = p2;
19
}
public int Suma()
{
return x+y+z;
}
}
public static void Main()
{
ConstSLect instancial= new ConstSLect();
/* un campo de slo lectura slo puede ser asignado en un constructor o en una
declaracin de inicializacin y la sentencia siguiente sera incorrecta
instancial.z = 4; */
Console.WriteLine(instancial.Suma()) ;
ConstSLect instancia2 = new ConstSLect(2,3);
Console.WriteLine(instancia2.Suma());
}
Las constantes literales son valores de un determinado tipo escritos directamente en un
programa. Dichas constantes podrn ser enteras, reales, lgicas, carcter, cadena de
caracteres, o el valor null.
Constantes enteras
Las constantes enteras representan nmeros enteros con y sin signo. La escritura de
constantes enteras en un programa debe seguir unas determinadas reglas:
Constantes reales
Una constante flotante representa un nmero real, siempre tiene signo y puede
representar tanto aproximaciones (coma flotante) como valores exactos (decimal). Las
constantes reales tienen el tipo double por defecto, aunque tambin pueden ir seguidas
por una da D que especifique su pertenencia a dicho tipo.
Cuando se les aade una f o F se obliga a que sean de tipo float y una m o M indican un
decimal.
20
double dr =-3.0m;
la sentencia anterior es incorrecta, no puede asignarse directamente un decimal a una
variable de tipo coma flotante
Constantes lgicas
Las constantes literales de tipo lgico disponibles en C# son true (verdadero) y false
(falso).
Constantes de tipo carcter
Una constante de tipo carcter es un carcter Unicode vlido encerrado entre comillas
simples. Los caracteres que pueden considerarse vlidos son:
21
Los mtodos son los miembros de un tipo clase donde se especifican las acciones que se
realizan por un objeto. Una invocacin a un mtodo es una peticin al mtodo para que
ejecute su accin y lo haga con el objeto mencionado. La invocacin de un mtodo se
denominara tambin llamar a un mtodo y pasar un mensaje a un objeto.
Nota: Existen dos tipos de mtodos: aquellos que devuelven un nico valor y aquellos
que realizan alguna accin distinta de devolver un valor. Los mtodos que realizan alguna
accin distinta de devolver un valor se denominan mtodos void.
La implementacin de los mtodos podra ser como sta:
public class CuentaCorriente
{
private double saldo;
public void Depositar(double cantidad)
{
saldo = saldo + cantidad;
}
public void Retirar(double cantidad)
{
saldo = saldo - cantidad;
}
public double ObtenerSaldo()
{
return saldo;
}
}
22
Comentario
23
Mientras que una instancia de una clase contiene una copia independiente de
todos los campos de instancia de la clase, slo existe una copia de cada campo
esttico.
Si la palabra clave static se aplica a una clase, todos los miembros de la clase
deben ser estticos.
Las clases, incluidas las clases estticas, pueden tener constructores estticos. Se
llama a los constructores estticos en algn momento comprendido entre el inicio
del programa y la creacin de instancias de la clase.
Para comprender el uso de miembros estticos, considere una clase que representa al
empleado de una compaa. Suponga que la clase contiene un mtodo que cuenta
empleados y un campo que almacena el nmero de empleados. Ni el mtodo ni el campo
pertenecen a ninguna instancia de empleado. En vez de ello, pertenecen a la clase
compaa. Por tanto, se deberan declarar como miembros estticos de la clase.
Ejemplo
Este ejemplo lee el nombre y el identificador de un nuevo empleado, incrementa en uno el
contador de empleados y muestra la informacin del nuevo empleado, as como el nuevo
nmero de empleados. Por motivos de simplicidad, el programa lee el nmero actual de
empleados desde el teclado. En una aplicacin real, esta informacin se leera desde un
archivo.
En el siguiente ejemplo vamos a usar el modo consola solo para uso de explicacin en
clase.
// cs_static_keyword.cs
using System;
public class Employee
{
public string id;
public string name;
public Employee() { }
public Employee(string name, string id)
{
this.name = name;
this.id = id;
}
public static int employeeCounter;
public static int AddEmployee()
{
return ++employeeCounter;
}
24
}
class MainClass : Employee
{
static void Main()
{
Console.Write("Enter the employee's name: "); string name = Console.ReadLine();
Console.Write("Enter the employee's ID: "); string id = Console.ReadLine();
// Create and configure the employee object:
Employee e = new Employee(name, id);
Console.Write("Enter the current number of employees: ");
String n = Console.ReadLine();
Employee.employeeCounter = Int32.Parse(n);
Employee.AddEmployee();
// Display the new information:
Console.WriteLine("Name: {0}", e.name);
Console.WriteLine("ID: {0}", e.id);
Console.WriteLine("NewNumber of Employees: {0}", Employee.employeeCounter);
}
}
Entrada
Tara Strahan
AF643G
15
25
CalcTax(this);
// keywords_this.cs
// this example
using System;
class Employee
{
private string name;
private string alias;
private decimal salary = 3000.00;
// Constructor:
public Employee(string name, string alias)
{
// Use this to qualify the fields, name and alias:
this.name = name;
this.alias = alias;
}
// Printing method:
public void printEmployee()
{
26
Resultados
Name: John M. Trainer
Alias: jtrainer
Taxes: $240.00
2.7 Forma de pasar argumentos.
La cabecera de un mtodo especifica el nmero y tipo de parmetros formales requeridos.
En el interior de una clase, un mtodo se identifica no slo por su nombre, sino tambin
por su lista de parmetros formales. Por consiguiente, el mismo nombre de mtodo se
puede definir ms de una vez con diferentes parmetros formales para conseguir la
sobrecarga de mtodos.
Cuando se llama a un mtodo se deben proporcionar un nmero y tipo correctos de
argumentos. Los argumentos incluidos en la llamada a un mtodo se conocen como
27
b. Invocacin incorrecta
La sentencia ImprimirN (4, "Carchelejo") es incorrecta, ya que el tipo de dato 4 no coincide
con el tipo del parmetro mensaje y, de igual modo, el segundo parmetro "Carchelejo"
tampoco coincide con el tipo del segundo parmetro formal n.
2. El mtodo ImprimirNX imprime n veces todos los argumentos que se le pasen como
parmetros a continuacin del hmero de veces a iterar, que deben ser de tipo ushort o
implcitamente convertibles a ushort.
class Prueba
{
// conversin implcita
static void ImprimirNX(int n, params ushort[ ] x)
for (int i=0; i<n; i++)
{
foreach(char j in x)
System.Console.Write("{0} ", j);
//conversin explcita
System.Console.WriteLine();
28
}
public static void Main () {
ImprimirNX (3, 'H', 79, 76, 'A');
ImprimirNX(2);
ImprimirNX (1, 65, 68, 73, 79, 83 );
}
Salida
HoLAHoLAHOLA
Tres veces la palabra HOLA
A DIO S
Dos lneas en blanco Una vez la palabra ADIOS
La operacin de enlazar (binding) los parmetros reales a los formales se denomina
paso de parmetros. Cuando se llama a un mtodo con ms de un argumento, dichos
argumentos se evalan de modo secuencial, de izquierda a derecha. Existen dos tipos de
paso de parmetros: por valor y por referencia.
PASO DE PARMETROS POR VALOR
En C#, los parmetros pueden ser pasados por valor o por referencia. Cuando un
parmetro se pasa por valor, sus valores se copian en nuevas posiciones, que se pasan a
la subrutina; como consecuencia de esto, si el parmetro cambia su valor dentro del
mtodo, propiedad, indexador, operador o constructor, dicho valor no cambiar en el
programa llamador original. Hay que tener en cuenta que las variables que se pasan
como parmetros pueden ser de tipo valor o de tipo referencia. Una variable de un tipo
valor almacena directamente los datos, esto significa que cuando el valor de la variable se
pasa a un parmetro formal, los datos se copian y su cambio en el interior del mtodo no
repercute en el exterior. Una variable de un tipo de referencia no contiene los datos
directamente, sino una referencia al lugar donde se encuentran almacenados los mismos;
esto implica que, cuando se pasa por valor una variable de tipo referencia, es posible
devolver cambiados a los datos apuntados por la referencia, pero no el valor de la propia
referencia.
PASO DE PARMETROS POR REFERENCIA
El paso por referencia permite a los mtodos, propiedades, indexadores, operadores, y
constructores devolver el valor de los parmetros modificado. Cuando se pasa un
parmetro por referencia no se copia el valor del parmetro actual en una nueva posicin
de memoria, sino que se establece un nuevo nombre para el parmetro actual. Por
defecto, los parmetros se pasan por valor y para pasar un parmetro por referencia es
necesario emplear las palabras reservadas out o ref.
Ejemplo
29
using System;
class Quebrado
{
int num, den;
// Constructor
public Quebrado(int x, int y)
{
num = x;
den = y;
}
/* Variable referencia pasada por valor
Permite que el objeto referenciado se devuelva modificado */
public static void Simplificar(Quebrado q)
{
int a = q.num;
int b = q.den;
/* Clculo del mximo comn divisor entre a y b.
El mximo comn divisor se obtiene aplicando el algoritmo
de Euclides, que dice que para obtener el mximo comn divisor
entre dos nmeros, se dividen y si el resto es cero el divisor
es el mximo comn divisor, si el resto no es cero se
intercambian dividendo por divisor y divisor por resto,
repitindose la operacin hasta obtener un resto cero,
en cuyo caso el divisor ser el mximo comn divisor */
while (b > 0)
{
int r = a % b;
a = b;
b = r;
}
/* Al terminar el bucle el mximo comn divisor se encuentra
almacenado en a.
Para simplificar el quebrado se divide numerador y denominador
por su mximo comn divisor */
q.num = q.num / a;
q.den = q.den / a;
}
30
31
32
class SimpleMath
{
public int AddTwoNumbers(int number1, int number2)
{
return number1 + number2;
}
public int SquareANumber(int number)
{
return number * number;
}
}
Para emplear un valor devuelto por un mtodo, el mtodo de llamada puede utilizar la
propia llamada del mtodo en cualquier parte donde un valor del mismo tipo sea
suficiente. El valor devuelto tambin se puede asignar a una variable. Por ejemplo, los dos
ejemplos de cdigo siguientes logran el mismo objetivo:
int result = obj.AddTwoNumbers(1, 2);
obj.SquareANumber(result);
33
obj.SquareANumber(obj.AddTwoNumbers(1, 2));
El uso de una variable intermedia, en este caso result, para almacenar un valor es
opcional. La legibilidad del cdigo puede ser til o puede ser necesaria si el valor se va a
utilizar ms de una vez.
34
predeterminados indicados
Tipo de
valor
Valor predeterminado
bool
false
byte
char
'\0'
decimal
0,0M
double
0,0D
enum
float
0,0F
int
long
0L
sbyte
short
struct
uint
ulong
ushort
Los constructores son mtodos de clase que se ejecutan cuando se crea un objeto de un
tipo determinado. Los constructores tienen el mismo nombre que la clase y, normalmente,
inicializan los miembros de datos del nuevo objeto.
En el ejemplo siguiente, una clase denominada Taxi se define con un constructor simple.
Esta clase crea instancias con el operador new. El operador new invoca el constructor
Taxi inmediatamente despus de asignar la memoria al nuevo objeto.
35
class TestTaxi
{
static void Main()
{
Taxi t = new Taxi();
System.Console.WriteLine(t.isInitialized);
}
}
Destructores
Los destructores se utilizan para destruir instancias de clases.
Comentarios
Los destructores no se pueden definir en estructuras. Slo se utilizan con clases.
Una clase slo puede tener un destructor.
Los destructores no se pueden heredar ni sobrecargar.
No se puede llamar a los destructores. Se invocan automticamente.
Un destructor no permite modificadores de acceso ni tiene parmetros.
Por ejemplo, el siguiente cdigo muestra una declaracin de un destructor para la clase
Car:
class Car
{
~ Car() // destructor
{
// cleanup statements...
}
}
El destructor llama implcitamente al mtodo Finalize en la case base del objeto. Por lo
tanto, el cdigo de destructor anterior se traduce implcitamente a:
36
Esto significa que se llama al mtodo Finalize de forma recursiva para todas las instancias
de la cadena de herencia, desde la ms derivada hasta la menos derivada.
El programador no puede controlar cundo se llama al destructor, porque esto lo
determina el recolector de elementos no utilizados. El recolector de elementos no
utilizados comprueba si hay objetos que ya no estn siendo utilizados por ninguna
aplicacin. Si considera un objeto elegible para su destruccin, llama al destructor (si
existe) y reclama la memoria utilizada para almacenar el objeto. Tambin se llama a los
destructores cuando se cierra el programa.
Es posible forzar la recoleccin de elementos no utilizados llamando al mtodo Collect,
pero en la mayora de los casos debe evitarse su uso por razones de rendimiento.
3.3 Aplicaciones de constructores y destructores / 3.4 Tipos de constructores y
destructores
En general, C# no requiere tanta administracin de memoria como se necesita al
desarrollar con un lenguaje que no est diseado para un motor en tiempo de ejecucin
con recoleccin de elementos no utilizados. Esto es debido a que el recolector de
elementos no utilizados de .NET Framework administra implcitamente la asignacin y
liberacin de memoria para los objetos. Sin embargo, cuando la aplicacin encapsule
recursos no administrados como ventanas, archivos y conexiones de red, debera utilizar
destructores para liberar dichos recursos. Cuando el objeto se marca para su destruccin,
el recolector de elementos no utilizados ejecuta el mtodo Finalize.
Ejemplo
En el siguiente ejemplo se crean tres clases que forman una cadena de herencia. La clase
First es la clase base, Second se deriva de First y Third se deriva de Second. Las tres
tienen destructores. En Main(), se crea una instancia de la clase ms derivada. Cuando
ejecute el programa, observe que se llama a los destructores de las tres clases
automticamente y en orden, desde la ms derivada hasta la menos derivada.
class First
{
~First()
{
System.Console.WriteLine("First's destructor is called");
}
}
37
~Third()
{
System.Console.WriteLine("Third's destructor is called");
}
}
class TestDestructors
{
static void Main()
{
Third t = new Third();
}
}
Constructores de instancias
Los constructores de instancia se utilizan para crear e inicializar instancias. El constructor
de clase se invoca al crear un objeto nuevo, por ejemplo:
class CoOrds
{
public int x, y;
// constructor
public CoOrds()
{
x = 0;
y = 0;
}
}
Se llama a este constructor cada vez que se crea un objeto basado en la clase CoOrds.
Un constructor como ste, que no toma ningn argumento, se denomina constructor
predeterminado. Sin embargo, suele ser til proporcionar constructores adicionales. Por
ejemplo, se puede agregar a la clase CoOrds un constructor que permita especificar los
valores iniciales de los miembros de datos:
// A constructor with two arguments:
public CoOrds(int x, int y)
{
this.x = x;
this.y = y;
}
Esto permite crear objetos CoOrd con valores iniciales concretos o predeterminados, del
modo siguiente:
CoOrds p1 = new CoOrds();
CoOrds p2 = new CoOrds(5, 3);
38
39
Constructores estticos
Un constructor esttico se utiliza para inicializar cualquier dato esttico o realizar una
accin determinada que slo debe realizarse una vez. Es llamado automticamente antes
de crear la primera instancia o de hacer referencia a cualquier miembro esttico.
class SimpleClass
{
// Static constructor
static SimpleClass()
{
//...
}
}
Los constructores estticos tienen las propiedades siguientes:
Un constructor esttico no permite modificadores de acceso ni tiene parmetros.
Se le llama automticamente para inicializar la clase antes de crear la primera instancia o
de hacer referencia a cualquier miembro esttico.
El constructor esttico no puede ser llamado directamente.
El usuario no puede controlar cuando se ejecuta el constructor esttico en el programa.
Los constructores estticos se utilizan normalmente cuando la clase hace uso de un
archivo de registro y el constructor escribe entradas en dicho archivo.
Los constructores estticos tambin son tiles al crear clases contenedoras para cdigo
no administrado, cuando el constructor puede llamar al mtodo LoadLibrary.
Ejemplo
En este ejemplo, la clase Bus tiene un constructor esttico y un miembro esttico, Drive().
Cuando se llama a Drive(), se invoca el constructor esttico para inicializar la clase.
public class Bus
{
// Static constructor:
static Bus()
{
System.Console.WriteLine("The static constructor invoked.");
}
public static void Drive()
{
System.Console.WriteLine("The Drive method invoked.");
}
}
class TestBus
{
static void Main()
{
Bus.Drive();
}
}
40
IV Sobrecarga
4.1 Conversin de tipos
La conversin entre tipos de datos se puede hacer de forma explcita utilizando una
conversin de tipos; en algunos casos, se permiten conversiones implcitas. Por ejemplo:
static void TestCasting()
{
int i = 10;
float f = 0;
f = i; // An implicit conversion, no data will be lost.
f = 0.5F;
i = (int) f; // An explicit conversion. Information will be lost.
}
Una conversin de tipos invoca de forma explcita al operador de conversin de un tipo a
otro. En la conversin de tipos se producir un error si no se ha definido ninguno de estos
operadores. Puede escribir operadores de conversin personalizados para convertir entre
los tipos definidos por el usuario.
class Test
{
41
42
Algunos de los mtodos de esta clase toman un objeto de parmetro que implementa la
interfaz IFormatProvider. Este parmetro puede proporcionar informacin de formato
especfica de la referencia cultural para ayudar en el proceso de conversin. Los tipos de
valor base pasan por alto este parmetro, pero los tipos definidos por el usuario que
implementan IConvertible pueden tenerlo en cuenta.
Para obtener ms informacin sobre los tipos de valor base, vea el tema correspondiente
que aparece en la seccin Vea tambin.
Ejemplo
En el siguiente ejemplo de cdigo, se muestran algunos de los mtodos de conversin de
la clase Convert, entre los que se incluyen ToInt32, ToBoolean y ToString.
double dNumber = 23.15;
try {
// Returns 23
int iNumber = System.Convert.ToInt32(dNumber);
}
catch (System.OverflowException) {
System.Console.WriteLine(
"Overflow in double to int conversion.");
}
// Returns True
bool bNumber = System.Convert.ToBoolean(dNumber);
// Returns "23.15"
string strNumber = System.Convert.ToString(dNumber);
try {
// Returns '2'
char chrNumber = System.Convert.ToChar(strNumber[0]);
}
catch (System.ArgumentNullException) {
System.Console.WriteLine("String is null");
}
catch (System.FormatException) {
System.Console.WriteLine("String length is greater than 1.");
}
// System.Console.ReadLine() returns a string and it
// must be converted.
int newInteger = 0;
try {
System.Console.WriteLine("Enter an integer:");
newInteger = System.Convert.ToInt32(
System.Console.ReadLine());
}
catch (System.ArgumentNullException) {
System.Console.WriteLine("String is null.");
}
43
catch (System.FormatException) {
System.Console.WriteLine("String does not consist of an " +
"optional sign followed by a series of digits.");
}
catch (System.OverflowException) {
System.Console.WriteLine(
"Overflow in string to int conversion.");
}
System.Console.WriteLine("Your integer as a double is {0}",
System.Convert.ToDouble(newInteger));
En el ejemplo de cdigo siguiente se muestran algunos de los mtodos de conversin de
la clase Convert.
// Sample for the Convert class summary.
using System;
class Sample
{
public static void Main()
{
string nl = Environment.NewLine;
string str = "{0}Return the Int64 equivalent of the following base types:{0}";
bool xBool = false;
short xShort = 1;
int xInt = 2;
long xLong = 3;
float xSingle = 4.0f;
double xDouble = 5.0;
decimal xDecimal = 6.0m;
string xString = "7";
char xChar = '8'; // '8' = hexadecimal 38 = decimal 56
byte xByte = 9;
// The following types are not CLS-compliant.
ushort xUshort = 120;
uint xUint = 121;
ulong xUlong = 122;
sbyte xSbyte = 123;
// The following type cannot be converted to an Int64.
// DateTime xDateTime = DateTime.Now;
Console.WriteLine(str, nl);
Console.WriteLine("Boolean: {0}", Convert.ToInt64(xBool));
Console.WriteLine("Int16: {0}", Convert.ToInt64(xShort));
Console.WriteLine("Int32: {0}", Convert.ToInt64(xInt));
Console.WriteLine("Int64: {0}", Convert.ToInt64(xLong));
Console.WriteLine("Single: {0}", Convert.ToInt64(xSingle));
Console.WriteLine("Double: {0}", Convert.ToInt64(xDouble));
44
120
121
122
123
varios mtodos con el mismo nombre, siempre que sus firmas sean nicas dentro de
esa clase, estructura o interfaz.
La sobrecarga de los constructores de instancias permite que una clase o una
45
declare varios indizadores, siempre que sus firmas sean nicas dentro de esa clase,
estructura o interfaz.
La sobrecarga de los operadores permite que una clase o una estructura declare
varios operadores con el mismo nombre, siempre que sus firmas sean nicas dentro
de esa clase o estructura.
El siguiente ejemplo muestra un conjunto de declaraciones de mtodos sobrecargados.
void F();
// F()
// F(int)
// F(ref int)
// F(int, int)
// F(string)
// F(int)
error
// F(string[])
46
Notacin funcional
op x
operator op(x)
x op
operator op(x)
x op y
operator op(x, y)
Las declaraciones de operador definidas por el usuario siempre requieren que por lo
menos uno de los parmetros sea del tipo de la clase o estructura que contiene la
declaracin del operador. Por lo tanto, no es posible que un operador definido por el
usuario tenga la misma firma que un operador predefinido.
Las declaraciones de operador definidas por el usuario no pueden modificar la sintaxis,
precedencia o asociatividad de un operador. Por ejemplo, el operador / siempre es un
operador binario, siempre tiene el nivel de precedencia especificado en la y siempre es
asociativo por la izquierda.
47
Aunque es posible que un operador definido por el usuario realice cualquier clculo que le
interese, no se recomiendan las implementaciones que generan resultados distintos de
los que intuitivamente pueden esperarse. Por ejemplo, una implementacin de operator
== debe comparar la igualdad de los dos operandos y devolver un resultado bool
apropiado.
La sobrecarga de operadores permite utilizar implementaciones de operadores definidas
por el usuario en operaciones en las que al menos uno de los operandos es de un tipo
estructura o clase definido por el usuario. El primer ejemplo muestra cmo utilizar la
sobrecarga de operadores para crear una clase de nmeros complejos que define la
suma compleja. El segundo ejemplo muestra cmo utilizar la sobrecarga de operadores
para implementar un tipo lgico de tres valores.
Ejemplo 1
Este ejemplo muestra cmo utilizar la sobrecarga de operadores para crear una clase de
nmeros complejos Complex que define la suma compleja. El programa muestra las
partes real e imaginaria de los nmeros y el resultado de la suma mediante un mtodo
sustituto del mtodo ToString.
// complex.cs
using System;
public struct Complex
{
public int real;
public int imaginary;
public Complex(int real, int imaginary)
{
this.real = real;
this.imaginary = imaginary;
}
// Declare which operator to overload (+), the types
// that can be added (two Complex objects), and the
// return type (Complex):
public static Complex operator +(Complex c1, Complex c2)
{
return new Complex(c1.real + c2.real, c1.imaginary + c2.imaginary);
}
// Override the ToString method to display an complex number in the suitable format:
public override string ToString()
{
return(String.Format("{0} + {1}i", real, imaginary));
}
public static void Main()
{
Complex num1 = new Complex(2,3);
48
Resultado
First complex number: 2 + 3i
Second complex number: 3 + 4i
The sum of the two numbers: 5 + 7i
Ejemplo 2
Este ejemplo muestra cmo utilizar la sobrecarga de operadores para implementar un tipo
lgico de tres valores. Los valores posibles de este tipo son DBBool.dbTrue,
DBBool.dbFalse y DBBool.dbNull, donde el miembro dbNull indica un valor desconocido.
Nota Los operadores True y False definidos aqu slo resultan de utilidad para tipos que
representan valores True, False y Null (ni True ni False), como los utilizados en bases de
datos.
// dbbool.cs
using System;
public struct DBBool
{
// The three possible DBBool values:
public static readonly DBBool dbNull = new DBBool(0);
public static readonly DBBool dbFalse = new DBBool(-1);
public static readonly DBBool dbTrue = new DBBool(1);
// Private field that stores -1, 0, 1 for dbFalse, dbNull, dbTrue:
int value;
// Private constructor. The value parameter must be -1, 0, or 1:
DBBool(int value)
{
this.value = value;
}
// Implicit conversion from bool to DBBool. Maps true to
// DBBool.dbTrue and false to DBBool.dbFalse:
49
50
51
case 1:
return "DBBool.True";
default:
throw new InvalidOperationException();
}
}
}
class Test
{
static void Main()
{
DBBool a, b;
a = DBBool.dbTrue;
b = DBBool.dbNull;
Console.WriteLine( "!{0} = {1}", a, !a);
Console.WriteLine( "!{0} = {1}", b, !b);
Console.WriteLine( "{0} & {1} = {2}", a, b, a & b);
Console.WriteLine( "{0} | {1} = {2}", a, b, a | b);
// Invoke the true operator to determine the Boolean
// value of the DBBool variable:
if (b)
Console.WriteLine("b is definitely true");
else
Console.WriteLine("b is not definitely true");
}
}
Resultado
!DBBool.True = DBBool.False
!DBBool.Null = DBBool.Null
DBBool.True & DBBool.Null = DBBool.Null
DBBool.True | DBBool.Null = DBBool.True
b is not definitely true
En las reglas siguientes se describen las pautas para sobrecargar operadores:
Defina los operadores en tipos de valor que sean tipos de lenguajes lgicos integrados,
como la Estructura System.Decimal.
Proporcione mtodos de sobrecarga de operadores slo en la clase en la que se definen
los mtodos. El compilador de C# cumple esta directriz.
Utilice las convenciones de firma y de nomenclatura descritas en Common Language
Specification (CLS). El compilador de C# lo hace automticamente.
Utilice la sobrecarga de operadores en los casos en los que el resultado de la operacin
es obvio. Por ejemplo, tiene sentido poder restar un valor Time de otro valor Time y
52
V Herencia
5.1 Introduccin a la herencia
Las clases pueden heredar de otra clase. Para conseguir esto, se coloca un signo de dos
puntos despus del nombre de la clase al declarar la clase y se denomina la clase de la
cual se hereda (la clase base) despus del signo de dos puntos, del modo siguiente:
public class A
{
public A() { }
}
public class B : A
{
public B() { }
}
La nueva clase (la clase derivada) obtiene todos los datos no privados y el
comportamiento de la clase base, adems de todos los dems datos y comportamientos
que define para s misma. La nueva clase tiene dos tipos efectivos: el tipo de la nueva
clase y el tipo de la clase que hereda.
Una clase extendida hereda todos los miembros de su clase base, excepto constructores
53
Herencia
Ejemplo
Ninguna
class ClassA { }
Simple
54
Estructuras
Ejemplo
En el siguiente ejemplo se muestra la declaracin de campos de clase, constructores y
mtodos. Tambin muestra la creacin de instancias de objetos y la impresin de datos
de instancia. En este ejemplo, se declaran dos clases, la clase Kid, que contiene dos
campos privados (name y age) y dos mtodos pblicos. La segunda clase, MainClass, se
utiliza para contener Main.
// keyword_class.cs
// class example using System;
class Kid
{
private int age;
private string name;
/ / Default constructor:
public Kid() { name = "N/A"; }
// Constructor:
public Kid(string name, int age)
{
this.name = name;
this.age = age;
}
// Printing method:
public void PrintKid() {
Console.WriteLine("{0}, {1} years old.", name, age);
}
}
class MainClass
{
static void Main()
{
// Create objects
// Objects must be created using the new operator:
Kid kid1 = new Kid("Craig", 11);
Kid kid2 = new Kid("Sally", 10);
// Create an object using the default constructor:
Kid kid3 = new Kid();
// Display results:
Console.Write("Kid #1: ");
kid1.PrintKid(); Console.Write("Kid #2: ");
kid2.PrintKid();
Console.Write("Kid #3: "); kid3.PrintKid();
}
}
Regla: Los constructores y destructores no se heredan por la subclase.
55
En el ejemplo siguiente, se define una clase pblica que contiene un campo nico, un
mtodo y un mtodo especial denominado constructor. Luego se crean instancias de la
clase con la palabra clave new.
public class Person
{
// Field
public string name;
// Constructor
public Person()
{
name = "unknown";
}
// Method
public void SetName(string newName)
{
name = newName;
}
}
class TestPerson
{
static void Main()
{
Person person1 = new Person();
System.Console.WriteLine(person1.name);
person1.SetName("John Smith");
System.Console.WriteLine(person1.name);
}
}
5.5 Parte protegida
5.5.1 Propsito de la parte protegida
La palabra clave protected es un modificador de acceso a miembros. Un miembro
protegido es accesible dentro de su clase y por clases derivadas.
Un miembro protegido de una clase base es accesible en una clase derivada slo si el
acceso se realiza a travs del tipo de la clase derivada. Por ejemplo, considere el
siguiente segmento de cdigo:
56
// protected_keyword.cs
using System;
class A {
protected int x = 123;
}
class B : A {
static void Main() {
A a = new A();
B b = new B();
// Error CS1540, because x can only be accessed by
// classes derived from A.
// a.x = 10;
// OK, because this class derives from A.
b.x = 10;
}
}
La instruccin a.x =10 genera un error, ya que A no se deriva de B.
Los miembros de una estructura no se pueden proteger, ya que la estructura no se puede
heredar.
Ejemplo
En este ejemplo, la clase DerivedPoint se deriva de Point; por lo tanto, puede obtener
acceso a los miembros protegidos de la clase base directamente desde la clase derivada.
// protected_keyword_2.cs
using System;
class Point
{
protected int x;
protected int y;
}
class DerivedPoint: Point
{
static void Main()
{
DerivedPoint dp = new DerivedPoint();
// Direct access to protected members:
dp.x = 10;
dp.y = 15;
Console.WriteLine("x = {0}, y = {1}", dp.x, dp.y);
}
}
Resultados
57
x = 10, y = 15
58
59
Comentarios
El mtodo override proporciona una nueva implementacin de un miembro heredado de
una clase base. El mtodo reemplazado por una declaracin override se conoce como
mtodo base reemplazado. El mtodo base reemplazado debe tener la misma firma que
el mtodo override. No se puede reemplazar un mtodo esttico o no virtual. El mtodo
base reemplazado debe ser virtual, abstract u override.
Una declaracin override no puede cambiar la accesibilidad del mtodo virtual. El mtodo
override y el mtodo virtual deben tener el mismo modificador de nivel de acceso.
No se pueden utilizar los modificadores new, static, virtual o abstract para modificar un
mtodo override.
Una declaracin de propiedad de reemplazo debe especificar el mismo modificador de
acceso, tipo y nombre que la propiedad heredada, y la propiedad reemplazada debe ser
virtual, abstract u override.
Ejemplo
Este ejemplo define una clase base denominada Employee y una clase derivada
denominada SalesEmployee. La clase SalesEmployee incluye una propiedad adicional,
salesbonus, y reemplaza al mtodo CalculatePay para tenerlo en cuenta.
using System;
class TestOverride
{
public class Employee
{
public string name;
// Basepay is defined as protected, so that it may be
// accessed only by this class and derrived classes. protected decimal basepay;
// Constructor to set the name and basepay values.
public Employee(string name, decimal basepay)
{
this.name = name;
this.basepay = basepay;
}
// Declared virtual so it can be overridden.
public virtual decimal CalculatePay() { return basepay; }
}
// Derive a new class from Employee.
public class SalesEmployee : Employee
{
// New field that will affect the base pay. private decimal salesbonus;
// The constructor calls the base-class version, and
// initializes the salesbonus field.
public SalesEmployee(string name, decimal basepay, decimal salesbonus) :
base(name, basepay)
{
this.salesbonus = salesbonus;
}
// Override the CalculatePay method
// to take bonus into account.
60
61
62
63
y = -1;
object();
count = n;
// Variable initializer
// Invoke object() constructor
}
}
class B: A
{
double sqrt2;
ArrayList items;
int max;
public B(): this(100) {
B(100);
// Invoke B(int) constructor
items.Add("default");
}
public B(int n): base(n 1) {
sqrt2 = Math.Sqrt(2.0);
// Variable initializer
items = new ArrayList(100); // Variable initializer
A(n 1);
// Invoke A(int) constructor
max = n;
}
Destructores
Un destructor es un miembro que implementa las acciones necesarias para destruir una
instancia de una clase. Un destructor se declara utilizando una declaracin-de-destructor
(destructor-declaration):
destructor-declaration:
attributesopt externopt ~ identifier ( ) destructor-body
destructor-body:
block
;
Una declaracin-de-destructor puede incluir un conjunto de atributos (attributes).
El identificador de un declarador-de-destructor debe nombrar la clase en la que se declara
el destructor. Si se especifica cualquier otro nombre, se produce un error en tiempo de
compilacin.
Cuando una declaracin de destructor incluye un modificador extern, se dice que es un
destructor externo. Debido a que la declaracin de destructor externo no proporciona una
implementacin real, su cuerpo-de-destructor (destructor-body) consiste en un punto y
coma. Para el resto de destructores, el cuerpo-de-destructor consiste en un bloque que
especifica las instrucciones necesarias para destruir una instancia de la clase. Un cuerpode-destructor corresponde exactamente al cuerpo-de-un-mtodo de un mtodo de
instancia con un tipo de valor devuelto void.
Los destructores no se heredan. Por lo tanto, una clase slo tiene el destructor que se
puede declarar en la propia clase.
Como un destructor no puede tener parmetros, no puede ser sobrecargado; por lo tanto,
una clase slo puede tener como mximo un destructor.
Los destructores se invocan automticamente y no se pueden invocar explcitamente. Una
instancia se convierte en candidata para destruccin cuando ya ninguna parte de cdigo
64
65
class A
{
void Finalize() {}
}
// permitted
VI Polimorfismo y reutilizacin
6.1 Concepto del polimorfismo
El polimorfismo ayuda al programador a escribir cdigo ms fcil de modificar y ampliar.
Polimorfismo es pues la capacidad de un objeto para responder a un mensaje basado en
su tipo y posicin en la jerarqua de clases. Una respuesta apropiada implica la capacidad
del objeto para elegir la implementacin del mtodo que mejor se adapte a sus
caractersticas. Mediante tcnicas polimrficas es posible escribir cdigo que manipule
objetos de muchas clases diferentes de un modo uniforme y consistente, con
independencia de su tipo exacto. La flexibilidad y generalidad de las estructuras
polimrficas es una de las ventajas ms significativas de la programacin orientada a
objetos.
La estrategia para desarrollar una estructura polimrfica comienza con la identificacin de
los mtodos comunes a travs de un grupo de tipos de objetos similares pero no idnticos
y organizando una jerarqua de clases donde los mtodos comunes se sitan en la clase
base, mientras que los restantes se organizan en clases derivadas, deducidas de esta
clase base. La clase base define una interfaz a travs de la cual un objeto de cualquiera
de las subclases especificadas se puede manipular. Es importante considerar que los
mtodos de la interfaz compartida se deben declarar en la clase base y han de ser de
virtuales. De esta forma las clases derivadas pueden redefinir dichos mtodos mediante el
modificador override, se establece ligadura dinmica y, en tiempo de ejecucin, se busca
cul es la clase del objeto que ha recibido el mensaje y se decide qu mtodo se ejecuta.
6.2 Clases Abstractas
6.2.1 Definicin y 6.2.2 Redefinicin
66
Las clases abstractas estn estrechamente relacionadas con las interfaces. Son clases de
las que no es posible crear instancias; frecuentemente, estn implementadas slo
parcialmente o no estn implementadas. Una de las principales diferencias entre las
clases abstractas y las interfaces es que una clase puede implementar un nmero
ilimitado de interfaces, pero slo puede heredar de una clase abstracta (o de cualquier
otra clase). Una clase derivada de una clase abstracta conserva la capacidad de
implementar interfaces. Las clases abstractas son tiles para crear componentes, porque
permiten especificar un nivel invariable de funcionalidad para algunos mtodos y aplazar
la implementacin de otros hasta que se necesite una implementacin especfica de la
clase. Tambin admiten bien el uso de versiones, porque, si se necesita una funcionalidad
adicional en las clases derivadas, se puede agregar a la clase base sin romper el cdigo.
abstract class WashingMachine
{
public WashingMachine()
{
// Code to initialize the class goes here.
}
abstract public void Wash();
abstract public void Rinse(int loadSize);
abstract public long Spin(int speed);
}
class MyWashingMachine : WashingMachine
{
public MyWashingMachine()
{
// Initialization code goes here.
}
override public void Wash()
{
// Wash code goes here.
}
override public void Rinse(int loadSize)
{
// Rinse code goes here.
67
}
override public long Spin(int speed)
{
// Spin code goes here.
}
}
Cuando se implementa una clase abstracta, debe implementarse cada mtodo abstracto
(MustOverride) de esta clase; cada mtodo implementado debe recibir el mismo nmero y
tipo de argumentos y devolver el mismo valor que el mtodo especificado en la clase
abstracta.
6.3 Definicin de una interfaz y 6.4 Implementacin de la definicin de una interfaz.
Las interfaces se definen utilizando la palabra clave interface. Por ejemplo:
interface IComparable
{
int CompareTo(object obj);
}
Las interfaces describen un grupo de comportamientos relacionados que pueden
pertenecer a cualquier clase o estructura. Las interfaces pueden estar compuestas de
mtodos, propiedades, eventos, indizadores o cualquier combinacin de estos cuatro
tipos de miembros. Una interfaz no puede contener campos. Los miembros de interfaz
son automticamente pblicos.
Las clases y estructuras se pueden heredar de interfaces de manera similar a como las
clases pueden heredar una clase base o estructura, con dos excepciones:
Una clase o estructura puede heredar ms de una interfaz.
Cuando una clase o estructura hereda una interfaz, hereda definiciones de
68
69
void Paint();
}
class SampleClass : IControl, ISurface
{
// Both ISurface.Paint and IControl.Paint call this method.
public void Paint()
{
}
}
Sin embargo, los miembros de dos interfaces no realizan la misma funcin, esto puede
llevar a una implementacin incorrecta de una o ambas interfaces. Es posible implementar
un miembro de interfaz explcitamente, creando un miembro de clase que slo se llama a
travs de la interfaz y es especfico de sta. Esto se puede llevar a cabo asignando al
miembro de clase el nombre de la interfaz y un punto. Por ejemplo:
public class SampleClass : IControl, ISurface
{
void IControl.Paint()
{
System.Console.WriteLine("IControl.Paint");
}
void ISurface.Paint()
{
System.Console.WriteLine("ISurface.Paint");
}
}
El miembro de clase IControl.Paint slo est disponible a travs de la interfaz IControl,
mientras que ISurface.Paint slo est disponible a travs de ISurface. Ambas
implementaciones de mtodo son independientes y ninguna est directamente disponible
en la clase. Por ejemplo:
SampleClass obj = new SampleClass();
//obj.Paint(); // Compiler error.
IControl c = (IControl)obj;
c.Paint(); // Calls IControl.Paint on SampleClass.
ISurface s = (ISurface)obj;
s.Paint(); // Calls ISurface.Paint on SampleClass.
La implementacin explcita tambin se usa para resolver casos donde cada una de las
dos interfaces declara miembros diferentes del mismo nombre como propiedad y mtodo:
interface ILeft
{
int P { get;}
}
interface IRight
{
70
int P();
}
Para implementar ambas interfaces, una clase tiene que utilizar implementacin explcita,
ya sea para la propiedad P, el mtodo P o ambos, con el fin de evitar un error del
compilador. Por ejemplo:
class Middle : ILeft, IRight
{
public int P() { return 0; }
int ILeft.P { get { return 0; } }
}
Propiedades de interfaces
A continuacin se muestra un ejemplo de descriptor de acceso de un indizador de
interfaz:
public interface ISampleInterface
{
// Property declaration:
string Name
{
get;
set;
}
}
Un identificador de acceso de una propiedad de interfaz no tiene cuerpo. As, el propsito
de los descriptores de acceso es indicar si la propiedad es de lectura y escritura, de slo
lectura o de slo escritura.
Ejemplo
En este ejemplo, la interfaz IEmployee tiene una propiedad de lectura y escritura, Name, y
una propiedad de slo lectura, Counter. La clase Employee implementa la interfaz
IEmployee y utiliza las dos propiedades. El programa lee el nombre de un empleado
nuevo y el nmero actual de empleados, y muestra como resultado el nombre del
empleado y el nuevo nmero de empleados calculado.
Se podra utilizar el nombre completo de la propiedad, que hace referencia a la interfaz en
la que se declara el miembro. Por ejemplo:
string IEmployee.Name
{
get { return "Employee Name"; }
set { }
}
Por ejemplo, si la clase Employee implementa dos interfaces ICitizen y IEmployee, y
ambas tienen la propiedad Name, ser necesario implementar explcitamente el miembro
de interfaz. Es decir, la siguiente declaracin de propiedad:
71
string IEmployee.Name
{
get { return "Employee Name"; }
set { }
}
implementa la propiedad Name en la interfaz IEmployee, mientras que la declaracin:
string ICitizen.Name
{
get { return "Citizen Name"; }
set { }
}
implementa la propiedad Name en la interfaz ICitizen.
interface IEmployee
{
string Name
{
get;
set;
}
int Counter
{
get;
}
}
public class Employee : IEmployee
{
public static int numberOfEmployees;
private string name;
public string Name // read-write instance property
{
get
{
return name;
}
set
{
name = value;
}
}
private int counter;
public int Counter // read-only instance property
{
get
72
{
return counter;
}
}
public Employee() // constructor
{
counter = ++counter + numberOfEmployees;
}
}
class TestEmployee
{
static void Main()
{
System.Console.Write("Enter number of employees: ");
Employee.numberOfEmployees = int.Parse(System.Console.ReadLine());
Employee e1 = new Employee();
System.Console.Write("Enter the name of the new employee: ");
e1.Name = System.Console.ReadLine();
System.Console.WriteLine("The employee information:");
System.Console.WriteLine("Employee number: {0}", e1.Counter);
System.Console.WriteLine("Employee name: {0}", e1.Name);
}
}
Indizadores en interfaces
Los descriptores de acceso de los indizadores de interfaz se diferencian de los
descriptores de acceso de los indizadores de clase en los siguientes aspectos:
Los descriptores de acceso de interfaz no utilizan modificadores.
Un identificador de acceso de interfaz no tiene cuerpo.
73
La firma de un indizador debe ser diferente de las firmas de los dems indizadores
declarados en la misma interfaz.
Ejemplo
En el ejemplo siguiente se muestra cmo se implementan indizadores de interfaz:
// Indexer on an interface:
public interface ISomeInterface
{
// Indexer declaration:
int this[int index]
{
get;
set;
}
}
// Implementing the interface.
class IndexerClass : ISomeInterface
{
private int[] arr = new int[100];
public int this[int index] // indexer declaration
{
get
{
// Check the index limits.
if (index < 0 || index >= 100)
{
return 0;
}
else
{
return arr[index];
}
}
set
{
if (!(index < 0 || index >= 100))
{
arr[index] = value;
}
}
}
}
class MainClass
{
static void Main()
{
IndexerClass test = new IndexerClass();
74
75
VII Excepciones
7.1 Definicin
7.1.1 Que son las excepciones
Las caractersticas de control de excepciones del lenguaje C# proporcionan una manera
de afrontar cualquier situacin inesperada o excepcional que se presente mientras se
ejecuta un programa. El control de excepciones utiliza las palabras clave try, catch y
finally para intentar acciones que podran no realizarse correctamente, controlar errores y
limpiar los recursos despus. Common Language Runtime (CLR), las bibliotecas de otro
fabricante o el cdigo de aplicacin que utiliza la palabra clave throw pueden generar
excepciones.
En este ejemplo, el mtodo hace una prueba para realizar una divisin por cero y detecta
el error. Sin el control de excepciones, este programa finalizara con un error
DivideByZeroException no controlado.
int SafeDivision(int x, int y)
{
try
{
return (x / y);
}
catch (System.DivideByZeroException dbz)
76
{
System.Console.WriteLine("Division by zero attempted!"); return 0;
}
}
Informacin general sobre excepciones
Las excepciones tienen las propiedades siguientes:
Cuando la aplicacin encuentra una circunstancia excepcional, como una
Excepcin
Descripcin
ArithmeticException
IndexOutOfRangeException
77
NullReferenceException
OutOfMemoryException
OverflowException
StackOverflowException
TypeInitializationException
7.1.3 Propagacin
La instruccin throw (throw-statement) inicia una excepcin.
throw-statement:
throw expressionopt ;
Una instruccin throw con expresin inicia el valor resultante de evaluar la expresin. La
expresin debe denotar un valor del tipo de clase System.Exception o de un tipo de clase
que derive de System.Exception. Si la expresin evaluada devuelve null, se inicia
entonces System.NullReferenceException.
Una instruccin throw sin expresin slo se puede utilizar en un bloque catch, en cuyo
caso esta instruccin volver a iniciar la excepcin que est controlando en ese momento
el bloque catch.
Como una instruccin throw transfiere incondicionalmente el control a otra parte del
cdigo, el punto final de una instruccin throw nunca es alcanzable.
Cuando se inicia una excepcin, el control se transfiere a la primera clusula catch de una
instruccin try envolvente que pueda controlar la excepcin. El proceso que tiene lugar
desde el punto de inicio de la excepcin hasta el punto en que se transfiere el control a un
controlador de excepciones adecuado es conocido con el nombre de propagacin de
excepcin. La propagacin de una excepcin consiste en evaluar repetidamente los
78
siguientes pasos hasta encontrar una clusula catch que coincida con la excepcin. En
esta descripcin, el punto de inicio es la ubicacin desde la que se inicia la excepcin.
79
Las excepciones en C# las podemos controlar usando las instrucciones try / catch / finally.
Estas instrucciones realmente son bloques de instrucciones, y por tanto estarn
delimitadas con un par de llaves.
Cuando queramos controlar una parte del cdigo que puede producir un error lo incluimos
dentro del bloque try, si se produce un error, ste lo podemos detectar en el bloque catch,
por ltimo, independientemente de que se produzca o no una excepcin, podemos
ejecutar el cdigo que incluyamos en el bloque finally.
Cuando creamos una estructura de control de excepciones no estamos obligados a usar
los tres bloques, aunque el primero: try si es necesario, ya que es el que le indica al
compilador que tenemos intencin de controlar los errores que se produzcan. Por tanto
podemos crear un "manejador" de excepciones usando los tres bloques, usando try y
catch o usando try y finally.
Veamos ahora con ms detalle cada uno de estos bloques y que es lo que podemos
hacer en cada uno de ellos.
Bloque try
En este bloque incluiremos el cdigo en el que queremos comprobar los errores. El cdigo
a usar ser un cdigo normal, es decir, no tenemos que hacer nada en especial, ya que
en el momento que se produzca el error se usar (si hay) el cdigo del bloque catch.
Bloque catch
Si se produce una excepcin, sta la capturamos en un bloque catch.
En el bloque catch podemos indicar que tipo de excepcin queremos capturar, para ello
usaremos una variable de tipo Exception, la cual puede ser del tipo de error especfico
que queremos controlar o de un tipo genrico.
Por ejemplo, si sabemos que nuestro cdigo puede producir un error al trabajar con
ficheros, podemos usar un cdigo como ste:
Nota
try
{
// cdigo para trabajar con ficheros, etc.
}
catch(System.IO.IOException ex)
{
// el cdigo a ejecutar cuando se produzca ese error
}
Si nuestra intencin es capturar todos los errores que se produzcan, es decir, no
queremos hacer un filtro con errores especficos, podemos usar la clase Exception como
tipo de excepcin a capturar. La clase Exception es la ms genrica de todas las clases
para manejo de excepciones, por tanto capturar todas las excepciones que se
produzcan.
Nota
80
try
{
// cdigo que queremos controlar
}
catch(System.Exception ex)
{
// el cdigo a ejecutar cuando se produzca cualquier error
}
Aunque si no vamos usar la variable indicada en el bloque Catch, pero queremos que no
se detenga la aplicacin cuando se produzca un error, podemos hacerlo de esta forma:
Nota
try
{
// cdigo que queremos controlar
}
catch
{
// el cdigo a ejecutar cuando se produzca cualquier error
}
La variable indicada en el bloque catch la podemos usar para mostrar un mensaje al
usuario o para obtener informacin extra sobre el error, pero no siempre vamos a hacer
uso de esa variable, en ese caso podemos utilizar el cdigo anterior, en el que no se usa
una variable y tampoco se indica el tipo de error que queremos interceptar. Pero es
posible que nuestra intencin sea capturar errores de un tipo concreto sin necesidad de
utilizar una variable, en ese caso podemos crear un bloque catch como el siguiente, en el
que solo se indica el tipo de excepcin:
Nota
try
{
// cdigo que queremos controlar
}
catch(FormatException)
{
// interceptar los errores del tipo FormatException
}
Varias capturas de errores en un mismo bloque try/catch
En un mismo try/catch podemos capturar diferentes tipos de errores, para ello podemos
incluir varios bloques catch, cada uno de ellos con un tipo de excepcin diferente.
Es importante tener en cuenta que cuando se produce un error y usamos varios bloques
catch, el CLR de .NET buscar la captura que mejor se adapte al error que se ha
producido, pero siempre lo har examinando los diferentes bloques catch que hayamos
indicado empezando por el indicado despus del bloque try, por tanto deberamos poner
las ms genricas al final, de forma que siempre nos aseguremos de que las capturas de
81
Nota
int i, j;
//
try
{
Console.Write("Un numero ");
i = Convert.ToInt32(Console.ReadLine());
Console.Write("Otro numero ");
j = Convert.ToInt32(Console.ReadLine());
int r = i / j;
Console.WriteLine("El resultado es: {0}", r);
}
catch (FormatException)
{
Console.WriteLine("No es un nmero vlido");
// Salimos de la funcin, pero se ejecutar el finally
return;
}
catch (DivideByZeroException)
{
82
83
file = fileInfo.OpenWrite();
file.WriteByte(0xF);
file.Close();
}
Ejemplo
Para convertir el cdigo anterior en una instruccin try-catch-finally, el cdigo de limpieza
est separado del cdigo activo como se muestra a continuacin.
static void CodeWithCleanup()
{
System.IO.FileStream file = null;
System.IO.FileInfo fileInfo = null;
try
{
fileInfo = new System.IO.FileInfo("C:\\file.txt");
file = fileInfo.OpenWrite();
file.WriteByte(0xF);
}
catch(System.Exception e)
{
System.Console.WriteLine(e.Message);
}
finally
{
if (file != null)
{
file.Close();
}
}
}
Como puede producirse una excepcin en cualquier momento dentro del bloque try antes
de la llamada a OpenWrite() o la propia llamada a OpenWrite() podra producir un error,
no se garantiza que el archivo est abierto cuando se intenta cerrarlo. El bloque finally
agrega una comprobacin para asegurarse de que el objeto FileStream no es null antes
de llamar al mtodo Close. Sin la comprobacin de null, el bloque finally podra iniciar su
propia excepcin NullReferenceException, pero se debera evitar producir excepciones en
bloques finally si es posible.
Una conexin de base de datos tambin es un elemento que debera cerrarse en un
bloque finally. Dado que el nmero de conexiones permitido a un servidor de base de
datos est limitado a veces, es importante cerrar las conexiones de base de datos tan
rpido como sea posible. Si se produce una excepcin antes de poder cerrar la conexin,
se trata de otro caso en el que es preferible utilizar el bloque finally a esperar a la
recoleccin de elementos no utilizados.
84
secuencia a una estructura de datos, como, por ejemplo, una matriz de bytes.
Segn el origen de datos o repositorio subyacente, las secuencias pueden admitir slo
algunas de estas caractersticas. Por ejemplo, NetworkStreams no admite operaciones de
85
86
StringWriter escribe los caracteres en Strings. StringWriter permite tratar Strings con la
misma API, de modo que la salida puede ser una Stream en cualquier codificacin o una
String.
TextReader es la clase base abstracta para StreamReader y StringReader. Mientras que
las implementaciones de la clase abstracta Stream estn diseadas para la entrada y
salida de bytes, las de TextReader estn diseadas para la entrada de caracteres
Unicode.
TextWriter es la clase base abstracta para StreamWriter y StringWriter. Mientras que las
implementaciones de la clase abstracta Stream estn diseadas para la entrada y salida
de bytes, las de TextWriter estn diseadas para la salida de caracteres Unicode.
Clases comunes de secuencias de E/S
Una BufferedStream es una Stream que agrega almacenamiento en bfer a otra Stream,
por ejemplo una NetworkStream. FileStream tiene almacenamiento en bfer internamente,
y MemoryStream no necesita almacenamiento en bfer. BufferedStream se puede
componer en torno a ciertos tipos de secuencias para mejorar el rendimiento de lectura y
escritura. Un bfer es un bloque de bytes de la memoria utilizado para almacenar datos
en la memoria cach y, de este modo, reducir el nmero de llamadas al sistema operativo.
Una CryptoStream vincula secuencias de datos a transformaciones criptogrficas. Aunque
CryptoStream deriva de Stream, no forma parte del espacio de nombres System.IO, sino
del espacio de nombres System.Security.Cryptography.
Una MemoryStream es una secuencia no almacenada en bfer cuyos datos encapsulados
son accesibles directamente en la memoria. Esta secuencia no tiene almacn de respaldo
y puede resultar til como bfer temporal.
Una NetworkStream representa una Stream a travs de una conexin de red. Aunque
NetworkStream deriva de Stream, no forma parte del espacio de nombres System.IO, sino
de System.Net.Sockets.
E/S y seguridad
Cuando se utilizan las clases del espacio de nombres System.IO se deben satisfacer
requisitos de seguridad del sistema operativo como las listas de control de acceso (ACL)
para que se permita el acceso. Este requisito es adicional a cualquier requisito
FileIOPermission.
Precaucin La directiva de seguridad predeterminada de Internet y de una intranet no
permite el acceso a archivos. Por ello, no use las clases de E/S de almacenamiento no
aislado normales al escribir cdigo que se vaya a descargar a travs de Internet. En su
lugar, utilice Almacenamiento aislado.
Precaucin Al abrir un archivo o una secuencia de red, slo se realiza una comprobacin
de seguridad cuando se construye la secuencia. Por lo tanto, se debe tener cuidado al
entregar estas secuencias a dominios de aplicaciones o cdigo que no sean de confianza.
8.2 Operaciones bsicas en archivos texto y binario
8.2.1 Crear y 8.2.2 Abrir.
Los ejemplos de cdigo siguientes muestran cmo escribir texto en un archivo de texto.
87
El primer ejemplo muestra cmo agregar texto a un archivo existente. El segundo ejemplo
indica cmo crear un nuevo archivo de texto y escribir una cadena en l. Los mtodos
WriteAllText pueden proporcionar una funcionalidad parecida.
Ejemplo 1:
using System;
using System.IO;
class Test
{
public static void Main()
{
// Create an instance of StreamWriter to write text to a file.
// The using statement also closes the StreamWriter.
using (StreamWriter sw = new StreamWriter("TestFile.txt"))
{
// Add some text to the file.
sw.Write("This is the ");
sw.WriteLine("header for the file.");
sw.WriteLine("-------------------");
// Arbitrary objects can also be written to the file.
sw.Write("The date is: ");
sw.WriteLine(DateTime.Now);
}
}
}
Ejemplo 2:
using System;
using System.IO;
public class TextToFile
{
private const string FILE_NAME = "MyFile.txt";
public static void Main(String[] args)
{
if (File.Exists(FILE_NAME))
{
Console.WriteLine("{0} already exists.", FILE_NAME);
return;
}
using (StreamWriter sw = File.CreateText(FILE_NAME))
{
sw.WriteLine ("This is my file.");
sw.WriteLine ("I can write ints {0} or floats {1}, and so on.", 1, 4.2);
sw.Close();
}
}
}
88
89
}
using (StreamReader sr = File.OpenText(FILE_NAME))
{
String input;
while ((input=sr.ReadLine())!=null)
{
Console.WriteLine(input);
}
Console.WriteLine ("The end of the stream has been reached.");
sr.Close();
}
}
Binario
8.2.4 Lectura y escritura, 8.2.5 Recorrer y 8.2.3 Cerrar
Las clases BinaryWriter y BinaryReader se usan para escribir y leer datos, en lugar de
cadenas de caracteres. En el siguiente ejemplo de cdigo se muestra cmo se escriben y
se leen datos en una nueva secuencia de archivos vaca (Test.data). Despus de crear el
archivo de datos en el directorio actual, se crean las clases BinaryWriter y BinaryReader
asociadas, y BinaryWriter se usa para escribir los enteros de 0 a 10 en Test.data, que
deja el puntero de archivo al final del archivo. Despus de volver a establecer el puntero
de archivo en el origen, BinaryReader lee el contenido especificado.
using System;
using System.IO;
class MyStream
{
private const string FILE_NAME = "Test.data";
public static void Main(String[] args)
{
// Create the new, empty data file.
if (File.Exists(FILE_NAME))
{
Console.WriteLine("{0} already exists!", FILE_NAME);
return;
}
FileStream fs = new FileStream(FILE_NAME, FileMode.CreateNew);
// Create the writer for data.
BinaryWriter w = new BinaryWriter(fs);
// Write data to Test.data.
for (int i = 0; i < 11; i++)
{
w.Write( (int) i);
}
w.Close();
fs.Close();
// Create the reader for data.
fs = new FileStream(FILE_NAME, FileMode.Open, FileAccess.Read);
BinaryReader r = new BinaryReader(fs);
// Read data from Test.data.
90
Bibliografa
Titulo: C# Manual de programacin
Autor: Joyanes Fernandez
Editorial: McGraw Hill
Titulo: Microsoft C# Lenguaje y aplicaciones
Autor: Francisco Javier Ceballos
Editorial: Ra-ma
WWW.MICROSOFT.COM.MX
91