Lenguajes de Programación: Tutorial csharp

of 37/37
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;
  • date post

    13-Jan-2017
  • Category

    Design

  • view

    61
  • download

    4

Embed Size (px)

Transcript of Lenguajes de Programación: Tutorial csharp

  • Pontificia Universidad Catlica del Ecuador

    Mtr. Luis Fernando Aguas B.

    Tutorial Csharp

    Variables y Constantes

    Una variable o una constante representan un posicin de memoria ocupada por un tipo de

    dato. Una varible puede ser local, el parmetro de un mtodo, el elemento de un array, un

    campo de una instancia de un objeto o un campo esttico 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 asignacin de valor puede ser tanto explcita como automtica a travs de la asignacin

    del valor por defecto para un tipo. Estos son los valores por defecto para los diferentes tipos:

    Tipo Valor por defecto

    tipos numricos 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 Catlica 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 lgica ciertas

    porciones de cdigo de forma que se les asocia un nombre para su uso. Si no utilizamos

    explcitamente ningn espacio de nombres estaremos utilizando el espacio de nombres

    global, como se hace en el primer ejemplo holamundo.cs. Veamos ahora como utilizar

    explcitamente 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 sern 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 Catlica del Ecuador

    Mtr. Luis Fernando Aguas B.

    namespace Espacio1 // declaracin del espacio de nombres

    Espacio1

    {

    public class Prueba

    {

    public Prueba()

    {

    Console.WriteLine("Espacio1.Prueba");

    }

    }

    }

    namespace Espacio2 // declaracin 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 ms que encerrara la declaracin 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 Catlica 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 podra 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

    declaracin.

    // 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 guin 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 Catlica 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 maysculas y

    minsculas 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 Catlica 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 mtodo 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 categoras, 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 ms 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

    caractersticas 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 Catlica 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 travs de structs pertenecen a esta categora.

    Tipos referencia

    Los tipos referencia son algo ms 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(", ests 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 estn 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 tambin 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 Catlica del Ecuador

    Mtr. Luis Fernando Aguas B.

    mismo objeto al que x lo hace. Por este motivo al modificar x tambin

    se modifica y. Ambos comparten la misma representacin interna de su valor.

    Los tipos object y string, asi como cualquier clase definida por nosotros pertenece a esta

    categora de tipos.

    Parmetros de la lnea de rdenes

    A un programa podemos pasarle parmetros a travs de su lnea de ordenes. La forma de

    acceder a ellos es a travs de un array de tipo string en la funcin principal, Main:

    // param.cs

    using System;

    public class Parametros

    {

    public static void Main(string[] args)

    {

    // la longitud del array puede obtenerse a travs de la propiedad Length

    // Length es una propiedad de slo lectura del array args

    Console.WriteLine("Nmero de parmetros de la lnea de rdenes = {0}",

    args.Length);

    for(int i = 0; i < args.Length; i++)

    {

    Console.WriteLine("Parmetro[{0}] = [{1}]", i, args[i]);

    }

    }

    }

    Este mismo ejemplo podra haberse creado utilizando foreach, que es estructura que permite

    crear un bucle sobre una collecin.

    // param2.cs

    using System;

    public class Parametros

    {

    public static void Main(string[] args)

    {

    // la longitud del array puede obtenerse a travs de la propiedad Length

    // Length es una propiedad de slo lectura del array args

    Console.WriteLine("Nmero de parmetros de la lnea de rdenes = {0}",

    args.Length);

    foreach(string s in args)

  • Pontificia Universidad Catlica del Ecuador

    Mtr. Luis Fernando Aguas B.

    {

    Console.WriteLine(s);

    }

    }

    }

    Arrays

    Un array es una coleccin 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 continuacin, y de forma opcional, podemos crearlo e

    inicializarlo. Veamos un ejemplo:

    char[] vocales = new char[5] {'a', 'e', 'i', 'o', 'u'}

    Esta lnea declara un array de 5 elementos de tipo char y despus lo inicializa con 5 valores.

    Para acceder a cada uno de los elementos del array utilizaremos el operador [] y el nmero

    de posicin 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 slo lectura Lenght. Existe un conjunto de colecciones mucho ms complejas

    y verstiles dentro de System.Collection.

    Arrays multidimensionales

    Los arrays pueden tener ms de una dimensin y entonces se clasifican en dos grupos:

    rectangulares y dentados. Los arrays rectangulares tienen una estructura multidimensional

    rectangular en la que cada dimensin posee siempre un mismo nmero de elementos. En

    cambio en los arrays dentados, lo que hay es un array de arrays, con lo cual cada subarray

    puede tener un tamao 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 Catlica del Ecuador

    Mtr. Luis Fernando Aguas B.

    }

    // acceso a un elemento

    matriz1[1,1,1] = matriz2[1][1][1] = 7;

    Para conocer el nmero de elementos de cada dimensin en los arrays multidimensionales

    rectangulared tendremos que utilizar el mtodo GetLength(n), donde n es el nmero de

    dimensin cuyo tamao deseamos conocer, tambin indexado desde 0. Para los arrays

    dentados en cambio, deberemos consultar el tamao 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 tamao de cada dimensin

    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);

    }

    }

    }

    Inicializacin de arrays

  • Pontificia Universidad Catlica del Ecuador

    Mtr. Luis Fernando Aguas B.

    Para inicializar un array hemos de aadir 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 inicializacin 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 parmetros

    Paso de parmetros por valor

    Por defecto en C# los parmetros son pasados por valor, lo que implica crear una copia de

    una variable para poder pasrsela a un mtodo.

    // 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 funcin recibe una copia de x

    Console.WriteLine("x = {0}", x); // x sigue siendo 7

    }

    }

    Paso de parmetros por referencia

    Si por algn motivo se necesita pasar una variable por referencia puede hacerse sin ms que

    anteponer la palabra clave ref delante de la variabel correspondiente en la lista de parmetros

  • Pontificia Universidad Catlica del Ecuador

    Mtr. Luis Fernando Aguas B.

    de un mtodo, tanto a la hora de definir el mtodo como a la de

    utilizarlo. El paso de parmetros por referencia es fundamental cuando queremos modificar

    el valor de una variable o para hacer ms eficiente el paso de grandes estructura de datos a

    un mtodo.

    // 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 funcin recibe una referencia de x

    Console.WriteLine("x = {0}", x); // x sigue cambia a 8

    }

    }

    El modificador out

    Siguiendo con la lnea 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 mtodo.

    // 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 Prez", out nombre, out apellido);

    Console.WriteLine("Nombre: {0} Apellido: {1}", nombre, apellido);

  • Pontificia Universidad Catlica del Ecuador

    Mtr. Luis Fernando Aguas B.

    }

    }

    El modificador params

    El modificador de parmetros params puede utilizarse en el ltimo parmetro de cualquier

    mtodo para indicar que dicho mtodo acepta cualquier nmero de parmetros de ese tipo

    particular. De esta forma se pueden crear mtodos con un nmero variable de parmetros.

    // 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 definicin 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;

    // declaracin de la clase

    class Persona

    {

    // una variable que contendr el nombre

    string nombre;

  • Pontificia Universidad Catlica 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("Adn");

    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 mtodo de la instancia

    de una clase en la que nos encontremos. Tambin nos permite llamar a un construtor

    sobrecargado, y declarar o acceder a un indexador. Un uso muy comn de la misma es

    distinguir entre un campo de una instancia de un objeto y un parmetro.

    public Persona(string nombre)

    {

    this.nombre = nombre;

    }

    Campos

    Los campos de una clase son los datos que esta contiene. En su forma ms sencilla pueden

    ser una simple declaracin 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 Catlica del Ecuador

    Mtr. Luis Fernando Aguas B.

    A los campos no estticos (por defecto) se les denomina variables de

    instancia y los campos estticos variables de clase. Mediante el uso explcito 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 ejecucin en vez de en tiempo de compilacin. Las constantes tienen la ventaja de permitir

    realizar un mayor nmero 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

    ejecucin del programa. Esto puede aportar ventajas a la hora de modificar su valor sin tener

    que recompilar el cdigo para que el nuevo valor surta efecto, como a la hora de corregir un

    valor errneo o simplemente actualizarlo.

    Propiedades

  • Pontificia Universidad Catlica del Ecuador

    Mtr. Luis Fernando Aguas B.

    Las son otros de los campos que pueden componer un objeto. Su

    funcin es controlar la forma en que se accede a los datos de un objeto escondiendo la

    representancin interna de los mismos. Las propiedades puede permitirnos acceder a un

    campo de un objeto de tres formas:

    get: slo lectura.

    set: slo escritura.

    get y set: lectura y escritura.

    // propiedades.cs

    using System;

    class Persona

    {

    int nacimiento; // ao 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} aos,", gustavo.Edad);

    gustavo.Edad = 31;

    Console.WriteLine("y el ao que viene tendr {0}", gustavo.Edad);

    }

    }

    Indexadores

    Los indexadores son una forma cmoda de acceder a una coleccin de objetos contenida

    dentro de una clase a travs 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 travs de un

    nombre, lo hacen a travs de un ndice. Su forma de utilizacin tambin es similar.

    // indexador.cs

    using System;

    class Nota

    {

    float[] notas;

  • Pontificia Universidad Catlica 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);

    }

    }

    Mtodos

    Un mtodo es un funcin o procedimiento definida en el interior de una clase. En C# todo el

    cdigo se ejecuta como un mtodo de alguna clase, pues todos los tipos que podemos usar

    son clases, e incluso, la funcin Main, es en realidad un mtodo de alguna clase.

  • Pontificia Universidad Catlica del Ecuador

    Mtr. Luis Fernando Aguas B.

    Todo mtodo tiene una firma (signature), que es el conjunto de tipos

    y modificadores de cada uno de los parmetros de su lista de parmetros.

    Dentro de una clase podemos tener diferentes mtodos aunque tengan el mismo nombre. A

    esto se lo denomina sobrecarga de mtodos. Podremos utilizar la sobrecarga siempre que la

    firma de los mtodos que intentemos sobrecargar sea diferente, es decir, sus parmetros no

    tenga idnticos tipos y modificadores. Para la sobrecarga no se tiene en cuenta el tipo de

    retorno ni el modificador params.

    Este conjunto de mtodos 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 mtodos no:

    int ValorAbsoluto(int a);

    float ValorAbsoluto(int a); // error

    Constructores

    Los constructores son un tipo especial de mtodos 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 montculo ("heap") y acto

    seguido ejecuta el constructor de la clase para llevar a cabo la inicializacin de todas los

    campos que lo requieran. A diferencia de otros mtodos 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 parmetros ...)

    {

    ... cdigo de inicializacin ...

    }

    }

    Los constructores pueden sobrecargarse, de forma que podemos tener varios de ellos y hacer

    que antes de ejecutar el cuerpo de su mtodo se ejecute otro utilizando this.

    class Persona

    {

    public string nombre;

    public Persona(string nombre) { this.nombre = nombre; }

  • Pontificia Universidad Catlica del Ecuador

    Mtr. Luis Fernando Aguas B.

    public Persona(): this("Jos Expsito") {}

    }

    Persona p1 = new Persona();

    Persona p2 = new Persona("Antonio Prez");

    En caso de no definir de forma explcita un constructor, se crear uno de forma implcita sin

    parmetros que inicializar todas las variables a sus valores por defecto.

    Las asignaciones de valores presentes en las propias declaraciones de las variables se

    ejecutarn antes que los constructores, y adems, 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 Expsito";

    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 inicializacin de una

    clase. Si la aplicamos al constructor, al igual que ocurria con la variables, tiene el efecto de

    hacer que el cdigo que ejecuta sea compartido por todas las instancias de una clase. Este

    tipo de constructores se ejecutan antes de la creacin 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 parmetros. En el caso de las variables estticas, como suceda con las

    no estticas, estas se inicializan antes de la llamada al constructor esttico. En resumen, el

    orden de inicializacin es:

    1. variables estticas 2. constructores estticos 3. variables no estticas 4. constructores no estticos

  • Pontificia Universidad Catlica 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 mtodo. 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 smbolo ~ seguido del nombre de la clase.

    class Persona

    {

    public Persona( ... parmetros ... ) { ... cdigo del constructor ... }

    ~Persona() { ... cdigo 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 Catlica 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 slo puede heredar de otra, pero en cambio no hay lmite a nmero de descendientes

    que pueda tener. Todas las clases forman parte de una jerarqua nica de clases cuya raiz es

    la clase Object. Una jerarqua de clases bien diseada se caracteriza por generalizar, de forma

    razonable, los nombres del espacio de un problema. De esta forma, podriamos tener una

    jerarqua de figuras geomtricas 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 cdigo 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 Catlica 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 despus de la declaracin 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 mtodos.

    Conversin de clases

  • Pontificia Universidad Catlica 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 conversin a un tipo derivado, se lanzar un excepcin 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 conversin 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 conversin 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 operacin sobre tipos diferentes

    mientras estos compartan una serie de caractersticas 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 operacin 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 Catlica del Ecuador

    Mtr. Luis Fernando Aguas B.

    foreach (Figura f in figuras)

    {

    Mostrar(f);

    }

    }

    }

    Mtodos virtuales

    Un aspecto clave del polimorfismo es la capacidad de cada tipo para relizar una accin de

    una forma particular. Las clases base pueden tener mtodos virtules que permitan a las clases

    derivadas proporcionar su propia implementacin de un mtodo. En la clase base hemos de

    utilizar la palabra clave virtual en el mtodo que deseemos particularizar en una clase

    derivada. Despus, en la clase derivada tendremos que utilizar override para indicar que

    vamos a proporcionar una nueva implementacin de un mtodo. Utilizando el mismo ejemplo

    anterior, ahora implementaremos los mtodos que nos muestren la frmula 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 mtodos abstractos

    Un mtodo abstracto es un mtodo sin implementacin. Implicitamente es un mtodo virtual

    que estamos obligados a sobrecargar en una clase derivada. Estos mtodos slo pueden

    aparecer en un clase abstracta. En ambos casos hemos de utilizar la palabra clave abstract

    para hacer abstracto un mtodo o una clase. Las clases abstracta no pueden ser instanciadas,

    ni tampoco las que deriven de ellas sin proporcionar un implementacin para todos los

    mtodos que carezcan de ella. Veamos un ejemplo que nos permita definir un mtodo que

    devuleva el rea de un figura geomtrica:

  • Pontificia Universidad Catlica 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 mtodos "sellados"

    Una clase puede evitar que otras deriven de ella empleando el modificador sealed en su

    declaracin.

    sealed class Math { ... }

    Existen dos razones para sellar una clase:

    Es una clase compuesta exclusivamente de miembros estticos, como Math.

    El uso de sealed permite al compilador realizar llamadas a mtodos no virtuales sobre

    la clase sellada, que son ms rpidas que las llamadas a mtodos virtuales.

  • Pontificia Universidad Catlica del Ecuador

    Mtr. Luis Fernando Aguas B.

    De la misma forma podemos sellar un mtodo 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 encapsulacin (esconder la implementacin de un objeto que no comtribuye

    a sus caractersticas 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 slo 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 slo 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 slo 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

    semntica 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 parmetros y adems inicializar los campos

    de una instancia, y en cambio, una estructura no. El constructor por defecto sin

    parmetros de las estructuras inicializa cada campo con el valor por defecto que le

  • Pontificia Universidad Catlica 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 mtodo, 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 Catlica 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 Catlica del Ecuador

    Mtr. Luis Fernando Aguas B.

    Interfaces

    Un interfaz nos permite hacer que mltiles clases compartan ciertas caractersticas no

    presentes en una clase base. Un interfaz tiene cierto parecido a una clase, pero con diferencias

    significaticas:

    Un interfaz proporciona un especificacin en lugar de una implementacin de sus

    miembros. Es algo parecido a una clase abstracta pura, que es una clase compuesta

    nicamente de mtodos abstractos.

    Cualquier clase o estructura pueden implementar varios imterfaces, pero slo pueden

    heredar de una nica clase.

    Anteriormente describimos el polimorfismo como la habilidad para realizar una misma

    operacin sobre un conjunto de tipos diferentes mientras estos compartiesen ciertas

    caractersticas comunes. El propsito de un interfaz es precisamente definir un conjunto de

    caractersticas. Estas caractersticas pueden ser:

    Mtodos

    Propiedades

    Indexadores

    Eventos

    La declaracin de un interfaz es como la de una clase, salvo por que no se proporciona

    implementacin para sus miembros. La intencin 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 declaracin de una clase o estructura que se deriva de l, y despus implementar los

    mtodos del interfaz. Si la clase o estructura tambin 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 Catlica 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 ms caractersticas 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 mtodo 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 Catlica del Ecuador

    Mtr. Luis Fernando Aguas B.

    interface Dibujable

    {

    void Dibujar();

    }

    class Rectangulo: Figura, Dibujable

    {

    void Figura.Dibujar() { ... cdigo ... }

    void dibujable.Dibujar() { ... cdigo ... }

    }

    Para acceder ahora a cualquiera de estos mtodos habremos de realizar una conversin 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 enumeracin y asignarle un

    valor dentro de los que dicha enumeracin posea.

    Rumbo avion = Rumbo.Sur;

    Por defecto, a cada valor de la enumeracin se le asigna como valor una constante entera 0,

    1, 2,... Opcionalmente se puede especificar un tipo numrico alternativo y, adems, 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 ms frio");

  • Pontificia Universidad Catlica del Ecuador

    Mtr. Luis Fernando Aguas B.

    El atributo [FLAGS] es opcional e informa al entorno de ejecucin de

    que los valores de la enumeracin pueden ser combinados, y debern 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 mtodos estticos 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 implementacin de operador siempre

    que uno o los dos operandos sean clases definidas por el usuario o una estructura. Los

    operadores son mtodos, cuya sintaxis es un tanto especial. La lista de operadores

    sobrecargables es: +, -, !, ~, ++, --, /, %, &, |, ^, , ==, !=, , =. Veamos en

    primer lugar un ejemplo que permite implementar la operacin de suma sobre los nmeros

    complejos:

    // complex.cs

  • Pontificia Universidad Catlica 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 mtodo "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 nmeros complejos utilizando el

    // operador de suma que hemos sobrecargado

    Complex sum = num1 + num2;

    // impresin de tres nmeros 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 informacin representando la ocurrencia de un

    estado excepcional en un programa. Cuando sucede un evento en un programa que produce

    un estado de excepcin, como una divisn por cero, se lanza una excepcin para avisar de

    dicho suceso.

  • Pontificia Universidad Catlica 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 propsitos: permitir a u n bloque catch capturar un excepcin y asegurar que se

    ejecutar el bloque finally. Un bloque try debe estar seguido por un o ms bloques catch y

    finally.

    try

    {

    cdigo que sospechamos que pueda lanzar una excepcin

    }

    catch (TipoDeException1 e)

    {

    cdigo para reaccionar a excepciones de tipo TipoDeException1

    }

    catch (TipoDeException2 e)

    {

    cdigo para reaccionar a excepciones de tipo TipoDeException2

    }

    ...

    catch (TipoDeExceptionN e)

    {

    cdigo para reaccionar a excepciones de tipo TipoDeExceptionN

    }

    finally

    {

    cdigo que se ejecuta siempre despus de try,

    tanto si se lanza una excepcin como si no

    }

    La accin por defecto cuando se lanza una excepcin 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 situacin:

    // exception2.cs

    using System;

  • Pontificia Universidad Catlica 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("Excepcin: {0}", exception.Message);

    }

    finally

    {

    Console.WriteLine("Supongo que ya se ha resulto el problema, no?");

    }

    }

    }

    Para poder atrapar una excepcin dentro de un bloque catch, esta debe ser de tipo

    System.Exception o derivar de este. Las excepciones de tipo System.Exception son las ms

    generales posibles. Normalmente intentaremos atrapar excepciones de algn tipo ms

    especfico que nos permita saber ms acerca de la excepcin lanzada y as tener ms medios

    para resolver la situacin. 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 explcitamente una excepcin mediante la palabra reservada try. Algunas de

    las excepciones ms 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 clusula catch puede omitirse tanto la variable de la excepcin si no va a utilizarse,

    como el parmetro con el tipo de excepcin completo, con lo cual se atrapar cualquier tipo

    de excepcin.

    // exception3.cs

    using System;

  • Pontificia Universidad Catlica 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("Excepcin: {0}", e.Message);

    }

    catch (IndexOutOfRangeException e)

    {

    Console.WriteLine("Excepcin: {0}", e.Message);

    }

    catch

    {

    Console.WriteLine("Excepcin general");

    }

    finally

    {

    Console.WriteLine("Supongo que ya se ha resulto el problema, no?");

    }

    }

    }

    La estructura jerrquica del sistema de excepciones que declaremos condicionar el orden en

    estas puedan ser utilizadas tras un bloque try. No se puede intentar atrapar una excepcin de

    un tipo derivado de otro que se ha intentado atraparse en una clusula previa. Veamos un

    ejemplo vlido y otro que no lo es:

    Uso vlido 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 descripcin del error.

  • Pontificia Universidad Catlica del Ecuador

    Mtr. Luis Fernando Aguas B.

    StackTrace: Cadena con todos los mtodos llamados desde el

    origen de la excepcin 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!");

    }

    }

    }