SlideShare una empresa de Scribd logo
1 de 37
Descargar para leer sin conexión
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
Tutorial Csharp
Variables y Constantes
Una variable o una constante representan un posición de memoria ocupada por un tipo de
dato. Una varible puede ser local, el parámetro de un método, el elemento de un array, un
campo de una instancia de un objeto o un campo estático de un objeto, y su valor puede ser
modificado, en cambio, el valor de una constante siempre es el mismo.
string saludo = "hola";
const double pi = 3.1415;
Dado que C# es fuertemente tipificado todas las variables y constantes tienen asociado un
tipo que define los posibles valores que puede tomar.
En C# a todas las variables y constantes se les debe asignar un valor antes de poder utilizarlas.
Esta asignación de valor puede ser tanto explícita como automática a través de la asignación
del valor por defecto para un tipo. Estos son los valores por defecto para los diferentes tipos:
Tipo Valor por defecto
tipos numéricos 0
bool false
char '0'
enumeraciones 0
referencias null
Cuando intentamos utilizar una variable sin asignarle un valor se producirá un error como
sucede con el siguiente ejemplo:
// variable.cs
using System;
public class Variable
{
int v;
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
public Variable() {} // v = valor por
defecto
public Variable(int a) { v = a; } // v = a
static void Main()
{
Variable[] variable = new Variable[2]; // declaramos un array
Console.WriteLine(variable[1]); // ok, valor por defecto
Variable v;
console.WriteLine(v); // error, v sin asignar
}
}
Espacios de nombres
En C# se podemos utilizar espacios de nombres para agrupar de forma lógica ciertas
porciones de código de forma que se les asocia un nombre para su uso. Si no utilizamos
explícitamente ningún espacio de nombres estaremos utilizando el espacio de nombres
global, como se hace en el primer ejemplo holamundo.cs. Veamos ahora como utilizar
explícitamente el espacio de nombres System en holamundo2.cs de forma que no tengamos
que escribir System. cada vez que nos queramos referir a alguna variable, clase, ... que esté
definida en su interior. Para ello deberemos emplear using.
// holamundo2.cs
using System; // espacio de nombres que usaremos
public class HolaMundo2
{
public static void Main()
{
Console.WriteLine("¡Hola, Mundo!");
}
}
Para definir un espacio de nombres deberemos utilizar la palabra namespace. En el siguiente
ejemplo se definen dos clases llamadas Prueba en dos espacios de nombres diferentes. Los
nombres completos de estas clases serán Espacio1.Prueba y Espacio2.Prueba. Para poder
utilizarlos empleando solamente Prueba deberemos especificar en que espacio de nombres
está dicha clase utilizando previamente using.
// espacios.cs
using System; // usaremos el espacio de nombres System
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
namespace Espacio1 // declaración del espacio de nombres
Espacio1
{
public class Prueba
{
public Prueba()
{
Console.WriteLine("Espacio1.Prueba");
}
}
}
namespace Espacio2 // declaración del espacio de nombres Espacio2
{
public class Prueba
{
public Prueba()
{
Console.WriteLine("Espacio2.Prueba");
}
}
}
using Espacio2; // usaremos el espacio de nombres Espacio2
public class Namespace
{
public static void Main()
{
Prueba p = new Prueba();
}
}
Espacios de nombres anidados
Los espacios de nombres pueden anidarse, es decir, definirse dentro de otros espacios de
nombres. Para ello no tendremos más que encerrara la declaración de un espacio de nombres
dentro de la de otro espacio de nombres. Para referirnos a las declaraciones del espacio
interior habremos de utilizar la clausula using seguida de todos los espacios de nombres
unidos mediante un punto o referirnos a un tipo empleando su nombre completo.
// anidado.cs
using System;
namespace Exterior
{
namespace Interior
{
class Hola
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
{
public Hola() { Console.WriteLine("¡Hola!"); }
}
}
}
using Exterior.Interior;
class EspacioNombresAnidado
{
public static void Main()
{
Hola hola = new Hola();
// alternativamente se podría haber utilizado:
// Exterior.Interior.Hola hola = new Exterior.Interior.Hola();
}
}
Alias
En C# se pueden crear alias de tipos y espacios de nombres, con lo que podremos referirnos
a ciertos tipos y espacios de nombres utilizando otro nombre distinto al que tienen en su
declaración.
// alias.cs
using sys = System; // alias de espacio de nombres
using cadena = System.String; // alias de tipo
class Alias
{
public static void Main()
{
cadena c = "¡Hola, mundo!";
sys.Console.WriteLine(c); // ¡hola, mundo!
sys.Console.WriteLine(c.GetType()); // System.String
}
}
Identificadores y palabras clave
Los identificadores son los nombre que elegimos para nuestros variables, clases, etc. Un
identificador debe ser una palabra completa compuesta de caracteres unicode y que comience
por una letra o un guión bajo (_) y que no sea igual que una palabra clave del lenguaje. Como
un caso especial podremos utilizar @ como prefijo de un identificador si queremos que este
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
se llame igual que una palabra reservada por el lenguaje, pero sin que
se considere parte de él. Así las variables x y @x son iguales. Las letras mayúsculas y
minúsculas crean identificadores diferentes.
Las palabras clave de C# son:
abstract event new struct as explicit null switch
base extern object this bool false operator throw
break finally out true byte fixed override try
case float params typeof catch for private uint
char foreach protected ulong checked goto public unchecked
class if readonly unsafe const implicit ref ushort
continue in return using decimal int byte virtual
default interface sealed volatile delegate internal short void
do is sizeof while double lock stackalloc else
long static enum namespace string
Tipos predefinidos
Los tipos predefinidos en C# son alias de tipos en el espacio de nombres System. Aquí
podemos ver la lista completa de los mismos:
Tipo C# Clase System
Bool System.Boolean
Byte System.Byte
Sbyte System.SByte
Char System.Char
Decimal System.Decimal
Doublé System.Double
Tipo C# Clase System
int System.Int32
uint System.UInt32
long System.Int64
ulong System.UInt64
object System.Object
short System.Short
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
Float System.Single ushort System.UShort
string System.String
A todos estos tipos, salvo object y string, se les denomina tipos simples. Todos los tipos y
sus alias pueden utilizarse indistintamente. De esta forma podemos declarar un entero
utilizando tanto int como System.Int32:
int x = 123;
System.Int32 x = 123;
Para mostrar el nombre de cualquier tipo C# podemos utilizar el método GetType() o el
operador typedef.
Console.WriteLine(x.GetType());
Tipos valor y tipos referencia
Todos los tipos en C# pertenecen a una de las siguientes tres categorías, cuya diferencia
fundamental entre estas tres categorias es la forma en que son tratados en memoria.
 Tipos valor: enum, struct
 Tipos referencia: array, class, delegate, interface
 Tipo puntero
Tipos valor
Estos tipos son los más sencillos de comprender. Directamente contienen los datos, por
ejemplo, un tipo int contiene su valor, o un tipo bool vale true o false. Una de sus
características es que cuando se asignan el valor de una variable a otra, se crea una copia de
dicho valor.
// valor.cs
using System;
class Valor
{
static void Main()
{
int x = 3;
int y = x; // y es una copia de x
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
++x; // incrementa x a 4
Console.WriteLine("x = {0} y = {1}", x, y);
}
}
Este ejemplo crea dos variables de tipo int, x e y. Inicialmente x vale 3 e y pasa a ser una
copia de x. Al incrementar el valor de x, el valor de y no cambia puesto que ambos valores
son copias independientes en memoria.
Todos los tipos simples y sus combinaciones a través de structs pertenecen a esta categoría.
Tipos referencia
Los tipos referencia son algo más complejos. En un tipo referencia hemos de diferenciar entre
un objeto y una referencia a un objeto. Veamos con un ejemplo cada una de estas partes:
// referencia.cs
using System;
using System.Text;
class Referencia
{
static void Main()
{
StringBuilder x = new StringBuilder("hola");
StringBuilder y = x;
x.Append(", ¿estás aprendiendo mucho?");
Console.WriteLine("x = '{0}' y = '{1}'", x, y);
}
}
En este caso StringBuilder es un tipo referencia, a diferencia de int que era un tipo valor.
Cuando se declara x en el ejemplo anterior, realmente se están haciendo dos cosas a la vez:
StringBuilder x;
x = new StringBuilder("hola");
La primera linea declara x como un referencia a un objeto de tipo StringBuilder. La segunda
crea un objeto de dicho tipo y le asigna a x su valor.
StringBuilder y = x;
Com esta linea también se llevan a cabo dos acciones diferentes: por un lado se crea una
nueva referencia, y, a un objeto de tipo StringBuilder y por otro lado se hace que y apunte al
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
mismo objeto al que x lo hace. Por este motivo al modificar x también
se modifica y. Ambos comparten la misma representación interna de su valor.
Los tipos object y string, asi como cualquier clase definida por nosotros pertenece a esta
categoría de tipos.
Parámetros de la línea de órdenes
A un programa podemos pasarle parámetros a través de su línea de ordenes. La forma de
acceder a ellos es a través de un array de tipo string en la función principal, Main:
// param.cs
using System;
public class Parametros
{
public static void Main(string[] args)
{
// la longitud del array puede obtenerse a través de la propiedad Length
// Length es una propiedad de sólo lectura del array args
Console.WriteLine("Número de parámetros de la línea de órdenes = {0}",
args.Length);
for(int i = 0; i < args.Length; i++)
{
Console.WriteLine("Parámetro[{0}] = [{1}]", i, args[i]);
}
}
}
Este mismo ejemplo podría haberse creado utilizando foreach, que es estructura que permite
crear un bucle sobre una colleción.
// param2.cs
using System;
public class Parametros
{
public static void Main(string[] args)
{
// la longitud del array puede obtenerse a través de la propiedad Length
// Length es una propiedad de sólo lectura del array args
Console.WriteLine("Número de parámetros de la línea de órdenes = {0}",
args.Length);
foreach(string s in args)
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
{
Console.WriteLine(s);
}
}
}
Arrays
Un array es una colección de objetos que se almacenan de forma consecutiva en un bloque
de memoria. Para crear uno hemos de especificar el tipo de los elementos junto a [] y el
nombre que deseemos darle. A continuación, y de forma opcional, podemos crearlo e
inicializarlo. Veamos un ejemplo:
char[] vocales = new char[5] {'a', 'e', 'i', 'o', 'u'}
Esta línea declara un array de 5 elementos de tipo char y después lo inicializa con 5 valores.
Para acceder a cada uno de los elementos del array utilizaremos el operador [] y el número
de posición al que deseamos acceder, teniendo en cuenta que los elementos se empiezan a
numerar desde 0.
Console.WriteLine(vocales[2]); // imprime una "i"
Una vez creado un array no puede modificar su longitud. Para conocer esta se puede utilizar
la propiedad de sólo lectura Lenght. Existe un conjunto de colecciones mucho más complejas
y versátiles dentro de System.Collection.
Arrays multidimensionales
Los arrays pueden tener más de una dimensión y entonces se clasifican en dos grupos:
rectangulares y dentados. Los arrays rectangulares tienen una estructura multidimensional
rectangular en la que cada dimensión posee siempre un mismo número de elementos. En
cambio en los arrays dentados, lo que hay es un array de arrays, con lo cual cada subarray
puede tener un tamaño diferente.
// array rectagular
int[,,] matriz1 = new int[3, 4, 5]; // cubo 3x4x5
// array dentado
int[][][] matriz2 = new int[3][][]; // cubo 3x_x_
for (int i = 0; i < 3; ++i)
{
matriz2[i] = new int[4][];
for (int j = 0; j < 4; ++j)
matriz2[i][j] = new int[5];
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
}
// acceso a un elemento
matriz1[1,1,1] = matriz2[1][1][1] = 7;
Para conocer el número de elementos de cada dimensión en los arrays multidimensionales
rectangulared tendremos que utilizar el método GetLength(n), donde n es el número de
dimensión cuyo tamaño deseamos conocer, también indexado desde 0. Para los arrays
dentados en cambio, deberemos consultar el tamaño de cada subarray uno por uno.
// getlenght.cs
using System;
public class Lenght
{
public static void Main()
{
// array rectagular
int[,,] cubo = new int[3, 4, 5];
// array dentado
int[][][] cosa = new int[3][][]; //
for (int i = 0; i < cosa.Length; ++i)
{
cosa[i] = new int[i + 1][];
for (int j = 0; j < cosa[i].Length; ++j)
cosa[i][j] = new int[i + j + 1];
}
// imprime el tamaño de cada dimensión
for(int i = 0; i < 3; ++i)
Console.WriteLine("cubo.GetLength({0}) = {1}",
i, cubo.GetLength(i));
Console.WriteLine("cosa.Length = {0}", cosa.Length);
for(int i = 0; i < cosa.Length; ++i)
{
Console.WriteLine("cosa[{0}].Length = {1}",
i, cosa[i].Length);
for (int j = 0; j < cosa[i].Length; ++j)
Console.WriteLine("cosa[{0}][{1}].Length = {2}",
i, j, cosa[i][j].Length);
}
}
}
Inicialización de arrays
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
Para inicializar un array hemos de añadir una lista de elementos entre
llaves, {}, y separados por comas.
int[] numeros = new int[10] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int[,] array2x2 = new int[2,2] {{11, 12}, {21, 22}};
int[][] array2xn = new int[2][] {new int[] {11, 12}, new int[] {21, 22,
23}};
Algunos partes de esta sintaxis de inicialización pueden omitirse, de forma que las siguientes
declaraciones son completamente equivalentes a las anteriores:
int[] numeros = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int[,] array2x2 = {{11, 12}, {21, 22}};
int[][] array2xn = {new int[] {11, 12}, new int[] {21, 22, 23}};
Paso de parámetros
Paso de parámetros por valor
Por defecto en C# los parámetros son pasados por valor, lo que implica crear una copia de
una variable para poder pasársela a un método.
// pasovalor.cs
using System;
public class PasoValor
{
static void Prueba(int i)
{
Console.WriteLine("i = {0}", ++i);
}
static void Main()
{
int x = 7;
Prueba(x); // la función recibe una copia de x
Console.WriteLine("x = {0}", x); // x sigue siendo 7
}
}
Paso de parámetros por referencia
Si por algún motivo se necesita pasar una variable por referencia puede hacerse sin más que
anteponer la palabra clave ref delante de la variabel correspondiente en la lista de parámetros
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
de un método, tanto a la hora de definir el método como a la de
utilizarlo. El paso de parámetros por referencia es fundamental cuando queremos modificar
el valor de una variable o para hacer más eficiente el paso de grandes estructura de datos a
un método.
// ref.cs
using System;
public class PasoRef
{
static void Prueba(ref int i)
{
Console.WriteLine("i = {0}", ++i);
}
static void Main()
{
int x = 7;
Prueba(ref x); // la función recibe una referencia de x
Console.WriteLine("x = {0}", x); // x sigue cambia a 8
}
}
El modificador out
Siguiendo con la línea de asegurar que una variable es asignada antes de utilizarse que C#
promueve, out es un modificador que nos obliga a asignar un valor a una variable antes de
finalizar un método.
// out.cs
using System;
public class PasoOut
{
static void Separa(string entrada, out string nombre, out string
apellido)
{
int i = entrada.LastIndexOf(' ');
nombre = entrada.Substring(0, i);
apellido = entrada.Substring(i + 1);
}
static void Main()
{
string nombre, apellido;
Separa("José Pérez", out nombre, out apellido);
Console.WriteLine("Nombre: {0} Apellido: {1}", nombre, apellido);
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
}
}
El modificador params
El modificador de parámetros params puede utilizarse en el último parámetro de cualquier
método para indicar que dicho método acepta cualquier número de parámetros de ese tipo
particular. De esta forma se pueden crear métodos con un número variable de parámetros.
// params.cs
using System;
public class Params
{
static int Suma(params int[] n)
{
int total = 0;
foreach(int i in n)
total += i;
return total;
}
static void Main()
{
int s = Suma(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
Console.WriteLine("0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 = {0}", s);
}
}
Clases
En C# un programa se crea mediante la definición de nuevos tipos. De hecho, en C# todos
los tipos son clases. Cada nuevo tipo estará formado por un conjunto de datos y funciones.
Veamos un ejemplo:
// clase.cs
using System;
// declaración de la clase
class Persona
{
// una variable que contendrá el nombre
string nombre;
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
// constructor: como inicializar un objeto de clase
Persona
public Persona(string nombre)
{
this.nombre = nombre; // this: una forma de acceder a este objeto
}
// propiedad: una forma de acceder al nombre de una persona
public string Nombre
{
get { return nombre; }
set { nombre = value; } // variable especial value
}
public static void Main()
{
Persona p = new Persona("Adán");
Console.WriteLine("p.Nombre = {0}", p.Nombre);
p.Nombre = "Eva";
Console.WriteLine("p.Nombre = {0}", p.Nombre);
}
}
La palabra clave this
Esta palabra clave, this, nos permite referirnos a cualquier variable o método de la instancia
de una clase en la que nos encontremos. También nos permite llamar a un construtor
sobrecargado, y declarar o acceder a un indexador. Un uso muy común de la misma es
distinguir entre un campo de una instancia de un objeto y un parámetro.
public Persona(string nombre)
{
this.nombre = nombre;
}
Campos
Los campos de una clase son los datos que esta contiene. En su forma más sencilla pueden
ser una simple declaración de variable como:
string nombre;
que cada instancia de una clase contendrá.
Podemos utilizar los modificadores static y readonly para alterar el comportamiento de un
campo.
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
A los campos no estáticos (por defecto) se les denomina variables de
instancia y los campos estáticos variables de clase. Mediante el uso explícito de la palabra
static hacemos que de una variable pase a haber una única copia compartida por todas las
instancias de una clase.
// static.cs
using System;
class Persona
{
static int contador;
int id;
public Persona() { id = contador++; }
~Persona() { contador--; }
public int Contador
{
get { return contador; }
}
public int Id
{
get { return id; }
}
static void Main()
{
Persona p1 = new Persona();
Persona p2 = new Persona();
Console.WriteLine("Hay {0} personas", p1.Contador);
Console.WriteLine("p2.Id() = {0}", p2.Id);
}
}
El modificador readonly nos permite evitar que una variable sea modificada una vez que sea
asignada. Al igual que una constante posee un valor invariable, pero este se calcula en tiempo
de ejecución en vez de en tiempo de compilación. Las constantes tienen la ventaja de permitir
realizar un mayor número de optimizaciones sobre ellas. En cambio las variables readonly,
nos aportan un mayor grado de flexibilidad, pues pueden retrasar el calcular su valor hasta la
ejecución del programa. Esto puede aportar ventajas a la hora de modificar su valor sin tener
que recompilar el código para que el nuevo valor surta efecto, como a la hora de corregir un
valor erróneo o simplemente actualizarlo.
Propiedades
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
Las son otros de los campos que pueden componer un objeto. Su
función es controlar la forma en que se accede a los datos de un objeto escondiendo la
representanción interna de los mismos. Las propiedades puede permitirnos acceder a un
campo de un objeto de tres formas:
 get: sólo lectura.
 set: sólo escritura.
 get y set: lectura y escritura.
// propiedades.cs
using System;
class Persona
{
int nacimiento; // año de nacimiento
public Persona(int nacimiento) { this.nacimiento = nacimiento; }
public int Edad
{
get { return DateTime.Now.Year - nacimiento; }
set { nacimiento = DateTime.Now.Year - value; }
}
static void Main()
{
Persona gustavo = new Persona(1973);
Console.WriteLine("Gustavo tiene {0} años,", gustavo.Edad);
gustavo.Edad = 31;
Console.WriteLine("y el año que viene tendrá {0}", gustavo.Edad);
}
}
Indexadores
Los indexadores son una forma cómoda de acceder a una colección de objetos contenida
dentro de una clase a través del uso de la sintaxis de los arrays. Al igual que las propiedades,
permiten acceder a datos contenidos en un objeto, pero en vez de hacerlo a través de un
nombre, lo hacen a través de un índice. Su forma de utilización también es similar.
// indexador.cs
using System;
class Nota
{
float[] notas;
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
public Nota(int alumnos)
{
notas = new float[alumnos];
}
public float this[int indice]
{
get { return notas[indice]; }
set { notas[indice] = value; }
}
public int Length
{
get { return notas.Length; }
}
public float Media
{
get
{
float suma = 0;
foreach(float nota in notas)
{
suma += nota;
}
return suma / notas.Length;
}
}
static void Main()
{
Nota n = new Nota(100);
Random rand = new Random();
for (int i = 0; i < n.Length; ++i)
{
n[i] = 5 + rand.Next(6);
Console.Write("{0}, ", n[i]);
}
Console.WriteLine();
Console.WriteLine("La nota media es: {0}", n.Media);
}
}
Métodos
Un método es un función o procedimiento definida en el interior de una clase. En C# todo el
código se ejecuta como un método de alguna clase, pues todos los tipos que podemos usar
son clases, e incluso, la función Main, es en realidad un método de alguna clase.
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
Todo método tiene una firma (signature), que es el conjunto de tipos
y modificadores de cada uno de los parámetros de su lista de parámetros.
Dentro de una clase podemos tener diferentes métodos aunque tengan el mismo nombre. A
esto se lo denomina sobrecarga de métodos. Podremos utilizar la sobrecarga siempre que la
firma de los métodos que intentemos sobrecargar sea diferente, es decir, sus parámetros no
tenga idénticos tipos y modificadores. Para la sobrecarga no se tiene en cuenta el tipo de
retorno ni el modificador params.
Este conjunto de métodos pueden darse a la vez en una clase:
float Media(float a, float b);
float Media(float a, int b);
float Media(int a, float b);
int Media(int a, int b);
En cambio este otro conjunto métodos no:
int ValorAbsoluto(int a);
float ValorAbsoluto(int a); // error
Constructores
Los constructores son un tipo especial de métodos que poseen las clases y cuya finalidad es
inicializar los campos de un objeto. Cada vez que se crea una nueva instancia de un objeto,
el sistema le asigna la cantidad de espacio que necesite en el montículo ("heap") y acto
seguido ejecuta el constructor de la clase para llevar a cabo la inicialización de todas los
campos que lo requieran. A diferencia de otros métodos el constuctor no puede tener tipo de
retorno ni tener otro nombre diferente del de la propia clase en que se define.
class Persona
{
public Persona(... lista de parámetros ...)
{
... código de inicialización ...
}
}
Los constructores pueden sobrecargarse, de forma que podemos tener varios de ellos y hacer
que antes de ejecutar el cuerpo de su método se ejecute otro utilizando this.
class Persona
{
public string nombre;
public Persona(string nombre) { this.nombre = nombre; }
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
public Persona(): this("José Expósito") {}
}
Persona p1 = new Persona();
Persona p2 = new Persona("Antonio Pérez");
En caso de no definir de forma explícita un constructor, se creará uno de forma implícita sin
parámetros que inicializará todas las variables a sus valores por defecto.
Las asignaciones de valores presentes en las propias declaraciones de las variables se
ejecutarán antes que los constructores, y además, en el mismo orden en que aparezcan. Esto
se puede comprobar ejecutando el siguiente ejemplo:
// inicializacion.cs
using System;
class Persona
{
public string nombre = "José Expósito";
public Persona(string nombre)
{
Console.WriteLine("antes del constructor nombre = {0}", this.nombre);
this.nombre = nombre;
Console.WriteLine("tras el constructor nombre = {0}", this.nombre);
}
public static void Main()
{
Persona p = new Persona("Pedro Castillo");
}
}
Estudiemos ahora como afecta el uso de la palabra clave static a la inicialización de una
clase. Si la aplicamos al constructor, al igual que ocurria con la variables, tiene el efecto de
hacer que el código que ejecuta sea compartido por todas las instancias de una clase. Este
tipo de constructores se ejecutan antes de la creación de cualquier instancia de la clase, y por
supuesto, esto sucede una única vez. Cada clase puede poseer un único constructor de este
tipo y no puede tener parámetros. En el caso de las variables estáticas, como sucedía con las
no estáticas, estas se inicializan antes de la llamada al constructor estático. En resumen, el
orden de inicialización es:
1. variables estáticas
2. constructores estáticos
3. variables no estáticas
4. constructores no estáticos
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
Destructores
Los destructores son el equivalente de los constructores pero a la hora de deshacernos de la
instancia de un objeto. Cada vez que el recolector de basura de C# decide eliminar un objeto
de memoria, antes, ejecuta este método. A diferencia de los constructores es único (no puede
se puede sobrecargar) y no podemos decidir cuando es llamado. Su nombre ha de estar
formado por el símbolo ~ seguido del nombre de la clase.
class Persona
{
public Persona( ... parámetros ... ) { ... código del constructor ... }
~Persona() { ... código del constructor ... }
}
Clases anidadas
Una clase anidada es una clase decladara dentro del ámbito de otra. El anidamiento de clases
nos proporciona tres beneficios:
 Una clase anidada puede acceder a cualquier miembro del la clase que lo contiene,
independiemtemente de los modificadores de acceso que este posea.
 Una clase anidada puede ser ocultada, si interesa, mediante el uso de modificadores
de acceso.
 Para acceder a una clase anidada desde fuera de la clase que la engloba habremos de
utilizar el nombre de la clase que la engloba.
// anidada.cs
using System;
class A
{
private int x = 3; // miembro privado (acceso por defecto)
protected internal class Anidada
{
public void Prueba()
{
A a = new A();
Console.WriteLine(a.x); // podemos acceder a miembros privados
}
}
}
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
class B
{
static void Main()
{
A.Anidada anidada = new A.Anidada()
anidada.Prueba();
}
}
Herencia
Una clase puede herendar de otra para extender o particularizar a la clase original. Heredar
de una clase nos permite reutilizar su funcionalidad sin tener que comenzar desde cero. Una
clase sólo puede heredar de otra, pero en cambio no hay límite a número de descendientes
que pueda tener. Todas las clases forman parte de una jerarquía única de clases cuya raiz es
la clase Object. Una jerarquía de clases bien diseñada se caracteriza por generalizar, de forma
razonable, los nombres del espacio de un problema. De esta forma, podriamos tener una
jerarquía de figuras geométricas con la siguiente estructura:
class Figura {}
class Rectangulo: Figura {}
class Cuadrado: Rectangulo {}
class Elipse: Figura {}
class Circulo: Elipse {}
Veamos como podemos utilizar la herencia para reutilizar código y datos de la clase Figura
en las clases Rectangulo y Cuadrado:
// figura.cs
using System;
class Figura // implicitamente hereda de Object
{
float alto, ancho;
public Figura(float alto, float ancho)
{
this.alto = alto;
this.ancho = ancho;
}
public float Alto { get { return alto; } set { alto = value; } }
public float Ancho { get { return ancho; } set { ancho = value; } }
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
public void Mostrar()
{
Console.WriteLine("{0}: {1}x{2}", GetType(), Alto, Ancho);
}
}
class Rectangulo: Figura // hereda de Figura
{
public Rectangulo(float alto, float ancho): base(alto, ancho) {}
}
class Cuadrado: Rectangulo // hereda de Rectangulo
{
public Cuadrado(float lado): base(lado, lado) {}
public float Lado { get { return alto; } set { alto = ancho = value; } }
}
class Prueba
{
public static void Main()
{
Figura f = new Figura(1, 2);
f.Mostrar();
Rectangulo r = new Rectangulo(3, 4);
r.Mostrar();
Console.WriteLine("alto de r = {0}", r.Alto);
Cuadrado c = new Cuadrado(5);
c.Mostrar();
Console.WriteLine("Lado de c = {0}", c.Lado);
}
}
Del anterior ejemplo debemos destacar varios aspectos:
 Aunque no se indique explicitamente, todas las clases heredad de la clase Object.
 Para hacer que una clase herede de otra debemos utilizar ":" (dos puntos) y el nombre
de la clase de la que queremos heredar después de la declaración del nombre de la
clase.
 Se puede utilizar la palabra reservada base para referirnos al constructor de la clase
de la que hemos heredado, de forma parecida a como utilizabamos this para referirnos
al de la propia clase.
 Como podemos ver en el ejemplo anterior, las clases derivadas de Figura, heredan
tanto sus campos como sus métodos.
Conversión de clases
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
Las variables de una clase pueden convertirse a otro tipo del que han
heredado ("upcast") o convertirse en un tipo que ha heredado de él ("downcast"). En caso de
fallar un conversión a un tipo derivado, se lanzará un excepción de tipo
InvalidCastException.
Cuadrado c = new Cuadrado(5);
Figura f = c; // upcast
c = (Cuadrado)f; // downcast
El operador as asiga null a una variable en caso de fallar una conversión a un tipo padre:
c = f as Cuadrado;
El operador is sirve para comprobar cuando un objeto deriva de un cierta clase o implementa
un interfaz. Suele utilizarse antes de realizar una conversión a un tipo derivado.
if (f is Cuadrado)
((Cuadrado)f).Lado = 5;
else
{
f.Alto = 5;
f.Ancho = 5;
}
Polimorfismo
El polimorfismo es la habilidad para relizar una misma operación sobre tipos diferentes
mientras estos compartan una serie de características comunes. Esto se puede conseguir
mediante la herencia o bien implementado un interfaz. Veamos un ejemplo de clase,
Polimorfismo, que utiliza el polimorfismo para realizar un operación sobre diferentes tipos:
class Polimorfismo
{
public static void Mostrar(Figura f)
{
Console.Write("usando polimorfismo para mostrar: ");
f.Mostrar();
}
public static void Main()
{
Figura[] figuras = new Figura[3];
figuras[0] = new Figura(1, 2);
figuras[1] = new Rectangulo(3, 4);
figuras[2] = new Cuadrado(5);
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
foreach (Figura f in figuras)
{
Mostrar(f);
}
}
}
Métodos virtuales
Un aspecto clave del polimorfismo es la capacidad de cada tipo para relizar una acción de
una forma particular. Las clases base pueden tener métodos virtules que permitan a las clases
derivadas proporcionar su propia implementación de un método. En la clase base hemos de
utilizar la palabra clave virtual en el método que deseemos particularizar en una clase
derivada. Después, en la clase derivada tendremos que utilizar override para indicar que
vamos a proporcionar una nueva implementación de un método. Utilizando el mismo ejemplo
anterior, ahora implementaremos los métodos que nos muestren la fórmula para calcular el
área de una Elipse y un Circulo:
class Elipse: Figura
{
...
public virtual string FormulaArea()
{
return "RadioMayor * RadioMenor * PI";
}
...
}
class Cuadrado: Elipse
{
...
public override string FormulaArea()
{
return "Radio^2 * PI";
}
...
}
Clases y métodos abstractos
Un método abstracto es un método sin implementación. Implicitamente es un método virtual
que estamos obligados a sobrecargar en una clase derivada. Estos métodos sólo pueden
aparecer en un clase abstracta. En ambos casos hemos de utilizar la palabra clave abstract
para hacer abstracto un método o una clase. Las clases abstracta no pueden ser instanciadas,
ni tampoco las que deriven de ellas sin proporcionar un implementación para todos los
métodos que carezcan de ella. Veamos un ejemplo que nos permita definir un método que
devuleva el área de un figura geométrica:
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
// abstrac.cs
abstract class Figura
{
...
public abstract float Area();
...
}
class Rectangulo: Figura
{
...
public override float Area()
{
return Alto * Ancho;
}
...
}
class Abstract
{
public static Main()
{
Figura[] figuras = new Figura[3];
figuras[0] = new Figura(1, 2); // error, clase abstracta
figuras[1] = new Rectangulo(3, 4); // ok
figuras[2] = new Cuadrado(5); // ok, hereda Area()
foreach (Figura f in figuras)
{
Console.WriteLine("El área de un {0} de {1}x{2} es {3}",
f.GetType(), f.Alto, f.Ancho, f.Area());
}
}
}
Clases y métodos "sellados"
Una clase puede evitar que otras deriven de ella empleando el modificador sealed en su
declaración.
sealed class Math { ... }
Existen dos razones para sellar una clase:
 Es una clase compuesta exclusivamente de miembros estáticos, como Math.
 El uso de sealed permite al compilador realizar llamadas a métodos no virtuales sobre
la clase sellada, que son más rápidas que las llamadas a métodos virtuales.
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
De la misma forma podemos sellar un método virtual de forma que
podemos asegurar su comportamiento al no permitir que pueda ser sobrecargado
posteriormente en una clase derivada.
Modificadores de acceso
Para favorecer la encapsulación (esconder la implementación de un objeto que no comtribuye
a sus características esnciales) una clase o sus componentespueden controlar quien puede
acceder a ellos:
 public: un tipo o miembro de un tipo es completamente accesible. Este es el tipo de
acceso por defecto de enumeraciones e interfaces.
 internal: un tipo o miembro de un tipo dentro de un ensamblaje sólo es accesible
desde el interior de dicho ensamblaje. Este es el tipo de acceso por defecto para
cualquier tipo, y por tanto puede ser omitido.
 private: un miembro de un tipo sólo es accesible desde el interior de dicho tipo. Este
es el tipo de acceso por defecto para los miembros de una clase o una estructura, y
por lo tanto, puede ser omitido.
 protected: un miembro de un tipo sólo es accesible desde el interior de dicho tipo y
de los tipos que de él deriven.
 protected internal: el miembro de una clase C dentro de un ensamblaje E es
accesible desde el interior de la clase C, las clases que derivan de C y desde el interior
del ensamblaje E.
Estructuras
Una estructura es similar a una clase. Se declaran utilizando la palabra clave struct. Las
principales diferencias con una clase son:
 Una clase es un tipo referencia mientras que una estructura es un tipo valor. En
consecuencia, las estructuras suelen utilizarse para declarar tipos simples en que la
semántica de tipo-valor sea deseable.
 Una estructura no puede heredar de una clase ni de otra estructura. Tampoco puede
ser la base de una clase. Sin embargo, heredan de la clase object. Al igual que las
clases, las estructuras pueden implementar interfaces.
 Las clases pueden tener destructores, pero las estructuras no.
 Las clases pueden tener constructores sin parámetros y además inicializar los campos
de una instancia, y en cambio, una estructura no. El constructor por defecto sin
parámetros de las estructuras inicializa cada campo con el valor por defecto que le
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
corresponda, y si declara un constructor, a todos los campos debe
asignarsele un valor.
// struct1.cs
using System;
struct SimpleStruct
{
private int xval;
public int X
{
get { return xval; }
set { if (value < 100) xval = value; }
}
public void DisplayX()
{
Console.WriteLine("El valor almacenado es: {0}", X);
}
}
class TestClass
{
public static void Main()
{
SimpleStruct ss = new SimpleStruct();
ss.X = 5;
ss.DisplayX();
}
}
A causa de que son tipos valor, cuando son pasados a un método, se pasan por valor en lugar
de por referencia como ocurre con las clases.
// struct2.cs
using System;
class TheClass
{
public int x;
}
struct TheStruct
{
public int x;
}
class TestClass
{
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
public static void structtaker(TheStruct s)
{
s.x = 5;
}
public static void classtaker(TheClass c)
{
c.x = 5;
}
public static void Main()
{
TheStruct a = new TheStruct();
TheClass b = new TheClass();
a.x = 1;
b.x = 1;
structtaker(a);
classtaker(b);
Console.WriteLine("a.x = {0}", a.x);
Console.WriteLine("b.x = {0}", b.x);
}
}
Podemos utilizar los atributos StructLayout(LayoutKind.Explicit) and FieldOffset para
indicar como deben colocarse en memoria los diferentes campos de una estructura. De esta
forma podemos conseguir el equivalente de una union de C/C++.
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Explicit)]
struct PosicionExplicita
{
[FieldOffset(0)]
public byte b0;
[FieldOffset(1)]
public byte b1;
[FieldOffset(2)]
public byte b2;
[FieldOffset(3)]
public byte b3;
[FieldOffset(0)]
public int i0;
[FieldOffset(1)]
public int i1;
[FieldOffset(0)]
public long l;
}
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
Interfaces
Un interfaz nos permite hacer que múltiles clases compartan ciertas características no
presentes en una clase base. Un interfaz tiene cierto parecido a una clase, pero con diferencias
significaticas:
 Un interfaz proporciona un especificación en lugar de una implementación de sus
miembros. Es algo parecido a una clase abstracta pura, que es una clase compuesta
únicamente de métodos abstractos.
 Cualquier clase o estructura pueden implementar varios imterfaces, pero sólo pueden
heredar de una única clase.
Anteriormente describimos el polimorfismo como la habilidad para realizar una misma
operación sobre un conjunto de tipos diferentes mientras estos compartiesen ciertas
características comunes. El propósito de un interfaz es precisamente definir un conjunto de
características. Estas características pueden ser:
 Métodos
 Propiedades
 Indexadores
 Eventos
La declaración de un interfaz es como la de una clase, salvo por que no se proporciona
implementación para sus miembros. La intención es que dichos miembros sean
implementados por las clases o estructuras que deriven de un interfaz.
interface Dibujable
{
void Dibujar();
}
Para implementar un interfaz, hemos de hacer como cuando utilizabamos la herencia, indicar
en la declaración de una clase o estructura que se deriva de él, y después implementar los
métodos del interfaz. Si la clase o estructura también hereda de una clase base, habremos de
colocarla al principio de la lista.
class Rectangulo: Figura, Dibujable
{
public void Dibujar()
{
if (Alto > 0)
{
string s = "";
for (int x = 0; x < Ancho; ++x)
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
s += "[]";
Console.WriteLine(s);
if (Alto > 2)
{
for (int y = 0; y < Alto - 2; ++y)
{
s = "[]";
for (int x = 0; x < Ancho - 2; ++x)
s += " ";
if (Ancho > 1)
s += "[]";
Console.WriteLine(s);
}
}
if (Alto > 1)
{
s = "";
for (int x = 0; x < Ancho; ++x)
s += "[]";
Console.WriteLine(s);
}
}
}
}
Al igual que ocurria en la herencia, podremos extender un interfaz. Con ello lograremos crear
un nuevo interfaz que posea más características que aquel del que deriva.
interface Dibujable
{
void Dibujar();
}
interface EsDibujable: Dibujable
{
bool PuedeDibujarse { get; }
}
Puede darse el caso en que en una misma clase o estructura se cree un conflito de nombres al
intentar heredar de una clase base y un interfaz un método o propiedad con el mismo nombre.
Para resolver este problema hemos de C# permite implementar explicitamente al menos uno
de los miembros del interfaz que generan el conflito. Veamos un ejemplo:
interface Figura
{
void Dibujar();
}
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
interface Dibujable
{
void Dibujar();
}
class Rectangulo: Figura, Dibujable
{
void Figura.Dibujar() { ... código ... }
void dibujable.Dibujar() { ... código ... }
}
Para acceder ahora a cualquiera de estos métodos habremos de realizar una conversión al tipo
de interfaz adecuado de la siguiente forma:
Rectangulo r = new Rectangulo(2, 3);
Figura f = (Figura)r;
Dibujable d = (Dibujable)r;
r.Dibujar();
d.Dibujar();
Enumeraciones
Las enumeraciones permiten crear un grupo de constantes numericas asociadas a un nombre.
Veamos un ejemplo:
public enum Rumbo {Norte, Sur, Este, Oeste};
Para utilizarlas tenemos que declarar una variable del tipo de la enumeración y asignarle un
valor dentro de los que dicha enumeración posea.
Rumbo avion = Rumbo.Sur;
Por defecto, a cada valor de la enumeración se le asigna como valor una constante entera 0,
1, 2,... Opcionalmente se puede especificar un tipo numérico alternativo y, además, asignarle
un valor de este tipo a cada uno de los componentes.
[Flags]
public enum Rumbo: byte {Norte = 1, Sur = 2, Este = 4, Oeste = 8};
Rumbo barco = Rumbo.Norte | Rumbo.Oeste;
if ((barco & Rumbo.Norte) != 0)
Console.WriteLine("Si vas hacia el Norte hará más frio");
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
El atributo [FLAGS] es opcional e informa al entorno de ejecución de
que los valores de la enumeración pueden ser combinados, y deberán ser decodificados
adecuadamente en el depurador y cuando se muestren por la consola.
Console.WriteLine(barco.Format()); // muestra "Norte|Oeste"
Console.WriteLine(barco); // muestra "9"
El tipo System.Enum proporciona una gran cantidad de métodos estáticos muy útilies para
manejar las enumeraciones:
// enum.cs
using System;
public enum Logico : byte { Off = 0, On = 1 };
class Prueba
{
public static void Main()
{
Type t = Enum.GetUnderlyingType(typeof(Logico));
Console.WriteLine(t); // imprime "Byte";
bool hay_medio = Enum.IsDefined(typeof(Logico), "Medio");
Console.WriteLine(hay_medio); // imprime "False"
Logico l = (Logico)Enum.Parse(typeof(Logico), "On");
Console.WriteLine(Enum.Format(typeof(Logico), l, "D")); // imprime "1"
Console.WriteLine(l); // imprime "On"
foreach(Logico logico in Enum.GetValues(typeof(Logico)))
Console.WriteLine("{0} = {1}", logico,
Enum.Format(typeof(Logico), logico, "D"));
}
}
Sobrecarga de operadores
La sobrecarga de operadores permite a especificar la implementación de operador siempre
que uno o los dos operandos sean clases definidas por el usuario o una estructura. Los
operadores son métodos, cuya sintaxis es un tanto especial. La lista de operadores
sobrecargables es: +, -, !, ~, ++, --, /, %, &, |, ^, <<, >>, ==, !=, <, >, <=, >=. Veamos en
primer lugar un ejemplo que permite implementar la operación de suma sobre los números
complejos:
// complex.cs
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
using System;
public struct Complex
{
public int real;
public int imaginary;
public Complex(int real, int imaginary)
{
this.real = real;
this.imaginary = imaginary;
}
// sobrecarga del operador de suma
public static Complex operator +(Complex c1, Complex c2)
{
return new Complex(c1.real + c2.real, c1.imaginary + c2.imaginary);
}
// sobrecarga del método "ToString"
public override string ToString()
{
return(String.Format("{0} + {1}i", real, imaginary));
}
public static void Main()
{
Complex num1 = new Complex(2,3);
Complex num2 = new Complex(3,4);
// suma de dos números complejos utilizando el
// operador de suma que hemos sobrecargado
Complex sum = num1 + num2;
// impresión de tres números complejos
Console.WriteLine("First complex number: {0}",num1);
Console.WriteLine("Second complex number: {0}",num2);
Console.WriteLine("The sum of the two numbers: {0}",sum);
}
}
Excepciones
Las excepciones son objetos que contienen información representando la ocurrencia de un
estado excepcional en un programa. Cuando sucede un evento en un programa que produce
un estado de excepción, como una divisón por cero, se lanza una excepción para avisar de
dicho suceso.
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
// exception.cs
using System;
class Exception
{
public static void Main()
{
int v0 = 0;
int v1 = 1;
v1 = v1 / v0;
}
}
Para manejar excepciones se utilizan las palabras reservadas try,catch y finally. El bloque
try tiene dos propósitos: permitir a u n bloque catch capturar un excepción y asegurar que se
ejecutará el bloque finally. Un bloque try debe estar seguido por un o más bloques catch y
finally.
try
{
código que sospechamos que pueda lanzar una excepción
}
catch (TipoDeException1 e)
{
código para reaccionar a excepciones de tipo TipoDeException1
}
catch (TipoDeException2 e)
{
código para reaccionar a excepciones de tipo TipoDeException2
}
...
catch (TipoDeExceptionN e)
{
código para reaccionar a excepciones de tipo TipoDeExceptionN
}
finally
{
código que se ejecuta siempre después de try,
tanto si se lanza una excepción como si no
}
La acción por defecto cuando se lanza una excepción y esta no es adecauadamente tratada
dentro de un bloque catch es abortar el programa, que es lo que sucede en el ejemplo
exeception.cs. Veamos como podemos resolver esta situación:
// exception2.cs
using System;
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
class Exception
{
public static void Main()
{
int v0 = 0;
int v1 = 1;
try
{
v1 = v1 / v0;
}
catch (DivideByZeroException exception)
{
Console.WriteLine("Excepción: {0}", exception.Message);
}
finally
{
Console.WriteLine("Supongo que ya se ha resulto el problema, ¿no?");
}
}
}
Para poder atrapar una excepción dentro de un bloque catch, esta debe ser de tipo
System.Exception o derivar de este. Las excepciones de tipo System.Exception son las más
generales posibles. Normalmente intentaremos atrapar excepciones de algún tipo más
específico que nos permita saber más acerca de la excepción lanzada y así tener más medios
para resolver la situación. A la hora de crear una clase podemos preveer que tipo de errores
pueden darse y derivar tipos de excepciones de para intentar resolver dichos errores. Nosotros
podemos lanzar explícitamente una excepción mediante la palabra reservada try. Algunas de
las excepciones más comunes y por ello ya definidas son:
System.OutOfMemoryException
System.NullReferenceException
Syste.InvalidCastException
Syste.ArrayTypeMismatchException
System.IndexOutOfRangeException
System.ArithmeticException
System.DevideByZeroException
System.OverFlowException
En una cláusula catch puede omitirse tanto la variable de la excepción si no va a utilizarse,
como el parámetro con el tipo de excepción completo, con lo cual se atrapará cualquier tipo
de excepción.
// exception3.cs
using System;
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
class Exception
{
public static void Main()
{
int[] array = {1, 2, 3};
try
{
for (int i = 0; i < 5; ++i)
Console.WriteLine("array[{0}] = {1}", i, array[i]);
}
catch (OutOfMemoryException e)
{
Console.WriteLine("Excepción: {0}", e.Message);
}
catch (IndexOutOfRangeException e)
{
Console.WriteLine("Excepción: {0}", e.Message);
}
catch
{
Console.WriteLine("Excepción general");
}
finally
{
Console.WriteLine("Supongo que ya se ha resulto el problema, ¿no?");
}
}
}
La estructura jerárquica del sistema de excepciones que declaremos condicionará el orden en
estas puedan ser utilizadas tras un bloque try. No se puede intentar atrapar una excepción de
un tipo derivado de otro que se ha intentado atraparse en una cláusula previa. Veamos un
ejemplo válido y otro que no lo es:
Uso válido Error
try { ... }
catch (Exception3) { ... }
catch (Exception2) { ... }
catch (Exception1) { ... }
catch { ... }
finally { ... }
try { ... }
catch { ... }
catch (Exception1) { ... }
catch (Exception2) { ... }
catch (Exception3) { ... }
finally { ... }
La clase System.Exception tiene algunas propiedades muy útiles de las que cabe destacar:
 Message: Cadena con la descripción del error.
Pontificia Universidad Católica del Ecuador
Mtr. Luis Fernando Aguas B.
 StackTrace: Cadena con todos los métodos llamados desde el
origen de la excepción hasta el bloque catch.
// exception4.cs
using System;
class Prueba
{
public static void Main()
{
int v0 = 0;
int v1 = 1;
try
{
v1 = v1 / v0;
}
catch (DivideByZeroException exception)
{
Console.WriteLine("exception.Message: {0}", exception.Message);
Console.WriteLine("exception.StackTrace: {0}",
exception.StackTrace);
}
finally
{
Console.WriteLine("¡Ya eres un experto en manejo de excepciones!");
}
}
}

Más contenido relacionado

La actualidad más candente

Tema 2 tipos de datos y expresiones en java por gio
Tema 2   tipos de datos y expresiones en java por gioTema 2   tipos de datos y expresiones en java por gio
Tema 2 tipos de datos y expresiones en java por gioRobert Wolf
 
Estructura sintactica de los lenguajes de programacion
Estructura sintactica de los lenguajes de programacionEstructura sintactica de los lenguajes de programacion
Estructura sintactica de los lenguajes de programacionandreinagracielarojasadam
 
Estructura sintactica de los lenguajes de programacion y bases de datos
Estructura sintactica de los lenguajes de programacion y bases de datosEstructura sintactica de los lenguajes de programacion y bases de datos
Estructura sintactica de los lenguajes de programacion y bases de datosspedy93
 
TIPOS DE DATOS EN JAVA
TIPOS DE DATOS EN JAVATIPOS DE DATOS EN JAVA
TIPOS DE DATOS EN JAVAberna29
 
Lenguaje latino
Lenguaje latinoLenguaje latino
Lenguaje latinoReneSergio
 
02 python Programación orientada a objetos y funcional
02 python Programación orientada a objetos y funcional02 python Programación orientada a objetos y funcional
02 python Programación orientada a objetos y funcionalJuan Rodríguez
 
Sintaxis Básica de Java
Sintaxis Básica de JavaSintaxis Básica de Java
Sintaxis Básica de JavaRay
 
Tipos de datos_para_c_
Tipos de datos_para_c_Tipos de datos_para_c_
Tipos de datos_para_c_oscar020615
 
Tema 1-2 identificadores - variable y constante
Tema 1-2 identificadores - variable y constanteTema 1-2 identificadores - variable y constante
Tema 1-2 identificadores - variable y constanteRufi Flores
 
Sentenciasenvisualbasicnet2019
Sentenciasenvisualbasicnet2019Sentenciasenvisualbasicnet2019
Sentenciasenvisualbasicnet2019Victor Zapata
 
3.2.- Identificadores, Variables y Constantes
3.2.- Identificadores, Variables y Constantes3.2.- Identificadores, Variables y Constantes
3.2.- Identificadores, Variables y ConstantesYenny Salazar
 
Java - Sintaxis Básica 2015
Java - Sintaxis Básica 2015Java - Sintaxis Básica 2015
Java - Sintaxis Básica 2015Renny Batista
 
Constante y variable
Constante y variableConstante y variable
Constante y variableAnthony Vera
 
P2 actividades 2 y 3 infografía palabras reservadas
P2 actividades 2 y 3 infografía palabras reservadasP2 actividades 2 y 3 infografía palabras reservadas
P2 actividades 2 y 3 infografía palabras reservadasRoberto Cortez
 
Tipos de datos definidos por el programador en pseudocódigo
Tipos de datos definidos por el programador en pseudocódigoTipos de datos definidos por el programador en pseudocódigo
Tipos de datos definidos por el programador en pseudocódigoAbrirllave
 

La actualidad más candente (20)

Tema 2 tipos de datos y expresiones en java por gio
Tema 2   tipos de datos y expresiones en java por gioTema 2   tipos de datos y expresiones en java por gio
Tema 2 tipos de datos y expresiones en java por gio
 
Estructura sintactica de los lenguajes de programacion
Estructura sintactica de los lenguajes de programacionEstructura sintactica de los lenguajes de programacion
Estructura sintactica de los lenguajes de programacion
 
Estructura sintactica de los lenguajes de programacion y bases de datos
Estructura sintactica de los lenguajes de programacion y bases de datosEstructura sintactica de los lenguajes de programacion y bases de datos
Estructura sintactica de los lenguajes de programacion y bases de datos
 
TIPOS DE DATOS EN JAVA
TIPOS DE DATOS EN JAVATIPOS DE DATOS EN JAVA
TIPOS DE DATOS EN JAVA
 
Programacion I
Programacion IProgramacion I
Programacion I
 
Lenguaje latino
Lenguaje latinoLenguaje latino
Lenguaje latino
 
02 python Programación orientada a objetos y funcional
02 python Programación orientada a objetos y funcional02 python Programación orientada a objetos y funcional
02 python Programación orientada a objetos y funcional
 
Tipos de datos.java
Tipos de datos.javaTipos de datos.java
Tipos de datos.java
 
Sintaxis Básica de Java
Sintaxis Básica de JavaSintaxis Básica de Java
Sintaxis Básica de Java
 
Ap3 java
Ap3   javaAp3   java
Ap3 java
 
Tipos de datos_para_c_
Tipos de datos_para_c_Tipos de datos_para_c_
Tipos de datos_para_c_
 
Tema 1-2 identificadores - variable y constante
Tema 1-2 identificadores - variable y constanteTema 1-2 identificadores - variable y constante
Tema 1-2 identificadores - variable y constante
 
Sentenciasenvisualbasicnet2019
Sentenciasenvisualbasicnet2019Sentenciasenvisualbasicnet2019
Sentenciasenvisualbasicnet2019
 
Tutorial jared
Tutorial jaredTutorial jared
Tutorial jared
 
3.2.- Identificadores, Variables y Constantes
3.2.- Identificadores, Variables y Constantes3.2.- Identificadores, Variables y Constantes
3.2.- Identificadores, Variables y Constantes
 
Java - Sintaxis Básica 2015
Java - Sintaxis Básica 2015Java - Sintaxis Básica 2015
Java - Sintaxis Básica 2015
 
Ap n° 3 rios,m. fernanda
Ap n° 3 rios,m. fernandaAp n° 3 rios,m. fernanda
Ap n° 3 rios,m. fernanda
 
Constante y variable
Constante y variableConstante y variable
Constante y variable
 
P2 actividades 2 y 3 infografía palabras reservadas
P2 actividades 2 y 3 infografía palabras reservadasP2 actividades 2 y 3 infografía palabras reservadas
P2 actividades 2 y 3 infografía palabras reservadas
 
Tipos de datos definidos por el programador en pseudocódigo
Tipos de datos definidos por el programador en pseudocódigoTipos de datos definidos por el programador en pseudocódigo
Tipos de datos definidos por el programador en pseudocódigo
 

Destacado (8)

Calculo i
Calculo iCalculo i
Calculo i
 
Tipos de hipotesis
Tipos de hipotesisTipos de hipotesis
Tipos de hipotesis
 
Distribucion normal
Distribucion normalDistribucion normal
Distribucion normal
 
Variables
VariablesVariables
Variables
 
Sistematizacion de las experiencias
Sistematizacion de las experienciasSistematizacion de las experiencias
Sistematizacion de las experiencias
 
Sistematización de experiencias
Sistematización de experienciasSistematización de experiencias
Sistematización de experiencias
 
Redacción material y metodo.
Redacción material y metodo.Redacción material y metodo.
Redacción material y metodo.
 
Materiales y métodos
Materiales y métodosMateriales y métodos
Materiales y métodos
 

Similar a Variables y constantes en Csharp

Similar a Variables y constantes en Csharp (20)

tipos
tipos tipos
tipos
 
Semana9b Vbr
Semana9b VbrSemana9b Vbr
Semana9b Vbr
 
Programación ii presentación tema 5
Programación ii presentación tema 5Programación ii presentación tema 5
Programación ii presentación tema 5
 
El lenguaje C++ (1).ppt
El lenguaje C++ (1).pptEl lenguaje C++ (1).ppt
El lenguaje C++ (1).ppt
 
El lenguaje C++.ppt
El lenguaje C++.pptEl lenguaje C++.ppt
El lenguaje C++.ppt
 
Framework .NET 3.5 05 Tipo y jerarquía de objetos
Framework .NET 3.5 05 Tipo y jerarquía de objetosFramework .NET 3.5 05 Tipo y jerarquía de objetos
Framework .NET 3.5 05 Tipo y jerarquía de objetos
 
Introducción a la Programaciónen Java
Introducción a la Programaciónen JavaIntroducción a la Programaciónen Java
Introducción a la Programaciónen Java
 
Diseño de la logica
Diseño de la logicaDiseño de la logica
Diseño de la logica
 
LibreríAs De Java
LibreríAs De JavaLibreríAs De Java
LibreríAs De Java
 
Poo4
Poo4Poo4
Poo4
 
Tutorial C++
Tutorial C++Tutorial C++
Tutorial C++
 
Tutorial c (3)
Tutorial c (3)Tutorial c (3)
Tutorial c (3)
 
Tutorial C++
Tutorial C++Tutorial C++
Tutorial C++
 
C2 clases en java
C2 clases en javaC2 clases en java
C2 clases en java
 
U8.- Programacion Orientada a objetos II (2).pdf
U8.- Programacion Orientada a objetos II (2).pdfU8.- Programacion Orientada a objetos II (2).pdf
U8.- Programacion Orientada a objetos II (2).pdf
 
9 Curso de POO en java - variables, constantes y objetos
9 Curso de POO en java - variables, constantes y objetos9 Curso de POO en java - variables, constantes y objetos
9 Curso de POO en java - variables, constantes y objetos
 
Elementos de una clase
Elementos de una claseElementos de una clase
Elementos de una clase
 
Guia poo
Guia pooGuia poo
Guia poo
 
Datos Previos
Datos PreviosDatos Previos
Datos Previos
 
Programacion
ProgramacionProgramacion
Programacion
 

Más de Luis Fernando Aguas Bucheli (20)

EFC-ISW-Luis Fernando Aguas.pptx
EFC-ISW-Luis Fernando Aguas.pptxEFC-ISW-Luis Fernando Aguas.pptx
EFC-ISW-Luis Fernando Aguas.pptx
 
P-S2.pptx
P-S2.pptxP-S2.pptx
P-S2.pptx
 
EBTS-S1.pptx
EBTS-S1.pptxEBTS-S1.pptx
EBTS-S1.pptx
 
P-S3.pptx
P-S3.pptxP-S3.pptx
P-S3.pptx
 
EBTS-S4.pptx
EBTS-S4.pptxEBTS-S4.pptx
EBTS-S4.pptx
 
P-S4.pptx
P-S4.pptxP-S4.pptx
P-S4.pptx
 
P-S1.pptx
P-S1.pptxP-S1.pptx
P-S1.pptx
 
EBTS-S3.pptx
EBTS-S3.pptxEBTS-S3.pptx
EBTS-S3.pptx
 
EBTS-S2.pptx
EBTS-S2.pptxEBTS-S2.pptx
EBTS-S2.pptx
 
PDIDTI-S7.pptx
PDIDTI-S7.pptxPDIDTI-S7.pptx
PDIDTI-S7.pptx
 
PDIDTI-S4.pptx
PDIDTI-S4.pptxPDIDTI-S4.pptx
PDIDTI-S4.pptx
 
PDIDTI-S2.pptx
PDIDTI-S2.pptxPDIDTI-S2.pptx
PDIDTI-S2.pptx
 
PDIDTI-S1.pptx
PDIDTI-S1.pptxPDIDTI-S1.pptx
PDIDTI-S1.pptx
 
PDIDTI-S8.pptx
PDIDTI-S8.pptxPDIDTI-S8.pptx
PDIDTI-S8.pptx
 
PDIDTI-S6.pptx
PDIDTI-S6.pptxPDIDTI-S6.pptx
PDIDTI-S6.pptx
 
PDIDTI-S5.pptx
PDIDTI-S5.pptxPDIDTI-S5.pptx
PDIDTI-S5.pptx
 
PDIDTI-S3.pptx
PDIDTI-S3.pptxPDIDTI-S3.pptx
PDIDTI-S3.pptx
 
TIC-S4.pptx
TIC-S4.pptxTIC-S4.pptx
TIC-S4.pptx
 
TIC-S3.pptx
TIC-S3.pptxTIC-S3.pptx
TIC-S3.pptx
 
TIC-S2.pptx
TIC-S2.pptxTIC-S2.pptx
TIC-S2.pptx
 

Último

Quinto-Cuaderno-del-Alumno-optimizado.pdf
Quinto-Cuaderno-del-Alumno-optimizado.pdfQuinto-Cuaderno-del-Alumno-optimizado.pdf
Quinto-Cuaderno-del-Alumno-optimizado.pdfPapiElMejor1
 
Arquitectura Moderna Walter Gropius- Frank Lloyd Wright
Arquitectura Moderna  Walter Gropius- Frank Lloyd WrightArquitectura Moderna  Walter Gropius- Frank Lloyd Wright
Arquitectura Moderna Walter Gropius- Frank Lloyd Wrightimariagsg
 
Arquitectura moderna nazareth bermudez PSM
Arquitectura moderna nazareth bermudez PSMArquitectura moderna nazareth bermudez PSM
Arquitectura moderna nazareth bermudez PSMNaza59
 
Presentacion de 100 psicologos dijeron.pptx
Presentacion de 100 psicologos dijeron.pptxPresentacion de 100 psicologos dijeron.pptx
Presentacion de 100 psicologos dijeron.pptxbarbaracantuflr
 
Jesus Diaz afiche Manierismo .pdf arquitectura
Jesus Diaz afiche Manierismo .pdf arquitecturaJesus Diaz afiche Manierismo .pdf arquitectura
Jesus Diaz afiche Manierismo .pdf arquitecturajesusgrosales12
 
2024-EL CAMBIO CLIMATICO Y SUS EFECTOS EN EL PERÚ Y EL MUNDO.pdf
2024-EL CAMBIO CLIMATICO Y SUS EFECTOS EN EL PERÚ Y EL MUNDO.pdf2024-EL CAMBIO CLIMATICO Y SUS EFECTOS EN EL PERÚ Y EL MUNDO.pdf
2024-EL CAMBIO CLIMATICO Y SUS EFECTOS EN EL PERÚ Y EL MUNDO.pdfcnaomi195
 
CERTIFICACIÓN DE CAPACITACIÓN PARA EL CENSO - tfdxwBRz6f3AP7QU.pdf
CERTIFICACIÓN DE CAPACITACIÓN PARA EL CENSO - tfdxwBRz6f3AP7QU.pdfCERTIFICACIÓN DE CAPACITACIÓN PARA EL CENSO - tfdxwBRz6f3AP7QU.pdf
CERTIFICACIÓN DE CAPACITACIÓN PARA EL CENSO - tfdxwBRz6f3AP7QU.pdfasnsdt
 
plantilla-de-messi-1.pdf es muy especial
plantilla-de-messi-1.pdf es muy especialplantilla-de-messi-1.pdf es muy especial
plantilla-de-messi-1.pdf es muy especialAndreaMlaga1
 
Maquetas-modelos-prototipos-Mapa mental-.pdf
Maquetas-modelos-prototipos-Mapa mental-.pdfMaquetas-modelos-prototipos-Mapa mental-.pdf
Maquetas-modelos-prototipos-Mapa mental-.pdforianaandrade11
 
Arquitectura Moderna Le Corbusier- Mies Van Der Rohe
Arquitectura Moderna Le Corbusier- Mies Van Der RoheArquitectura Moderna Le Corbusier- Mies Van Der Rohe
Arquitectura Moderna Le Corbusier- Mies Van Der Roheimariagsg
 
Normas de convivencia para imprimir gratis
Normas de convivencia para imprimir gratisNormas de convivencia para imprimir gratis
Normas de convivencia para imprimir gratisbrasilyamile
 
Arquitectura moderna / Nazareth Bermúdez
Arquitectura moderna / Nazareth BermúdezArquitectura moderna / Nazareth Bermúdez
Arquitectura moderna / Nazareth BermúdezNaza59
 
Brochure Tuna Haus _ Hecho para mascotas.pdf
Brochure Tuna Haus _ Hecho para mascotas.pdfBrochure Tuna Haus _ Hecho para mascotas.pdf
Brochure Tuna Haus _ Hecho para mascotas.pdfhellotunahaus
 
TIPOS DE LINEAS utilizados en dibujo técnico mecánico
TIPOS DE LINEAS utilizados en dibujo técnico mecánicoTIPOS DE LINEAS utilizados en dibujo técnico mecánico
TIPOS DE LINEAS utilizados en dibujo técnico mecánicoWilsonChambi4
 
Guía de actividades y rúbrica de evaluación - Unidad 3 - Escenario 4 - Rol de...
Guía de actividades y rúbrica de evaluación - Unidad 3 - Escenario 4 - Rol de...Guía de actividades y rúbrica de evaluación - Unidad 3 - Escenario 4 - Rol de...
Guía de actividades y rúbrica de evaluación - Unidad 3 - Escenario 4 - Rol de...MayerlyAscanioNavarr
 
Arquitectos del Movimiento Moderno (Historia de la Arquitectura)
Arquitectos del Movimiento Moderno (Historia de la Arquitectura)Arquitectos del Movimiento Moderno (Historia de la Arquitectura)
Arquitectos del Movimiento Moderno (Historia de la Arquitectura)LeonardoDantasRivas
 
Le Corbusier y Mies van der Rohe: Aportes a la Arquitectura Moderna
Le Corbusier y Mies van der Rohe: Aportes a la Arquitectura ModernaLe Corbusier y Mies van der Rohe: Aportes a la Arquitectura Moderna
Le Corbusier y Mies van der Rohe: Aportes a la Arquitectura Modernasofpaolpz
 
Proceso de percepción visual y de reconocimiento
Proceso de percepción visual y de reconocimientoProceso de percepción visual y de reconocimiento
Proceso de percepción visual y de reconocimientoJorge Fernandez
 
PDU - PLAN DE DESARROLLO URBANO DE LA CIUDAD DE CHICLAYO
PDU - PLAN DE DESARROLLO URBANO DE LA CIUDAD DE CHICLAYOPDU - PLAN DE DESARROLLO URBANO DE LA CIUDAD DE CHICLAYO
PDU - PLAN DE DESARROLLO URBANO DE LA CIUDAD DE CHICLAYOManuelBustamante49
 

Último (20)

Quinto-Cuaderno-del-Alumno-optimizado.pdf
Quinto-Cuaderno-del-Alumno-optimizado.pdfQuinto-Cuaderno-del-Alumno-optimizado.pdf
Quinto-Cuaderno-del-Alumno-optimizado.pdf
 
Arquitectura Moderna Walter Gropius- Frank Lloyd Wright
Arquitectura Moderna  Walter Gropius- Frank Lloyd WrightArquitectura Moderna  Walter Gropius- Frank Lloyd Wright
Arquitectura Moderna Walter Gropius- Frank Lloyd Wright
 
Arquitectura moderna nazareth bermudez PSM
Arquitectura moderna nazareth bermudez PSMArquitectura moderna nazareth bermudez PSM
Arquitectura moderna nazareth bermudez PSM
 
Presentacion de 100 psicologos dijeron.pptx
Presentacion de 100 psicologos dijeron.pptxPresentacion de 100 psicologos dijeron.pptx
Presentacion de 100 psicologos dijeron.pptx
 
Jesus Diaz afiche Manierismo .pdf arquitectura
Jesus Diaz afiche Manierismo .pdf arquitecturaJesus Diaz afiche Manierismo .pdf arquitectura
Jesus Diaz afiche Manierismo .pdf arquitectura
 
2024-EL CAMBIO CLIMATICO Y SUS EFECTOS EN EL PERÚ Y EL MUNDO.pdf
2024-EL CAMBIO CLIMATICO Y SUS EFECTOS EN EL PERÚ Y EL MUNDO.pdf2024-EL CAMBIO CLIMATICO Y SUS EFECTOS EN EL PERÚ Y EL MUNDO.pdf
2024-EL CAMBIO CLIMATICO Y SUS EFECTOS EN EL PERÚ Y EL MUNDO.pdf
 
CERTIFICACIÓN DE CAPACITACIÓN PARA EL CENSO - tfdxwBRz6f3AP7QU.pdf
CERTIFICACIÓN DE CAPACITACIÓN PARA EL CENSO - tfdxwBRz6f3AP7QU.pdfCERTIFICACIÓN DE CAPACITACIÓN PARA EL CENSO - tfdxwBRz6f3AP7QU.pdf
CERTIFICACIÓN DE CAPACITACIÓN PARA EL CENSO - tfdxwBRz6f3AP7QU.pdf
 
plantilla-de-messi-1.pdf es muy especial
plantilla-de-messi-1.pdf es muy especialplantilla-de-messi-1.pdf es muy especial
plantilla-de-messi-1.pdf es muy especial
 
Maquetas-modelos-prototipos-Mapa mental-.pdf
Maquetas-modelos-prototipos-Mapa mental-.pdfMaquetas-modelos-prototipos-Mapa mental-.pdf
Maquetas-modelos-prototipos-Mapa mental-.pdf
 
Arquitectura Moderna Le Corbusier- Mies Van Der Rohe
Arquitectura Moderna Le Corbusier- Mies Van Der RoheArquitectura Moderna Le Corbusier- Mies Van Der Rohe
Arquitectura Moderna Le Corbusier- Mies Van Der Rohe
 
1.La locomoción de los seres vivos diseño
1.La locomoción de los seres vivos diseño1.La locomoción de los seres vivos diseño
1.La locomoción de los seres vivos diseño
 
Normas de convivencia para imprimir gratis
Normas de convivencia para imprimir gratisNormas de convivencia para imprimir gratis
Normas de convivencia para imprimir gratis
 
Arquitectura moderna / Nazareth Bermúdez
Arquitectura moderna / Nazareth BermúdezArquitectura moderna / Nazareth Bermúdez
Arquitectura moderna / Nazareth Bermúdez
 
Brochure Tuna Haus _ Hecho para mascotas.pdf
Brochure Tuna Haus _ Hecho para mascotas.pdfBrochure Tuna Haus _ Hecho para mascotas.pdf
Brochure Tuna Haus _ Hecho para mascotas.pdf
 
TIPOS DE LINEAS utilizados en dibujo técnico mecánico
TIPOS DE LINEAS utilizados en dibujo técnico mecánicoTIPOS DE LINEAS utilizados en dibujo técnico mecánico
TIPOS DE LINEAS utilizados en dibujo técnico mecánico
 
Guía de actividades y rúbrica de evaluación - Unidad 3 - Escenario 4 - Rol de...
Guía de actividades y rúbrica de evaluación - Unidad 3 - Escenario 4 - Rol de...Guía de actividades y rúbrica de evaluación - Unidad 3 - Escenario 4 - Rol de...
Guía de actividades y rúbrica de evaluación - Unidad 3 - Escenario 4 - Rol de...
 
Arquitectos del Movimiento Moderno (Historia de la Arquitectura)
Arquitectos del Movimiento Moderno (Historia de la Arquitectura)Arquitectos del Movimiento Moderno (Historia de la Arquitectura)
Arquitectos del Movimiento Moderno (Historia de la Arquitectura)
 
Le Corbusier y Mies van der Rohe: Aportes a la Arquitectura Moderna
Le Corbusier y Mies van der Rohe: Aportes a la Arquitectura ModernaLe Corbusier y Mies van der Rohe: Aportes a la Arquitectura Moderna
Le Corbusier y Mies van der Rohe: Aportes a la Arquitectura Moderna
 
Proceso de percepción visual y de reconocimiento
Proceso de percepción visual y de reconocimientoProceso de percepción visual y de reconocimiento
Proceso de percepción visual y de reconocimiento
 
PDU - PLAN DE DESARROLLO URBANO DE LA CIUDAD DE CHICLAYO
PDU - PLAN DE DESARROLLO URBANO DE LA CIUDAD DE CHICLAYOPDU - PLAN DE DESARROLLO URBANO DE LA CIUDAD DE CHICLAYO
PDU - PLAN DE DESARROLLO URBANO DE LA CIUDAD DE CHICLAYO
 

Variables y constantes en Csharp

  • 1. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. Tutorial Csharp Variables y Constantes Una variable o una constante representan un posición de memoria ocupada por un tipo de dato. Una varible puede ser local, el parámetro de un método, el elemento de un array, un campo de una instancia de un objeto o un campo estático de un objeto, y su valor puede ser modificado, en cambio, el valor de una constante siempre es el mismo. string saludo = "hola"; const double pi = 3.1415; Dado que C# es fuertemente tipificado todas las variables y constantes tienen asociado un tipo que define los posibles valores que puede tomar. En C# a todas las variables y constantes se les debe asignar un valor antes de poder utilizarlas. Esta asignación de valor puede ser tanto explícita como automática a través de la asignación del valor por defecto para un tipo. Estos son los valores por defecto para los diferentes tipos: Tipo Valor por defecto tipos numéricos 0 bool false char '0' enumeraciones 0 referencias null Cuando intentamos utilizar una variable sin asignarle un valor se producirá un error como sucede con el siguiente ejemplo: // variable.cs using System; public class Variable { int v;
  • 2. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. public Variable() {} // v = valor por defecto public Variable(int a) { v = a; } // v = a static void Main() { Variable[] variable = new Variable[2]; // declaramos un array Console.WriteLine(variable[1]); // ok, valor por defecto Variable v; console.WriteLine(v); // error, v sin asignar } } Espacios de nombres En C# se podemos utilizar espacios de nombres para agrupar de forma lógica ciertas porciones de código de forma que se les asocia un nombre para su uso. Si no utilizamos explícitamente ningún espacio de nombres estaremos utilizando el espacio de nombres global, como se hace en el primer ejemplo holamundo.cs. Veamos ahora como utilizar explícitamente el espacio de nombres System en holamundo2.cs de forma que no tengamos que escribir System. cada vez que nos queramos referir a alguna variable, clase, ... que esté definida en su interior. Para ello deberemos emplear using. // holamundo2.cs using System; // espacio de nombres que usaremos public class HolaMundo2 { public static void Main() { Console.WriteLine("¡Hola, Mundo!"); } } Para definir un espacio de nombres deberemos utilizar la palabra namespace. En el siguiente ejemplo se definen dos clases llamadas Prueba en dos espacios de nombres diferentes. Los nombres completos de estas clases serán Espacio1.Prueba y Espacio2.Prueba. Para poder utilizarlos empleando solamente Prueba deberemos especificar en que espacio de nombres está dicha clase utilizando previamente using. // espacios.cs using System; // usaremos el espacio de nombres System
  • 3. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. namespace Espacio1 // declaración del espacio de nombres Espacio1 { public class Prueba { public Prueba() { Console.WriteLine("Espacio1.Prueba"); } } } namespace Espacio2 // declaración del espacio de nombres Espacio2 { public class Prueba { public Prueba() { Console.WriteLine("Espacio2.Prueba"); } } } using Espacio2; // usaremos el espacio de nombres Espacio2 public class Namespace { public static void Main() { Prueba p = new Prueba(); } } Espacios de nombres anidados Los espacios de nombres pueden anidarse, es decir, definirse dentro de otros espacios de nombres. Para ello no tendremos más que encerrara la declaración de un espacio de nombres dentro de la de otro espacio de nombres. Para referirnos a las declaraciones del espacio interior habremos de utilizar la clausula using seguida de todos los espacios de nombres unidos mediante un punto o referirnos a un tipo empleando su nombre completo. // anidado.cs using System; namespace Exterior { namespace Interior { class Hola
  • 4. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. { public Hola() { Console.WriteLine("¡Hola!"); } } } } using Exterior.Interior; class EspacioNombresAnidado { public static void Main() { Hola hola = new Hola(); // alternativamente se podría haber utilizado: // Exterior.Interior.Hola hola = new Exterior.Interior.Hola(); } } Alias En C# se pueden crear alias de tipos y espacios de nombres, con lo que podremos referirnos a ciertos tipos y espacios de nombres utilizando otro nombre distinto al que tienen en su declaración. // alias.cs using sys = System; // alias de espacio de nombres using cadena = System.String; // alias de tipo class Alias { public static void Main() { cadena c = "¡Hola, mundo!"; sys.Console.WriteLine(c); // ¡hola, mundo! sys.Console.WriteLine(c.GetType()); // System.String } } Identificadores y palabras clave Los identificadores son los nombre que elegimos para nuestros variables, clases, etc. Un identificador debe ser una palabra completa compuesta de caracteres unicode y que comience por una letra o un guión bajo (_) y que no sea igual que una palabra clave del lenguaje. Como un caso especial podremos utilizar @ como prefijo de un identificador si queremos que este
  • 5. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. se llame igual que una palabra reservada por el lenguaje, pero sin que se considere parte de él. Así las variables x y @x son iguales. Las letras mayúsculas y minúsculas crean identificadores diferentes. Las palabras clave de C# son: abstract event new struct as explicit null switch base extern object this bool false operator throw break finally out true byte fixed override try case float params typeof catch for private uint char foreach protected ulong checked goto public unchecked class if readonly unsafe const implicit ref ushort continue in return using decimal int byte virtual default interface sealed volatile delegate internal short void do is sizeof while double lock stackalloc else long static enum namespace string Tipos predefinidos Los tipos predefinidos en C# son alias de tipos en el espacio de nombres System. Aquí podemos ver la lista completa de los mismos: Tipo C# Clase System Bool System.Boolean Byte System.Byte Sbyte System.SByte Char System.Char Decimal System.Decimal Doublé System.Double Tipo C# Clase System int System.Int32 uint System.UInt32 long System.Int64 ulong System.UInt64 object System.Object short System.Short
  • 6. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. Float System.Single ushort System.UShort string System.String A todos estos tipos, salvo object y string, se les denomina tipos simples. Todos los tipos y sus alias pueden utilizarse indistintamente. De esta forma podemos declarar un entero utilizando tanto int como System.Int32: int x = 123; System.Int32 x = 123; Para mostrar el nombre de cualquier tipo C# podemos utilizar el método GetType() o el operador typedef. Console.WriteLine(x.GetType()); Tipos valor y tipos referencia Todos los tipos en C# pertenecen a una de las siguientes tres categorías, cuya diferencia fundamental entre estas tres categorias es la forma en que son tratados en memoria.  Tipos valor: enum, struct  Tipos referencia: array, class, delegate, interface  Tipo puntero Tipos valor Estos tipos son los más sencillos de comprender. Directamente contienen los datos, por ejemplo, un tipo int contiene su valor, o un tipo bool vale true o false. Una de sus características es que cuando se asignan el valor de una variable a otra, se crea una copia de dicho valor. // valor.cs using System; class Valor { static void Main() { int x = 3; int y = x; // y es una copia de x
  • 7. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. ++x; // incrementa x a 4 Console.WriteLine("x = {0} y = {1}", x, y); } } Este ejemplo crea dos variables de tipo int, x e y. Inicialmente x vale 3 e y pasa a ser una copia de x. Al incrementar el valor de x, el valor de y no cambia puesto que ambos valores son copias independientes en memoria. Todos los tipos simples y sus combinaciones a través de structs pertenecen a esta categoría. Tipos referencia Los tipos referencia son algo más complejos. En un tipo referencia hemos de diferenciar entre un objeto y una referencia a un objeto. Veamos con un ejemplo cada una de estas partes: // referencia.cs using System; using System.Text; class Referencia { static void Main() { StringBuilder x = new StringBuilder("hola"); StringBuilder y = x; x.Append(", ¿estás aprendiendo mucho?"); Console.WriteLine("x = '{0}' y = '{1}'", x, y); } } En este caso StringBuilder es un tipo referencia, a diferencia de int que era un tipo valor. Cuando se declara x en el ejemplo anterior, realmente se están haciendo dos cosas a la vez: StringBuilder x; x = new StringBuilder("hola"); La primera linea declara x como un referencia a un objeto de tipo StringBuilder. La segunda crea un objeto de dicho tipo y le asigna a x su valor. StringBuilder y = x; Com esta linea también se llevan a cabo dos acciones diferentes: por un lado se crea una nueva referencia, y, a un objeto de tipo StringBuilder y por otro lado se hace que y apunte al
  • 8. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. mismo objeto al que x lo hace. Por este motivo al modificar x también se modifica y. Ambos comparten la misma representación interna de su valor. Los tipos object y string, asi como cualquier clase definida por nosotros pertenece a esta categoría de tipos. Parámetros de la línea de órdenes A un programa podemos pasarle parámetros a través de su línea de ordenes. La forma de acceder a ellos es a través de un array de tipo string en la función principal, Main: // param.cs using System; public class Parametros { public static void Main(string[] args) { // la longitud del array puede obtenerse a través de la propiedad Length // Length es una propiedad de sólo lectura del array args Console.WriteLine("Número de parámetros de la línea de órdenes = {0}", args.Length); for(int i = 0; i < args.Length; i++) { Console.WriteLine("Parámetro[{0}] = [{1}]", i, args[i]); } } } Este mismo ejemplo podría haberse creado utilizando foreach, que es estructura que permite crear un bucle sobre una colleción. // param2.cs using System; public class Parametros { public static void Main(string[] args) { // la longitud del array puede obtenerse a través de la propiedad Length // Length es una propiedad de sólo lectura del array args Console.WriteLine("Número de parámetros de la línea de órdenes = {0}", args.Length); foreach(string s in args)
  • 9. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. { Console.WriteLine(s); } } } Arrays Un array es una colección de objetos que se almacenan de forma consecutiva en un bloque de memoria. Para crear uno hemos de especificar el tipo de los elementos junto a [] y el nombre que deseemos darle. A continuación, y de forma opcional, podemos crearlo e inicializarlo. Veamos un ejemplo: char[] vocales = new char[5] {'a', 'e', 'i', 'o', 'u'} Esta línea declara un array de 5 elementos de tipo char y después lo inicializa con 5 valores. Para acceder a cada uno de los elementos del array utilizaremos el operador [] y el número de posición al que deseamos acceder, teniendo en cuenta que los elementos se empiezan a numerar desde 0. Console.WriteLine(vocales[2]); // imprime una "i" Una vez creado un array no puede modificar su longitud. Para conocer esta se puede utilizar la propiedad de sólo lectura Lenght. Existe un conjunto de colecciones mucho más complejas y versátiles dentro de System.Collection. Arrays multidimensionales Los arrays pueden tener más de una dimensión y entonces se clasifican en dos grupos: rectangulares y dentados. Los arrays rectangulares tienen una estructura multidimensional rectangular en la que cada dimensión posee siempre un mismo número de elementos. En cambio en los arrays dentados, lo que hay es un array de arrays, con lo cual cada subarray puede tener un tamaño diferente. // array rectagular int[,,] matriz1 = new int[3, 4, 5]; // cubo 3x4x5 // array dentado int[][][] matriz2 = new int[3][][]; // cubo 3x_x_ for (int i = 0; i < 3; ++i) { matriz2[i] = new int[4][]; for (int j = 0; j < 4; ++j) matriz2[i][j] = new int[5];
  • 10. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. } // acceso a un elemento matriz1[1,1,1] = matriz2[1][1][1] = 7; Para conocer el número de elementos de cada dimensión en los arrays multidimensionales rectangulared tendremos que utilizar el método GetLength(n), donde n es el número de dimensión cuyo tamaño deseamos conocer, también indexado desde 0. Para los arrays dentados en cambio, deberemos consultar el tamaño de cada subarray uno por uno. // getlenght.cs using System; public class Lenght { public static void Main() { // array rectagular int[,,] cubo = new int[3, 4, 5]; // array dentado int[][][] cosa = new int[3][][]; // for (int i = 0; i < cosa.Length; ++i) { cosa[i] = new int[i + 1][]; for (int j = 0; j < cosa[i].Length; ++j) cosa[i][j] = new int[i + j + 1]; } // imprime el tamaño de cada dimensión for(int i = 0; i < 3; ++i) Console.WriteLine("cubo.GetLength({0}) = {1}", i, cubo.GetLength(i)); Console.WriteLine("cosa.Length = {0}", cosa.Length); for(int i = 0; i < cosa.Length; ++i) { Console.WriteLine("cosa[{0}].Length = {1}", i, cosa[i].Length); for (int j = 0; j < cosa[i].Length; ++j) Console.WriteLine("cosa[{0}][{1}].Length = {2}", i, j, cosa[i][j].Length); } } } Inicialización de arrays
  • 11. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. Para inicializar un array hemos de añadir una lista de elementos entre llaves, {}, y separados por comas. int[] numeros = new int[10] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; int[,] array2x2 = new int[2,2] {{11, 12}, {21, 22}}; int[][] array2xn = new int[2][] {new int[] {11, 12}, new int[] {21, 22, 23}}; Algunos partes de esta sintaxis de inicialización pueden omitirse, de forma que las siguientes declaraciones son completamente equivalentes a las anteriores: int[] numeros = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; int[,] array2x2 = {{11, 12}, {21, 22}}; int[][] array2xn = {new int[] {11, 12}, new int[] {21, 22, 23}}; Paso de parámetros Paso de parámetros por valor Por defecto en C# los parámetros son pasados por valor, lo que implica crear una copia de una variable para poder pasársela a un método. // pasovalor.cs using System; public class PasoValor { static void Prueba(int i) { Console.WriteLine("i = {0}", ++i); } static void Main() { int x = 7; Prueba(x); // la función recibe una copia de x Console.WriteLine("x = {0}", x); // x sigue siendo 7 } } Paso de parámetros por referencia Si por algún motivo se necesita pasar una variable por referencia puede hacerse sin más que anteponer la palabra clave ref delante de la variabel correspondiente en la lista de parámetros
  • 12. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. de un método, tanto a la hora de definir el método como a la de utilizarlo. El paso de parámetros por referencia es fundamental cuando queremos modificar el valor de una variable o para hacer más eficiente el paso de grandes estructura de datos a un método. // ref.cs using System; public class PasoRef { static void Prueba(ref int i) { Console.WriteLine("i = {0}", ++i); } static void Main() { int x = 7; Prueba(ref x); // la función recibe una referencia de x Console.WriteLine("x = {0}", x); // x sigue cambia a 8 } } El modificador out Siguiendo con la línea de asegurar que una variable es asignada antes de utilizarse que C# promueve, out es un modificador que nos obliga a asignar un valor a una variable antes de finalizar un método. // out.cs using System; public class PasoOut { static void Separa(string entrada, out string nombre, out string apellido) { int i = entrada.LastIndexOf(' '); nombre = entrada.Substring(0, i); apellido = entrada.Substring(i + 1); } static void Main() { string nombre, apellido; Separa("José Pérez", out nombre, out apellido); Console.WriteLine("Nombre: {0} Apellido: {1}", nombre, apellido);
  • 13. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. } } El modificador params El modificador de parámetros params puede utilizarse en el último parámetro de cualquier método para indicar que dicho método acepta cualquier número de parámetros de ese tipo particular. De esta forma se pueden crear métodos con un número variable de parámetros. // params.cs using System; public class Params { static int Suma(params int[] n) { int total = 0; foreach(int i in n) total += i; return total; } static void Main() { int s = Suma(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); Console.WriteLine("0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 = {0}", s); } } Clases En C# un programa se crea mediante la definición de nuevos tipos. De hecho, en C# todos los tipos son clases. Cada nuevo tipo estará formado por un conjunto de datos y funciones. Veamos un ejemplo: // clase.cs using System; // declaración de la clase class Persona { // una variable que contendrá el nombre string nombre;
  • 14. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. // constructor: como inicializar un objeto de clase Persona public Persona(string nombre) { this.nombre = nombre; // this: una forma de acceder a este objeto } // propiedad: una forma de acceder al nombre de una persona public string Nombre { get { return nombre; } set { nombre = value; } // variable especial value } public static void Main() { Persona p = new Persona("Adán"); Console.WriteLine("p.Nombre = {0}", p.Nombre); p.Nombre = "Eva"; Console.WriteLine("p.Nombre = {0}", p.Nombre); } } La palabra clave this Esta palabra clave, this, nos permite referirnos a cualquier variable o método de la instancia de una clase en la que nos encontremos. También nos permite llamar a un construtor sobrecargado, y declarar o acceder a un indexador. Un uso muy común de la misma es distinguir entre un campo de una instancia de un objeto y un parámetro. public Persona(string nombre) { this.nombre = nombre; } Campos Los campos de una clase son los datos que esta contiene. En su forma más sencilla pueden ser una simple declaración de variable como: string nombre; que cada instancia de una clase contendrá. Podemos utilizar los modificadores static y readonly para alterar el comportamiento de un campo.
  • 15. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. A los campos no estáticos (por defecto) se les denomina variables de instancia y los campos estáticos variables de clase. Mediante el uso explícito de la palabra static hacemos que de una variable pase a haber una única copia compartida por todas las instancias de una clase. // static.cs using System; class Persona { static int contador; int id; public Persona() { id = contador++; } ~Persona() { contador--; } public int Contador { get { return contador; } } public int Id { get { return id; } } static void Main() { Persona p1 = new Persona(); Persona p2 = new Persona(); Console.WriteLine("Hay {0} personas", p1.Contador); Console.WriteLine("p2.Id() = {0}", p2.Id); } } El modificador readonly nos permite evitar que una variable sea modificada una vez que sea asignada. Al igual que una constante posee un valor invariable, pero este se calcula en tiempo de ejecución en vez de en tiempo de compilación. Las constantes tienen la ventaja de permitir realizar un mayor número de optimizaciones sobre ellas. En cambio las variables readonly, nos aportan un mayor grado de flexibilidad, pues pueden retrasar el calcular su valor hasta la ejecución del programa. Esto puede aportar ventajas a la hora de modificar su valor sin tener que recompilar el código para que el nuevo valor surta efecto, como a la hora de corregir un valor erróneo o simplemente actualizarlo. Propiedades
  • 16. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. Las son otros de los campos que pueden componer un objeto. Su función es controlar la forma en que se accede a los datos de un objeto escondiendo la representanción interna de los mismos. Las propiedades puede permitirnos acceder a un campo de un objeto de tres formas:  get: sólo lectura.  set: sólo escritura.  get y set: lectura y escritura. // propiedades.cs using System; class Persona { int nacimiento; // año de nacimiento public Persona(int nacimiento) { this.nacimiento = nacimiento; } public int Edad { get { return DateTime.Now.Year - nacimiento; } set { nacimiento = DateTime.Now.Year - value; } } static void Main() { Persona gustavo = new Persona(1973); Console.WriteLine("Gustavo tiene {0} años,", gustavo.Edad); gustavo.Edad = 31; Console.WriteLine("y el año que viene tendrá {0}", gustavo.Edad); } } Indexadores Los indexadores son una forma cómoda de acceder a una colección de objetos contenida dentro de una clase a través del uso de la sintaxis de los arrays. Al igual que las propiedades, permiten acceder a datos contenidos en un objeto, pero en vez de hacerlo a través de un nombre, lo hacen a través de un índice. Su forma de utilización también es similar. // indexador.cs using System; class Nota { float[] notas;
  • 17. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. public Nota(int alumnos) { notas = new float[alumnos]; } public float this[int indice] { get { return notas[indice]; } set { notas[indice] = value; } } public int Length { get { return notas.Length; } } public float Media { get { float suma = 0; foreach(float nota in notas) { suma += nota; } return suma / notas.Length; } } static void Main() { Nota n = new Nota(100); Random rand = new Random(); for (int i = 0; i < n.Length; ++i) { n[i] = 5 + rand.Next(6); Console.Write("{0}, ", n[i]); } Console.WriteLine(); Console.WriteLine("La nota media es: {0}", n.Media); } } Métodos Un método es un función o procedimiento definida en el interior de una clase. En C# todo el código se ejecuta como un método de alguna clase, pues todos los tipos que podemos usar son clases, e incluso, la función Main, es en realidad un método de alguna clase.
  • 18. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. Todo método tiene una firma (signature), que es el conjunto de tipos y modificadores de cada uno de los parámetros de su lista de parámetros. Dentro de una clase podemos tener diferentes métodos aunque tengan el mismo nombre. A esto se lo denomina sobrecarga de métodos. Podremos utilizar la sobrecarga siempre que la firma de los métodos que intentemos sobrecargar sea diferente, es decir, sus parámetros no tenga idénticos tipos y modificadores. Para la sobrecarga no se tiene en cuenta el tipo de retorno ni el modificador params. Este conjunto de métodos pueden darse a la vez en una clase: float Media(float a, float b); float Media(float a, int b); float Media(int a, float b); int Media(int a, int b); En cambio este otro conjunto métodos no: int ValorAbsoluto(int a); float ValorAbsoluto(int a); // error Constructores Los constructores son un tipo especial de métodos que poseen las clases y cuya finalidad es inicializar los campos de un objeto. Cada vez que se crea una nueva instancia de un objeto, el sistema le asigna la cantidad de espacio que necesite en el montículo ("heap") y acto seguido ejecuta el constructor de la clase para llevar a cabo la inicialización de todas los campos que lo requieran. A diferencia de otros métodos el constuctor no puede tener tipo de retorno ni tener otro nombre diferente del de la propia clase en que se define. class Persona { public Persona(... lista de parámetros ...) { ... código de inicialización ... } } Los constructores pueden sobrecargarse, de forma que podemos tener varios de ellos y hacer que antes de ejecutar el cuerpo de su método se ejecute otro utilizando this. class Persona { public string nombre; public Persona(string nombre) { this.nombre = nombre; }
  • 19. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. public Persona(): this("José Expósito") {} } Persona p1 = new Persona(); Persona p2 = new Persona("Antonio Pérez"); En caso de no definir de forma explícita un constructor, se creará uno de forma implícita sin parámetros que inicializará todas las variables a sus valores por defecto. Las asignaciones de valores presentes en las propias declaraciones de las variables se ejecutarán antes que los constructores, y además, en el mismo orden en que aparezcan. Esto se puede comprobar ejecutando el siguiente ejemplo: // inicializacion.cs using System; class Persona { public string nombre = "José Expósito"; public Persona(string nombre) { Console.WriteLine("antes del constructor nombre = {0}", this.nombre); this.nombre = nombre; Console.WriteLine("tras el constructor nombre = {0}", this.nombre); } public static void Main() { Persona p = new Persona("Pedro Castillo"); } } Estudiemos ahora como afecta el uso de la palabra clave static a la inicialización de una clase. Si la aplicamos al constructor, al igual que ocurria con la variables, tiene el efecto de hacer que el código que ejecuta sea compartido por todas las instancias de una clase. Este tipo de constructores se ejecutan antes de la creación de cualquier instancia de la clase, y por supuesto, esto sucede una única vez. Cada clase puede poseer un único constructor de este tipo y no puede tener parámetros. En el caso de las variables estáticas, como sucedía con las no estáticas, estas se inicializan antes de la llamada al constructor estático. En resumen, el orden de inicialización es: 1. variables estáticas 2. constructores estáticos 3. variables no estáticas 4. constructores no estáticos
  • 20. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. Destructores Los destructores son el equivalente de los constructores pero a la hora de deshacernos de la instancia de un objeto. Cada vez que el recolector de basura de C# decide eliminar un objeto de memoria, antes, ejecuta este método. A diferencia de los constructores es único (no puede se puede sobrecargar) y no podemos decidir cuando es llamado. Su nombre ha de estar formado por el símbolo ~ seguido del nombre de la clase. class Persona { public Persona( ... parámetros ... ) { ... código del constructor ... } ~Persona() { ... código del constructor ... } } Clases anidadas Una clase anidada es una clase decladara dentro del ámbito de otra. El anidamiento de clases nos proporciona tres beneficios:  Una clase anidada puede acceder a cualquier miembro del la clase que lo contiene, independiemtemente de los modificadores de acceso que este posea.  Una clase anidada puede ser ocultada, si interesa, mediante el uso de modificadores de acceso.  Para acceder a una clase anidada desde fuera de la clase que la engloba habremos de utilizar el nombre de la clase que la engloba. // anidada.cs using System; class A { private int x = 3; // miembro privado (acceso por defecto) protected internal class Anidada { public void Prueba() { A a = new A(); Console.WriteLine(a.x); // podemos acceder a miembros privados } } }
  • 21. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. class B { static void Main() { A.Anidada anidada = new A.Anidada() anidada.Prueba(); } } Herencia Una clase puede herendar de otra para extender o particularizar a la clase original. Heredar de una clase nos permite reutilizar su funcionalidad sin tener que comenzar desde cero. Una clase sólo puede heredar de otra, pero en cambio no hay límite a número de descendientes que pueda tener. Todas las clases forman parte de una jerarquía única de clases cuya raiz es la clase Object. Una jerarquía de clases bien diseñada se caracteriza por generalizar, de forma razonable, los nombres del espacio de un problema. De esta forma, podriamos tener una jerarquía de figuras geométricas con la siguiente estructura: class Figura {} class Rectangulo: Figura {} class Cuadrado: Rectangulo {} class Elipse: Figura {} class Circulo: Elipse {} Veamos como podemos utilizar la herencia para reutilizar código y datos de la clase Figura en las clases Rectangulo y Cuadrado: // figura.cs using System; class Figura // implicitamente hereda de Object { float alto, ancho; public Figura(float alto, float ancho) { this.alto = alto; this.ancho = ancho; } public float Alto { get { return alto; } set { alto = value; } } public float Ancho { get { return ancho; } set { ancho = value; } }
  • 22. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. public void Mostrar() { Console.WriteLine("{0}: {1}x{2}", GetType(), Alto, Ancho); } } class Rectangulo: Figura // hereda de Figura { public Rectangulo(float alto, float ancho): base(alto, ancho) {} } class Cuadrado: Rectangulo // hereda de Rectangulo { public Cuadrado(float lado): base(lado, lado) {} public float Lado { get { return alto; } set { alto = ancho = value; } } } class Prueba { public static void Main() { Figura f = new Figura(1, 2); f.Mostrar(); Rectangulo r = new Rectangulo(3, 4); r.Mostrar(); Console.WriteLine("alto de r = {0}", r.Alto); Cuadrado c = new Cuadrado(5); c.Mostrar(); Console.WriteLine("Lado de c = {0}", c.Lado); } } Del anterior ejemplo debemos destacar varios aspectos:  Aunque no se indique explicitamente, todas las clases heredad de la clase Object.  Para hacer que una clase herede de otra debemos utilizar ":" (dos puntos) y el nombre de la clase de la que queremos heredar después de la declaración del nombre de la clase.  Se puede utilizar la palabra reservada base para referirnos al constructor de la clase de la que hemos heredado, de forma parecida a como utilizabamos this para referirnos al de la propia clase.  Como podemos ver en el ejemplo anterior, las clases derivadas de Figura, heredan tanto sus campos como sus métodos. Conversión de clases
  • 23. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. Las variables de una clase pueden convertirse a otro tipo del que han heredado ("upcast") o convertirse en un tipo que ha heredado de él ("downcast"). En caso de fallar un conversión a un tipo derivado, se lanzará un excepción de tipo InvalidCastException. Cuadrado c = new Cuadrado(5); Figura f = c; // upcast c = (Cuadrado)f; // downcast El operador as asiga null a una variable en caso de fallar una conversión a un tipo padre: c = f as Cuadrado; El operador is sirve para comprobar cuando un objeto deriva de un cierta clase o implementa un interfaz. Suele utilizarse antes de realizar una conversión a un tipo derivado. if (f is Cuadrado) ((Cuadrado)f).Lado = 5; else { f.Alto = 5; f.Ancho = 5; } Polimorfismo El polimorfismo es la habilidad para relizar una misma operación sobre tipos diferentes mientras estos compartan una serie de características comunes. Esto se puede conseguir mediante la herencia o bien implementado un interfaz. Veamos un ejemplo de clase, Polimorfismo, que utiliza el polimorfismo para realizar un operación sobre diferentes tipos: class Polimorfismo { public static void Mostrar(Figura f) { Console.Write("usando polimorfismo para mostrar: "); f.Mostrar(); } public static void Main() { Figura[] figuras = new Figura[3]; figuras[0] = new Figura(1, 2); figuras[1] = new Rectangulo(3, 4); figuras[2] = new Cuadrado(5);
  • 24. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. foreach (Figura f in figuras) { Mostrar(f); } } } Métodos virtuales Un aspecto clave del polimorfismo es la capacidad de cada tipo para relizar una acción de una forma particular. Las clases base pueden tener métodos virtules que permitan a las clases derivadas proporcionar su propia implementación de un método. En la clase base hemos de utilizar la palabra clave virtual en el método que deseemos particularizar en una clase derivada. Después, en la clase derivada tendremos que utilizar override para indicar que vamos a proporcionar una nueva implementación de un método. Utilizando el mismo ejemplo anterior, ahora implementaremos los métodos que nos muestren la fórmula para calcular el área de una Elipse y un Circulo: class Elipse: Figura { ... public virtual string FormulaArea() { return "RadioMayor * RadioMenor * PI"; } ... } class Cuadrado: Elipse { ... public override string FormulaArea() { return "Radio^2 * PI"; } ... } Clases y métodos abstractos Un método abstracto es un método sin implementación. Implicitamente es un método virtual que estamos obligados a sobrecargar en una clase derivada. Estos métodos sólo pueden aparecer en un clase abstracta. En ambos casos hemos de utilizar la palabra clave abstract para hacer abstracto un método o una clase. Las clases abstracta no pueden ser instanciadas, ni tampoco las que deriven de ellas sin proporcionar un implementación para todos los métodos que carezcan de ella. Veamos un ejemplo que nos permita definir un método que devuleva el área de un figura geométrica:
  • 25. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. // abstrac.cs abstract class Figura { ... public abstract float Area(); ... } class Rectangulo: Figura { ... public override float Area() { return Alto * Ancho; } ... } class Abstract { public static Main() { Figura[] figuras = new Figura[3]; figuras[0] = new Figura(1, 2); // error, clase abstracta figuras[1] = new Rectangulo(3, 4); // ok figuras[2] = new Cuadrado(5); // ok, hereda Area() foreach (Figura f in figuras) { Console.WriteLine("El área de un {0} de {1}x{2} es {3}", f.GetType(), f.Alto, f.Ancho, f.Area()); } } } Clases y métodos "sellados" Una clase puede evitar que otras deriven de ella empleando el modificador sealed en su declaración. sealed class Math { ... } Existen dos razones para sellar una clase:  Es una clase compuesta exclusivamente de miembros estáticos, como Math.  El uso de sealed permite al compilador realizar llamadas a métodos no virtuales sobre la clase sellada, que son más rápidas que las llamadas a métodos virtuales.
  • 26. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. De la misma forma podemos sellar un método virtual de forma que podemos asegurar su comportamiento al no permitir que pueda ser sobrecargado posteriormente en una clase derivada. Modificadores de acceso Para favorecer la encapsulación (esconder la implementación de un objeto que no comtribuye a sus características esnciales) una clase o sus componentespueden controlar quien puede acceder a ellos:  public: un tipo o miembro de un tipo es completamente accesible. Este es el tipo de acceso por defecto de enumeraciones e interfaces.  internal: un tipo o miembro de un tipo dentro de un ensamblaje sólo es accesible desde el interior de dicho ensamblaje. Este es el tipo de acceso por defecto para cualquier tipo, y por tanto puede ser omitido.  private: un miembro de un tipo sólo es accesible desde el interior de dicho tipo. Este es el tipo de acceso por defecto para los miembros de una clase o una estructura, y por lo tanto, puede ser omitido.  protected: un miembro de un tipo sólo es accesible desde el interior de dicho tipo y de los tipos que de él deriven.  protected internal: el miembro de una clase C dentro de un ensamblaje E es accesible desde el interior de la clase C, las clases que derivan de C y desde el interior del ensamblaje E. Estructuras Una estructura es similar a una clase. Se declaran utilizando la palabra clave struct. Las principales diferencias con una clase son:  Una clase es un tipo referencia mientras que una estructura es un tipo valor. En consecuencia, las estructuras suelen utilizarse para declarar tipos simples en que la semántica de tipo-valor sea deseable.  Una estructura no puede heredar de una clase ni de otra estructura. Tampoco puede ser la base de una clase. Sin embargo, heredan de la clase object. Al igual que las clases, las estructuras pueden implementar interfaces.  Las clases pueden tener destructores, pero las estructuras no.  Las clases pueden tener constructores sin parámetros y además inicializar los campos de una instancia, y en cambio, una estructura no. El constructor por defecto sin parámetros de las estructuras inicializa cada campo con el valor por defecto que le
  • 27. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. corresponda, y si declara un constructor, a todos los campos debe asignarsele un valor. // struct1.cs using System; struct SimpleStruct { private int xval; public int X { get { return xval; } set { if (value < 100) xval = value; } } public void DisplayX() { Console.WriteLine("El valor almacenado es: {0}", X); } } class TestClass { public static void Main() { SimpleStruct ss = new SimpleStruct(); ss.X = 5; ss.DisplayX(); } } A causa de que son tipos valor, cuando son pasados a un método, se pasan por valor en lugar de por referencia como ocurre con las clases. // struct2.cs using System; class TheClass { public int x; } struct TheStruct { public int x; } class TestClass {
  • 28. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. public static void structtaker(TheStruct s) { s.x = 5; } public static void classtaker(TheClass c) { c.x = 5; } public static void Main() { TheStruct a = new TheStruct(); TheClass b = new TheClass(); a.x = 1; b.x = 1; structtaker(a); classtaker(b); Console.WriteLine("a.x = {0}", a.x); Console.WriteLine("b.x = {0}", b.x); } } Podemos utilizar los atributos StructLayout(LayoutKind.Explicit) and FieldOffset para indicar como deben colocarse en memoria los diferentes campos de una estructura. De esta forma podemos conseguir el equivalente de una union de C/C++. using System.Runtime.InteropServices; [StructLayout(LayoutKind.Explicit)] struct PosicionExplicita { [FieldOffset(0)] public byte b0; [FieldOffset(1)] public byte b1; [FieldOffset(2)] public byte b2; [FieldOffset(3)] public byte b3; [FieldOffset(0)] public int i0; [FieldOffset(1)] public int i1; [FieldOffset(0)] public long l; }
  • 29. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. Interfaces Un interfaz nos permite hacer que múltiles clases compartan ciertas características no presentes en una clase base. Un interfaz tiene cierto parecido a una clase, pero con diferencias significaticas:  Un interfaz proporciona un especificación en lugar de una implementación de sus miembros. Es algo parecido a una clase abstracta pura, que es una clase compuesta únicamente de métodos abstractos.  Cualquier clase o estructura pueden implementar varios imterfaces, pero sólo pueden heredar de una única clase. Anteriormente describimos el polimorfismo como la habilidad para realizar una misma operación sobre un conjunto de tipos diferentes mientras estos compartiesen ciertas características comunes. El propósito de un interfaz es precisamente definir un conjunto de características. Estas características pueden ser:  Métodos  Propiedades  Indexadores  Eventos La declaración de un interfaz es como la de una clase, salvo por que no se proporciona implementación para sus miembros. La intención es que dichos miembros sean implementados por las clases o estructuras que deriven de un interfaz. interface Dibujable { void Dibujar(); } Para implementar un interfaz, hemos de hacer como cuando utilizabamos la herencia, indicar en la declaración de una clase o estructura que se deriva de él, y después implementar los métodos del interfaz. Si la clase o estructura también hereda de una clase base, habremos de colocarla al principio de la lista. class Rectangulo: Figura, Dibujable { public void Dibujar() { if (Alto > 0) { string s = ""; for (int x = 0; x < Ancho; ++x)
  • 30. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. s += "[]"; Console.WriteLine(s); if (Alto > 2) { for (int y = 0; y < Alto - 2; ++y) { s = "[]"; for (int x = 0; x < Ancho - 2; ++x) s += " "; if (Ancho > 1) s += "[]"; Console.WriteLine(s); } } if (Alto > 1) { s = ""; for (int x = 0; x < Ancho; ++x) s += "[]"; Console.WriteLine(s); } } } } Al igual que ocurria en la herencia, podremos extender un interfaz. Con ello lograremos crear un nuevo interfaz que posea más características que aquel del que deriva. interface Dibujable { void Dibujar(); } interface EsDibujable: Dibujable { bool PuedeDibujarse { get; } } Puede darse el caso en que en una misma clase o estructura se cree un conflito de nombres al intentar heredar de una clase base y un interfaz un método o propiedad con el mismo nombre. Para resolver este problema hemos de C# permite implementar explicitamente al menos uno de los miembros del interfaz que generan el conflito. Veamos un ejemplo: interface Figura { void Dibujar(); }
  • 31. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. interface Dibujable { void Dibujar(); } class Rectangulo: Figura, Dibujable { void Figura.Dibujar() { ... código ... } void dibujable.Dibujar() { ... código ... } } Para acceder ahora a cualquiera de estos métodos habremos de realizar una conversión al tipo de interfaz adecuado de la siguiente forma: Rectangulo r = new Rectangulo(2, 3); Figura f = (Figura)r; Dibujable d = (Dibujable)r; r.Dibujar(); d.Dibujar(); Enumeraciones Las enumeraciones permiten crear un grupo de constantes numericas asociadas a un nombre. Veamos un ejemplo: public enum Rumbo {Norte, Sur, Este, Oeste}; Para utilizarlas tenemos que declarar una variable del tipo de la enumeración y asignarle un valor dentro de los que dicha enumeración posea. Rumbo avion = Rumbo.Sur; Por defecto, a cada valor de la enumeración se le asigna como valor una constante entera 0, 1, 2,... Opcionalmente se puede especificar un tipo numérico alternativo y, además, asignarle un valor de este tipo a cada uno de los componentes. [Flags] public enum Rumbo: byte {Norte = 1, Sur = 2, Este = 4, Oeste = 8}; Rumbo barco = Rumbo.Norte | Rumbo.Oeste; if ((barco & Rumbo.Norte) != 0) Console.WriteLine("Si vas hacia el Norte hará más frio");
  • 32. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. El atributo [FLAGS] es opcional e informa al entorno de ejecución de que los valores de la enumeración pueden ser combinados, y deberán ser decodificados adecuadamente en el depurador y cuando se muestren por la consola. Console.WriteLine(barco.Format()); // muestra "Norte|Oeste" Console.WriteLine(barco); // muestra "9" El tipo System.Enum proporciona una gran cantidad de métodos estáticos muy útilies para manejar las enumeraciones: // enum.cs using System; public enum Logico : byte { Off = 0, On = 1 }; class Prueba { public static void Main() { Type t = Enum.GetUnderlyingType(typeof(Logico)); Console.WriteLine(t); // imprime "Byte"; bool hay_medio = Enum.IsDefined(typeof(Logico), "Medio"); Console.WriteLine(hay_medio); // imprime "False" Logico l = (Logico)Enum.Parse(typeof(Logico), "On"); Console.WriteLine(Enum.Format(typeof(Logico), l, "D")); // imprime "1" Console.WriteLine(l); // imprime "On" foreach(Logico logico in Enum.GetValues(typeof(Logico))) Console.WriteLine("{0} = {1}", logico, Enum.Format(typeof(Logico), logico, "D")); } } Sobrecarga de operadores La sobrecarga de operadores permite a especificar la implementación de operador siempre que uno o los dos operandos sean clases definidas por el usuario o una estructura. Los operadores son métodos, cuya sintaxis es un tanto especial. La lista de operadores sobrecargables es: +, -, !, ~, ++, --, /, %, &, |, ^, <<, >>, ==, !=, <, >, <=, >=. Veamos en primer lugar un ejemplo que permite implementar la operación de suma sobre los números complejos: // complex.cs
  • 33. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. using System; public struct Complex { public int real; public int imaginary; public Complex(int real, int imaginary) { this.real = real; this.imaginary = imaginary; } // sobrecarga del operador de suma public static Complex operator +(Complex c1, Complex c2) { return new Complex(c1.real + c2.real, c1.imaginary + c2.imaginary); } // sobrecarga del método "ToString" public override string ToString() { return(String.Format("{0} + {1}i", real, imaginary)); } public static void Main() { Complex num1 = new Complex(2,3); Complex num2 = new Complex(3,4); // suma de dos números complejos utilizando el // operador de suma que hemos sobrecargado Complex sum = num1 + num2; // impresión de tres números complejos Console.WriteLine("First complex number: {0}",num1); Console.WriteLine("Second complex number: {0}",num2); Console.WriteLine("The sum of the two numbers: {0}",sum); } } Excepciones Las excepciones son objetos que contienen información representando la ocurrencia de un estado excepcional en un programa. Cuando sucede un evento en un programa que produce un estado de excepción, como una divisón por cero, se lanza una excepción para avisar de dicho suceso.
  • 34. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. // exception.cs using System; class Exception { public static void Main() { int v0 = 0; int v1 = 1; v1 = v1 / v0; } } Para manejar excepciones se utilizan las palabras reservadas try,catch y finally. El bloque try tiene dos propósitos: permitir a u n bloque catch capturar un excepción y asegurar que se ejecutará el bloque finally. Un bloque try debe estar seguido por un o más bloques catch y finally. try { código que sospechamos que pueda lanzar una excepción } catch (TipoDeException1 e) { código para reaccionar a excepciones de tipo TipoDeException1 } catch (TipoDeException2 e) { código para reaccionar a excepciones de tipo TipoDeException2 } ... catch (TipoDeExceptionN e) { código para reaccionar a excepciones de tipo TipoDeExceptionN } finally { código que se ejecuta siempre después de try, tanto si se lanza una excepción como si no } La acción por defecto cuando se lanza una excepción y esta no es adecauadamente tratada dentro de un bloque catch es abortar el programa, que es lo que sucede en el ejemplo exeception.cs. Veamos como podemos resolver esta situación: // exception2.cs using System;
  • 35. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. class Exception { public static void Main() { int v0 = 0; int v1 = 1; try { v1 = v1 / v0; } catch (DivideByZeroException exception) { Console.WriteLine("Excepción: {0}", exception.Message); } finally { Console.WriteLine("Supongo que ya se ha resulto el problema, ¿no?"); } } } Para poder atrapar una excepción dentro de un bloque catch, esta debe ser de tipo System.Exception o derivar de este. Las excepciones de tipo System.Exception son las más generales posibles. Normalmente intentaremos atrapar excepciones de algún tipo más específico que nos permita saber más acerca de la excepción lanzada y así tener más medios para resolver la situación. A la hora de crear una clase podemos preveer que tipo de errores pueden darse y derivar tipos de excepciones de para intentar resolver dichos errores. Nosotros podemos lanzar explícitamente una excepción mediante la palabra reservada try. Algunas de las excepciones más comunes y por ello ya definidas son: System.OutOfMemoryException System.NullReferenceException Syste.InvalidCastException Syste.ArrayTypeMismatchException System.IndexOutOfRangeException System.ArithmeticException System.DevideByZeroException System.OverFlowException En una cláusula catch puede omitirse tanto la variable de la excepción si no va a utilizarse, como el parámetro con el tipo de excepción completo, con lo cual se atrapará cualquier tipo de excepción. // exception3.cs using System;
  • 36. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B. class Exception { public static void Main() { int[] array = {1, 2, 3}; try { for (int i = 0; i < 5; ++i) Console.WriteLine("array[{0}] = {1}", i, array[i]); } catch (OutOfMemoryException e) { Console.WriteLine("Excepción: {0}", e.Message); } catch (IndexOutOfRangeException e) { Console.WriteLine("Excepción: {0}", e.Message); } catch { Console.WriteLine("Excepción general"); } finally { Console.WriteLine("Supongo que ya se ha resulto el problema, ¿no?"); } } } La estructura jerárquica del sistema de excepciones que declaremos condicionará el orden en estas puedan ser utilizadas tras un bloque try. No se puede intentar atrapar una excepción de un tipo derivado de otro que se ha intentado atraparse en una cláusula previa. Veamos un ejemplo válido y otro que no lo es: Uso válido Error try { ... } catch (Exception3) { ... } catch (Exception2) { ... } catch (Exception1) { ... } catch { ... } finally { ... } try { ... } catch { ... } catch (Exception1) { ... } catch (Exception2) { ... } catch (Exception3) { ... } finally { ... } La clase System.Exception tiene algunas propiedades muy útiles de las que cabe destacar:  Message: Cadena con la descripción del error.
  • 37. Pontificia Universidad Católica del Ecuador Mtr. Luis Fernando Aguas B.  StackTrace: Cadena con todos los métodos llamados desde el origen de la excepción hasta el bloque catch. // exception4.cs using System; class Prueba { public static void Main() { int v0 = 0; int v1 = 1; try { v1 = v1 / v0; } catch (DivideByZeroException exception) { Console.WriteLine("exception.Message: {0}", exception.Message); Console.WriteLine("exception.StackTrace: {0}", exception.StackTrace); } finally { Console.WriteLine("¡Ya eres un experto en manejo de excepciones!"); } } }