Herencia en Csharp C# nos permite diseñar una clase que usa herencia para extender otra ya existente C# como Java sólo soporta herencia simple Ejemplo herencia simple: using System; class Persona { protected string nombre, apellido1; public Persona(string nombre, string apellido1) { this.nombre = nombre; this.apellido1 = apellido1; } public void Saludar() { Console.WriteLine("¡Hola " + this.nombre + " " + this.apellido1 + "!"); } }
Herencia class Hombre: Persona { public Hombre(string nombre, string apellido1): base(nombre, apellido1) {} public new void Saludar() { Console.WriteLine("¡Hola " + this.apellido1 + "!"); } } class Test { public static void Main() { Persona p = new Persona("Diego", "Ipiña"); p.Saludar(); // Visualizar ¡Hola Diego Ipiña! Hombre h = new Hombre("Jon", "Altuna"); h.Saludar(); // Visualizar ¡Hola Altuna! } }
Herencia La herencia representa una relación is-a Al cambiar la accesibilidad de los campos nombre y apellido a protected, ahora son accesibles en las clases que los derivan class Hombre: Persona { … } La única diferencia entre Hombre y Persona es la implementación del método Saludar. La palabra clave base se usa para referenciar al objeto padre La palabra clave new indica al compilador que queremos sobre-escribir el método Saludar del padre (Persona).
Métodos virtuales Una de las ventajas de la herencia que podemos usar una clase base para referenciar a una instancia de una clase derivada
Persona p = new Hombre("Diego", "Ipiña"); p.Saludar(); // problema, invoca a Saludar de Persona y no de Hombre
La solución a esto son métodos virtuales a través de las palabras claves virtual (a usarse en el método de la clase padre) y override (a usarse en el método de la clase hijo)
Métodos virtuales using System; class Persona { protected string nombre, apellido1; public Persona(string nombre, string apellido1) { this.nombre = nombre; this.apellido1 = apellido1; } public virtual void Saludar() { Console.WriteLine("¡Hola " + this.nombre + " " + this.apellido1 + "!"); } }
Métodos virtuales class Hombre: Persona { public Hombre(string nombre, string apellido1): base(nombre, apellido1) {} public override void Saludar() { Console.WriteLine("¡Hola " + this.apellido1 + "!"); } } class Test { public static void Main() { Persona p1 = new Hombre("Diego", "Ipiña"); p1.Saludar(); // Visualizar ¡Hola Ipiña! Persona p2 = new Persona("Jon", "Altuna"); p2.Saludar(); // Visualizar ¡Hola Jon Altuna! } }
Clases abstractas Supongamos que estamos interesados en modelar hombres y mujeres, pero no personas perse ? No queremos permitir la creación de objetos Persona directamente, pero queremos permitir la creación de objetos Hombre y Mujer directamente. Usamos abstract delante de Persona para evitar que esta clase se pueda instanciar Usamos abstract en el método Saludar de Persona para indicar que las clases que heredan deben sobreescribirlo
Clases abstractas using System; abstract class Persona { protected string nombre, apellido1; public Persona(string nombre, string apellido1) { this.nombre = nombre; this.apellido1 = apellido1; } abstract public void Saludar(); }
Clases abstractas class Hombre: Persona { public Hombre(string nombre, string apellido1): base(nombre, apellido1) {} public override void Saludar() { Console.WriteLine("¡Hola Señor " + this.apellido1 + "!"); } } class Mujer: Persona { public Mujer(string nombre, string apellido1): base(nombre, apellido1) {} public override void Saludar() { Console.WriteLine("¡Hola Señorita " + this.apellido1 + "!"); } }
Clases abstractas class Test { public static void Main() { Hombre h = new Hombre("Diego", "Ipiña"); h.Saludar(); // Visualizar ¡Hola Señor Ipiña! Mujer m = new Mujer("Usue", "Artaza"); m.Saludar(); // Visualizar ¡Hola Señorita Artaza! } }
Para deshabilitar la herencia se puede marcar una clase como sealed, resultando en un error de compilación si se intenta derivar de ella sealed class Person { … }
Más sobre métodos Los métodos acceptan parámetros y devuelven un resultado int Add(int x, int y) { return x+y; } Los parámetros x e y se pasan por valor, se recibe una copia de ellos Si queremos modificar dentro de una función un parámetro y que el cambio se refleje en el código de invocación de la función, usaremos ref, tanto en la declaración del método como en su invocación: void Increment(out int i) { i = 3; } … int i; Increment(out i); // i == 3
Más sobre métodos Mientras ref se usa para modificar el valor de una variable, si el método asigna el valor inicial a la variable habrá que usar out: Para pasar un numero variable de parámetros se usa params: class Adder { int Add(params int[] ints) { int sum=0; foreach(int i in ints) sum+=i; return sum; } public static void Main() { Adder a = new Adder(); int sum = a.Add(1, 2, 3, 4, 5); System.Console.WriteLine(sum); // visualiza "15" } }
Más sobre métodos Métodos de sobrecarga, es decir, métodos con el mismo nombre, con firmas (número y tipo de parámetros) diferentes: class Persona { string nombre, apellido1, apellido2; public Persona(string nombre, string apellido1) { this.nombre = nombre; this.apellido1 = apellido1; } public Persona(string nombre, string apellido1, string apellido2) { this.nombre = nombre; this.apellido1 = apellido1; this.apellido2 = apellido2; } } Persona p1 = new Persona("Diego", "Ipiña"); Persona p2 = new Persona("Diego", "Ipiña", "Artaza");
Modificadores de acceso Los modificadores de acceso controlan la visibilidad de los miembros de una clase private, sólo código dentro de la misma clase contenedora tiene acceso a un miembro privado. Es el modo de acceso por defecto. public , visible a todos los usuarios de una clase protected, miembros accesibles tanto por dentro de la clase como en clases derivadas internal, miembros accesibles sólo dentro de un assembly protected internal, permite acceso protected e internal
NDD (Non Deterministic Destruction) class File: Idisposable { protected IntPtr Handle = IntPtr.Zero; public File(string name) {} ~File() { this.Dispose(false); } public void Dispose() { System.GC.SupressFinalize(this); this.Dispose(true); } protected virtual void Dispose(bool disposing) { if (disposing) { // Dispose otros recursos de recursos no gestionados } } public void Close() { Dispose(); } }
Excepciones Modo recomendado para manejar errores excepcionales en C# Todas las excepciones definidas en la FCL derivan de System.Exception System.Exception define una serie de propiedades comunes a todas las excepciones: Message: contiene un mensaje de error indicando que ha ido mal StackTrace: detalla los detalles de la llamada que produjo la excepción Para distinguir entre excepciones lanzadas por la framework y excepciones generadas por aplicaciones, estas últimas se recomienda deriven de System.ApplicationException
Página siguiente |