NET - Resumen
NET - Resumen
com/ssofiaavila
o Campo readonly
o Encapsulamiento
o Propiedades
o Descriptores de acceso con cuerpos de expresión
o Propiedades vs campos públicos
o Propiedades implementadas automáticamente
o Encadenamiento de métodos
o Herencia
o Invalidación de métodos
o Acceso a miembros de la clase base
o Constructores
o Modificadores de acceso
o Descriptores de acceso con distintos niveles de accesibilidad
o Invalidación de propiedades
o Clases abstractas
o Finalizadores (destructores)
o Polimorfismo
o Interfaz polimórfica
o Principio open/close
o Diseño ineficiente que no hace uso de polimorfismo
✓ Indizadores
o Indizadores de objeto
✓ Método ToString()
✓ Excepciones definidas por el usuario
✓ Herencia de campos estáticos
✓ Herencia de métodos estáticos
✓ Extensión de métodos
✓ Interfaces
o Interfaces de la plataforma que se usan para la comparación
o Interfaces para enumerar : “System.Collections.IEnumerable” y
“System.Collections.IEnumerator”
o Iteradores
✓ File system- Espacio de nombres System.IO
o Archivos de texto
o Interface IDisposable
✓ Delegados
o Asignación de delegados
o Pasando métodos como parámetros
o Métodos anónimos
✓ Eventos
o Eventos- Convenciones
o Tipo Event Handler
o Observaciones
o Event
✓ Operador condicional NULL
github.com/ssofiaavila
GENERALIDADES DE .NET
Es una plataforma de desarrollo
gratuita, de código abierto y de Comentado [SA1]: código abierto es el software cuyo
uso general. código fuente y otros derechos que normalmente son
exclusivos para quienes poseen los derechos de autor,
Soporta varios lenguajes de son publicados bajo una licencia de código abierto o
programación. Microsoft forman parte del dominio público
desarrolla activamente C#,
Visual Basic y F#, pero también
existen otros.
IMPLEMENTACIONES DE .NET
✓ .NET framework: implementación original, optimizado para aplicaciones de escritorio de
Windows
✓ Mono: para entornos de ejecución pequeños como Android, macOS, iOS,tvOs, watchOS
✓ Plataforma Universal de Windows (UWP): para aplicaciones Windows e internet de las cosas
✓ .NET CORE: implementación multiplataforma de .NET
HISTORIA DE .NET
La versión 1.0 de .NET Framework fue lanzada oficialmente por Microsoft para su sistema operativo
Windows en enero del 2002. Junto con .NET Framework, Microsoft liberó la primera versión del
lenguaje C# y una nueva versión de Visual Basic. F# es un lenguaje funcional más reciente, fue
desarrollado por Microsoft en 2005. .NET Framework es gratuito pero no es open source. La última
versión es la 4.8 (última actualización abril de 2019)
La versión multiplataforma (Windows, macOS y Linux) y open-source de .NET se inició con el nombre
de .NET Core (v 1.0 liberado en junio 2016). La última versión con el nombre .NET Core es la 3.1
(liberado en diciembre 2019). A partir de noviembre de 2020 cambió su nombre a .NET 5.0. La única
rama que seguirá evolucionando en el futuro es la que se inicia con .NET 5.0
De manera transparente el código MSIL se traduce al lenguaje nativo del procesador físico en tiempo
de ejecución, por intermediación de un compilador bajo demanda “Just In Time” (JIT)
Por ejemplo, los tipos integrados están en el espacio de nombres System. En System.Collections
(namespace Collections dentro del namespace System) encontramos clases que representan
colecciones. Las clases relacionadas con el manejo de estructuras de datos XML se encuentra en el
espacio de nombres System.Xml (namespace Xml dentro del namespace System). Las clases para
manejar la comunicación entre servidor web y cliente están en el espacio de nombres System.Web
github.com/ssofiaavila
INTRODUCCIÓN A C#
DIRECTIVA USING
El nombre extenso de una clase lleva como prefijo el espacio de nombres en la que se ha definido. El
nombre extenso de la clase Console definida en el espacio de nombres System es System.Console
La directiva using X al comienzo del archivo fuente permite omitir el prefijo X. para todos los miembros
del espacio de nombres X . El alcance de la directiva using es el archivo fuente donde se especifica
C# es case sensitive
OPERADORES ARITMÉTICOS
Operador Operación
+ Suma
- Resta
* Multiplicación
/ División
% Residuo/ resto
github.com/ssofiaavila
OPERADORES RELACIONALES
Operador Operación
< Menor que
> Mayor que
<= Menor o igual que
>= Mayor igual que
¡= Diferente de
== Igual a
OPERADORES LÓGICOS
Operador Operación
& AND
\ OR
¡ NOT
^ XOR
&& AND en cortocircuito
\\ OR en cortocircuito
OPERADORES DE ASIGNACIÓN
Operador Operación
++ Incremento
-- Decremento
= Asignación simple
*= Multiplicación más asignación
/= División más asignación
%= Residuo más asignación
+= Suma más asignación
-= Resta más asignación
ESTRUCTURAS DE CONTROL
IF Condicional TERNARIO
github.com/ssofiaavila
SISTEMA DE TIPOS
COMMON TYPE SYSTEM
Define un conjunto de tipos orientado a objetos. Todo lenguaje de programación de .NET debe
implementar los tipos definidos por el CTS. Los tipos de .NET pueden ser tipos de valor o tipos de
referencia.
TIPOS DE VALOR
El espacio reservado para la variable en la pila de ejecución guarda directamente el valor asignado.
Admite ESTRUCTURAS (char,bool, DateTime, tipos números, tipos punto flotante),
ENUMERACIONES
Las variables de tipos de valor siempre contienen un valor válido para su tipo y por lo tanto no admiten
el valor null (a excepción de los “nullables value types”)
TIPOS DE REFERENCIA
El espacio reservado para la
variable en la pila de ejecución
guarda la dirección en la memoria
heap donde está el valor asignado
El valor null
github.com/ssofiaavila
Las variables de tipos de referencia o bien contienen la referencia al objeto en la memoria heap, o bien
poseen un valor especial nulo (palabra clave null)
CONVERSIÓN DE TIPOS
Hay distintos tipos de conversiones
Además del operador de cast (...), para algunos casos también se puede usar el operador as. Cuando
una conversión de tipo no puede llevarse a cabo el operador (...) provoca una excepción (error en
tiempo de ejecución). Cuando una conversión de tipo no puede llevarse a cabo el operador as devuelve
el valor null (no provoca una excepción). Por lo tanto as se utiliza sólo para tipos de referencia o tipos
nullables
BOXING Y UNBOXING
Las conversiones boxing y unboxing permiten asignar variables de tipo de valor a variables de tipo de
referencia y viceversa
✓ Cuando una variable de algún tipo de valor se asigna a una de tipo de referencia, se dice que
se le ha aplicado la conversión boxing
✓ Cuando una variable de algún tipo de referencia se asigna a una de tipo de valor, se dice que
se le ha aplicado la conversión unboxing.
github.com/ssofiaavila
ARREGLOS
Los arreglos son de tipo de referencia. Los arreglos pueden tener varias dimensiones. El número de
dimensiones se denomina rank. El número total de elementos de un arreglo se llama longitud del
arreglo length
CLASE STRING
Es un tipo de referencia, por lo tanto acepta el valor null. Sin embargo la comparación no es por
dirección de memoria. Se ha redefinido el operador == para realizar una comparación lexicográfica.
Tiene en cuenta mayúsculas y minúsculas. Los string son de solo lectura, se accede a los elementos
[], el prime elemento tiene el índice 0
STRING BUILDER
El string es de lectura/escritura. Definida en el espacio de nombre System.text. Tiene métodos
adicionales como append, insert, remove, replace, etc.
TIPOS ENUMERATIVOS
enum Tamaño
{
chico, mediano, grande
}
Uso de enumeraciones
Tamaño t;
t = Tamaño.grande;
t = (Tamaño)0; //ahora t vale
Tamaño.chico
ARREGLO DE 2 DIMENSIONES
Matriz: int[,] matriz = new int[,] { {1,2,3,4}, {5,6,7,8}, {9,10,11,12} };
Arreglo de arreglos: int[][] tabla = new int[2][];
tabla[0] = new int[2]; tabla[1] = new int[3];
PALABRA CLAVE VAR
La palabra clave var en la declaración de una variable local con inicialización (≠ null) indica que el tipo
de la misma es inferido por el compilador en función de la inicialización. Una vez inferido el tipo de una
variable por el compilador queda fijo e inmutable (no es un tipo dinámico)
TIPOS ANÓNIMOS
La inferencia de tipos permite instanciar objetos de tipos anónimos. Una forma conveniente de
encapsular un conjunto de propiedades de solo lectura en un solo objeto sin tener que definir
explícitamente un tipo primero.
MÉTODOS
Bloque con nombre de código ejecutable que puede invocarse desde diferentes partes del programa,
e incluso desde otros programas
Si el método no devuelve ningún valor, se especifica void como tipo de retorno. En este caso return
es opcional
PARÁMETROS
✓ De entrada/ por valor: recibe una copia del valor pasado como parámetro. Desde un método
estático como es el caso de main, puede invocarse de forma directa a otro método estático de
la misma clase
✓ De salida (out): se deben asignar dentro del cuerpo del método invocado antes de cualquier
lectura. Es posible pasar parámetros de salida que sean variables no inicializadas
✓ De referencia: similar a los parámetros de salida, pero no es posible indicar el método pasando
una variable no inicializada. El método invocado puede leer el valor del parámetro ref en
cualquier momento pues la inicialización está garantizada por el invocador
✓ De entrada (in): el parámetro se pasa por referencia pero no puede modificarse dentro del
método invocado
Params: permite que un método tome un número variable de argumentos. El tipo declarado del
parámetro params debe ser un arreglo unidimensional
Esta sintaxis no está limitada a métodos que devuelven void, se puede utilizar con cualquier tipo de
retorno.
CADENAS INTERPOLADAS
Las cadenas interpoladas también utilizan elementos de formato. Son más legible y cómodas de usar
que los strings de formato compuesto. Las cadenas interpoladas llevan antepuesto el símbolo $
COLECCIONES
Algunas funcionalidades no pueden resolverse con arreglos de manera conveniente. Como:
Por esto, surgen las colecciones, que gestionan un conjunto de elementos pero lo hacen de una
manera especial. Se pueden considerar arreglos especializados, hay varios tipos según la tarea. Los
más importantes en System.collection encontramos:
ARRAY LIST
Similar a un vector de object pero que puedo redimensionar dinámicamente
La capacidad es el espacio reservado para alocar a los elementos del ArrayList. Count es el número
total de elementos que efectivamente contiene el ArrayList. Si se agregan elementos al ArrayList
continuamente, la estrategia de aumentar la capacidad de este solo lo necesario es muy mala porque
el rendimiento cae abruptamente. La capacidad se duplica cada vez que se necesita reservar más
espacio en el ArrayList
STACK
Las pilas están implementadas como objetos. Cuentan con métodos especializados
QUEUE
Las colas están implementadas como objetos. Permiten:
HASHTABLE
Colección de elementos, acceso a los valores por la clave. Representa una colección de pares
clave/valor que se organizan en función del código hash de la clave. El acceso a los elementos de la
colección se realiza a través de la clave que puede ser de cualquier tipo
Hashtable ht = new Hashtable();
//Agregando elementos
ht["un número" ] = 7;
ht[2.23] = "dos con 23" ;
ht[DayOfWeek.Friday] = 'F';
//Accediendo a los elementos
Console.WriteLine(ht["un número" ]); 7
Console.WriteLine(ht[2.23]); dos con 23
Console.WriteLine(ht[DayOfWeek.Friday]); F
if (ht[3] == null)
github.com/ssofiaavila
{
Console.Write("La clave 3 no existe" ); La clave 3 no existe
}
MANEJO DE EXCEPCIONES
Las excepciones son errores en tiempo de ejecución. Ejemplos de excepciones: Intentar dividir por
cero, escribir un archivo de sólo lectura, referencias a null, acceder a un arreglo con un índice fuera
del rango válido, etc.
EXCEPCIONES COMÚNES
✓ DivideByZeroException
✓ OverflorException
✓ NullReferenceException
✓ IndexOutOfRangeException
✓ IOException
✓ InvalidCastException
PROPAGACIÓN DE EXCEPCIONES
Si Metodo1 invoca a Metodo2 y dentro de este último se produce una excepción que no es manejada,
ésta se propaga a Metodo1. Desde la perspectiva de Metodo1, la invocación a Metodo2 es la
instrucción que genera la excepción
Ejemplo: Se requiere codificar el método imprimir que reciba un string como parámetro. Se lanzará la
excepción ArgumentNullException en caso que el argumento sea null
Todos los métodos que definimos dentro de una clase son miembros de esa clase
Uso de this
Dentro de un constructor o método de instancia, la palabra clave this hace referencia a la instancia (el
propio objeto) que está ejecutando ese código. Puede ser útil para diferenciar el nombre de un campo
de una variable local o parámetro con el mismo nombre
CAMPO DE INSTANCIA
Un campo o variable de instancia es un miembro de datos de una clase. Cada objeto instanciado de
esa clase tendrá su propio campo de instancia con un propio valor (posiblemente distinto al valor que
tengan en dicho campo otros objetos de la misma clase)
MÉTODOS DE INSTANCIA
Los métodos de instancia permiten manipular los datos almacenados en los objetos. Los métodos de
instancia implementan el comportamiento de los objetos. Dentro de los métodos de instancia se pueden
acceder a todos los campos del objeto, incluidos los privados
CONSTRUCTORES DE INSTANCIA
Un constructor de instancia es un método especial que contiene código que se ejecuta en el momento
de la instanciación de un objeto. Habitualmente se utilizan para establecer el estado del nuevo objeto
por medio del pasaje de argumentos
Si no se define un constructor explícitamente, el compilador agrega uno sin parámetros y con cuerpo
vacío. Si se define un constructor explícitamente, el compilador ya no incluye el constructor por defecto
Sobrecarga
Es posible tener más de un constructor en cada clase (sobrecarga de constructores) siempre que
difieran en alguno de los siguientes puntos: la cantidad de parámetros, el tipo y el orden de los
parámetros, los modificadores de los parámetros
Los métodos también pueden ser sobrecargados. Para sobrecargar los métodos valen las mismas
consideraciones que en el caso de los constructores. El valor de retorno NO puede utilizarse como
única diferencia para permitir una sobrecarga
github.com/ssofiaavila
MIEMBROS ESTÁTICOS
Los miembros estáticos son miembros que pertenecen a la propia clase (o tipo) en lugar de a un objeto
(instancia) específico de la misma. Para declararlos se utiliza el modificador static
Campos estáticos
Un campo estático de una clase es una variable accesible a través de la clase en la que fue definido
(NO a través de las instancias). Es una única variable compartida por todas las instancias de esa clase,
incluso por objetos de otras clases en caso de no ser privada.
Los miembros estáticos pueden accederse desde la propia clase sin anteponer el nombre de la misma
Constructores estáticos
Un constructor estático se declara como uno de instancia pero con el modificador static. No se puede
invocar explícitamente. Es invocado por el runtime de .Net una única vez cuando se carga la clase, por
lo tanto: no pueden tener parámetros ni modificadores de acceso, no pueden sobrecargarse (sólo
puede definirse un constructor estático por clase)
Clases estáticas
Las clases estáticas llevan el modificador static en su declaración. Sólo pueden poseer miembros
estáticos. No es posible instanciar objetos de una clase estática. A menudo agrupan un conjunto de
utilidades y datos relacionados (utility class). Ejemplos de clases estáticas: Console, File, Directory,
Math, etc.
Utility classes
Las clases estáticas por lo general constituyen “clases de utilidad’, agrupando cierta funcionalidad que
se expone completamente como miembros de nivel de clases, como math
La expresión que se asigna a una constante es computada por el compilador, por lo tanto: es una
expresión simple, no puede referir a ninguna variable (todas las variables, aún las estáticas se
inicializan en tiempo de ejecución), no puede implicar la ejecución de código del programa, solo los
tipos integrados de C# (excluido object) pueden declararse como const.
github.com/ssofiaavila
Los tipos integrados en C# son: bool, byte, sbyte, char, decimal, double, floar, int, uint, long, ulong,
short, ushot, object y string. Por lo tanto pueden ser constante todos los tipos numéricos, char, bool y
string
CAMPOS READONLY
Con los campos readonly se obtiene un efecto similar al que tienen los campos constantes pero sin
sus restricciones. Se identifican con el modificador readonly, sólo pueden asignarse en su declaración
o dentro de un constructor (los estáticos sólo en el constructor estático). Se asignan en tiempo de
ejecución, como cualquier variable, por lo tanto no están restringidos a un conjunto de tipos u
operaciones simples como en el caso de las constantes
ENCAPSULAMIENTO
El encapsulamiento es uno de los pilares de la programación orientada a objetos. Es la capacidad del
lenguaje para ocultar detalles de implementación hacia fuera del objeto, en estrecha relación con la
noción de encapsulamiento está la idea de la protección de datos. Idealmente, el estado de los objetos
debería especificarse usando campos privados.
Para acceder a los campos privados usamos getters y setters pero no es lo indicado, se deben usar
propiedades
PROPIEDADES
Una propiedad integra los conceptos de campo y método al
mismo tiempo. Externamente se asigna y lee como si fuese un public double Lado
campo. Internamente se codifican dos bloques de código:
{
✓ bloque get: se ejecuta cuando se lee la propiedad
get
✓ bloque set: se ejecuta cuando se escribe la propiedad.
{
A los bloques get y set se los llama descriptores de acceso
(accessors en inglés) <código para leer el
valor de la propiedad>
}
set
{
<código para establecer
Una propiedad que implementa sólo el bloque get es una propiedadel de valor
sólo lectura.
de laUna propiedad que
propiedad>
implementa sólo el bloque set es una propiedad de sólo escritura. No es aconsejable el uso de propiedades de
}
sólo escritura. Si la intención es desencadenar algún efecto secundario cuando se asigna el valor, es preferible
usar un método en lugar de una propiedad. }
DESCRIPTORES DE ACCESO CON CUERPOS DE EXPRESIÓN
Si el cuerpo de un descriptor de acceso consta de una sola expresión puede utilizarse la sintaxis
alternativa (expression bodied member)
Si la clase que modificamos es utilizada por otro programa, al cambiar un campo por una propiedad
debemos volver a compilar también el otro programa. Esto no sucede si desde el principio se codifica
una propiedad. Al cambiar su implementación no es necesario recompila otros programas que acceden
a ella
github.com/ssofiaavila
No hay excusa para seguir utilizando campos públicos. Solo agregando (get;set; ) los convertimos en
propiedades auto implementadas
ENCADENAMIENTO DE MÉTODOS
El encadenamiento de métodos es una técnica muy útil que permite invocar múltiples métodos en una
sentencia.
HERENCIA
La herencia permite crear clases que reutilizan, extienden y modifican el comportamiento definido en
otras clases. La clase cuyos miembros se heredan se denomina clase base y las clases que heredan
esos miembros se denominan clases derivadas. Una clase derivada sólo puede tener una clase base
directa, pero la herencia es transitiva.
Derivación de clases
Claramente las clases Auto y Colectivo comparten tanto atributos como comportamiento. Es posible
por lo tanto generalizar el diseño colocando las características comunes en una superclase que
llamaremos Automotor
Una clase derivada obtiene implícitamente todos los miembros de la clase base, salvo sus
constructores y sus finalizadores. Las clases Auto y Colectivo del ejemplo derivan de la clase
Automotor, por lo tanto un Auto es un Automotor y un Colectivo también es un Automotor.
Las clases Auto y Colectivo también heredan el método Imprimir() definido en Automotor. Sin embargo,
el método Imprimir() resulta poco útil al no poder acceder a las variables específicas de Auto y Colectivo
(Tipo y CantPasajeros respectivamente). Solución: Sobrescribir (invalidar) el método Imprimir() en cada
una de las subclases para que tanto autos como colectivos se impriman de forma más adecuada.
INVALIDACIÓN DE MÉTODOS
Las clases derivadas pueden invalidar class Automotor {
los métodos heredados para public string Marca;
proporcionar una implementación public int Modelo;
alternativa. Para poder invalidar un public virtual void Imprimir()
método, el método de la clase base debe => Console.WriteLine($"{Marca} {Modelo}");
marcarse con la palabra virtual }
github.com/ssofiaavila
El modificador override indica que se está invalidando el método de la clase base. Un método override,
al igual que virtual, también puede ser invalidado en una clase derivada
virtual is used to modify a method, property, indexer, or event declared in the base class and allow
it to be overridden in the derived class.
override is used to extend or modify a virtual/abstract method, property, indexer, or event of base
class into derived class.
CONSTRUCTORES
Los constructores no se heredan, sin embargo, debemos estar atentos cuando los definimos en una
jerarquía de clases
Public auto():base(){ }
En lugar de agregar el constructor sin argumentos en la clase Automotor se pueden definir
constructores adecuados en las clases Auto y Colectivo que invoquen al constructor de dos
argumentos de la clase automotor de la siguiente manera:
✓ Protected terminal: pueden accederse desde cualquier código de ensamblado, o desde una
clase derivada de cualquier ensamblado
✓ Private protected: solo pueden accederse desde la propia clase o desde sus clases derivadas
en el mismo ensamblado
Clases
✓ Públicas: precedidas por el modificador public
✓ Internas: precedidas por el modificador de acceso terminal o no contienen el modificador
No se pueden definir clases con el modificador private o protected a menos que sea una clase anidada
dentro de otra
Propiedades
class Automotor
{
Se desea controlar que el modelo sea
public string Marca { get; } mayor o igual a 2005
private int _modelo;
public int Modelo
{
get => _modelo;
set => _modelo = (value < 2005) ? 2005 : value;
}
. . .
}
Restricciones
Las clases no pueden ser más accesibles que su clase base. Las constantes, campos, propiedades e
indizadores no pueden ser más accesibles que sus respectivos tipos. Los métodos, constructores e
indizadores no pueden ser más accesibles que los tipos de sus parámetros, índices o valor de retorno
Si defino una clase como pública, sus propiedades deben serlo también porque si no existe una
contradicción
github.com/ssofiaavila
class Automotor
{
public string Marca { get; }
private int _modelo;
public int Modelo
{
get => _modelo;
protected
El modificador de set => solo
acceso _modelo
afecta=al(value < 2005)
descriptor ? 2005
set, debe : value;
ver más restrictivo que el modificador de
la propiedad
}
Solo puede ser escrita en Automotor o sus jerarquías derivadas
INVALIDACIÓN DE PROPIEDADES
Las propiedades, al igual que los métodos, pueden ser redefinidas en las clases derivadas. Para ello,
al igual que los métodos, la propiedad debe ser marcada como una propiedad virtual mediante la
palabra clase virtual
Esto permite que las clases derivadas invaliden el comportamiento de la propiedad mediante la palabra
clave override
}
CLASES ABSTRACTAS
El propósito de una clase abstracta es proporcionar una definición común de una clase base que
hereden múltiples clases derivadas. No se pueden crear instancias de una clase abstracta. Las clases
abstractas se señalan con el modificador abstract.
Una clase abstracta puede tener métodos, propiedades, indizadores y eventos abstractos. Una clase
abstracta también pueden tener miembros no abstractos. Las miembros abstractos no tienen
implementación, se escriben sin el cuerpo, y llevan el modificador abstract
Ejemplo:
En las aplicaciones de .NET Framework (pero no en las de .NET Core), cuando se cierra el programa
también se llama a los finalizadores. No se puede llamar a los finalizadores, se invocan
automáticamente. Puede haber un solo finalizador por clase, no puede tener ni parámetros ni
modificadores. Los finalizadores no se heredan.
POLIMORFISMO
El polimorfismo suele considerarse el
tercer pilar de la programación
object o;
orientada a objetos, después del
encapsulamiento y la herencia. Un o = 1;
objeto polimórfico en tiempo de o = "ABC";
ejecución puede adoptar la forma de
un tipo no idéntico a su tipo declarado. Automotor a;
La relación “es un” asociada a la a = new Auto("Ford", 2000, TipoAuto.Deportivo);
herencia permite tener objetos
a = new Colectivo("Mercedes", 2010, 20);
polimórficos.
O y a son objetos polimórficos. En tiempo de ejecución va a ocurrir polimorfismo (van a adoptar distintas
formas de tipos)
a.Imprimir();
github.com/ssofiaavila
Imprimirá “depende de quién sea a”. El método que se invocará en la expresión “a.Imprimir();” NO se
enlaza estáticamente en tiempo de compilación. El CLR busca en tiempo de ejecución, el tipo
específico del objeto a , e invoca la invalidación correcta de Imprimir() (enlace dinámico)
INTERFAZ POLIMÓRFICA
La interfaz polimórfica de una clase base es el conjunto de sus métodos virtuales y eventualmente
abstractos. Esto es más interesante de lo que parece a primera vista, ya que permite crear aplicaciones
de software fácilmente extensibles y flexibles. Un diseño adecuado de la jerarquía de clases permitirá
tomar ventaja del polimorfismo.
{ ImprimidorAutomotores.Imprimir(vector);
PRINCIPIO OPEN/CLOSE
Establece que una entidad de software debe ser abierta para su extensión, pero cerrada para su
modificación. El polimorfismo contribuye a que podamos cumplir con este principio.
SI nuestro código requiere consultar por el tipo de un objeto, puede ser una señal de un diseño
ineficiente. Ejemplo: si a es una instancia de Auto, retornará true
INDIZADORES
Ahora se desea acceder a los miembros de una
familia a través de un índice (como si se tratase de public Persona this[<lista de índices>]
una colección). {
get
Un indizador es una definición de cómo aplicar el {
operador ([ ]) a los objetos de una clase. A diferencia código que retorna el elemento
de los arreglos, los índices que se les pase entre según la <lista de índices>
corchetes no están limitados a los enteros, }
pudiéndose definir varios indizadores en una misma set
clase siempre y cuando cada uno tome un número {
o tipo de índices diferente (sobrecarga). Los código que establece el elemento
indizadores son sólo de instancia, no pueden según la <lista de índices>
definirse indizadores estáticos }
}
INDIZADORES DE OBJETO
Los inicializadores de objeto permiten asignar valores a cualquier campo o propiedad accesible de un
objeto en el momento de su creación. Un inicializador consiste en una lista de elementos separada por
comas encerradas entre llaves { } que sigue a la invocación del constructor. Cada miembro de la lista
mapea con un campo o propiedad pública del objeto al que le asigna un valor.
MÉTODO TOSTRING()
Uno de los métodos de la interfaz polimórfica de object es: public virtual string ToString();
La implementación genérica en object simplemente devuelve el nombre del tipo del objeto que recibe
el mensaje, es lo que muestra el método WriteLine() de la clase Console.
Cuando heredo campos, no obtengo dos variables, si no que tengo dos accesos a la misma variable
Es posible volver a definir un campo estático en una clase derivada. De esta forma se dice que el nuevo
campo oculta al campo de la clase base. Se debe utilizar el modificador new para evitar un Warning
del compilador y ahora tengo 2 variables
Utilizo un new
EXTENSIÓN DE MÉTODOS
Implemento métodos en una clase aunque no estén definidas en la clase, por lo tanto conviene
agruparlas en una clase estática
La herencia permite extender el funcionamiento de clases existentes, sin embargo no siempre está
disponible. No pueden derivarse clases selladas (marcadas con el modificador sealed) ni tampoco
estructuras (por ejemplo los tipos numéricos). Los métodos de extensión permiten agregar
funcionalidad a los tipos incluso en los casos en que la herencia no está permitida.
Los métodos de extensión son métodos con los que se extiende a un tipo pero se definen realmente
como miembros en otro tipo (una clase estática). Supongamos que queremos contar con un conjunto
extra de funciones para trabajar con tipos int. Una buena idea es definir una clase estática que agrupe
las nuevas funciones.
Para llamar a estos métodos, debo poner this y el tipo al principio de los parámetros de los métodos
extendidos, brinda azúcar sintáctica
github.com/ssofiaavila
Si la clase estática con los métodos de extensión se encuentra definida en otro espacio de nombres,
estos métodos estarán disponibles únicamente cuando el espacio de nombres se importe
explícitamente con la directiva using
INTERFACES
La interfaz polimórfica establecida por una clase base solo es aprovechada por los tipos derivados. Sin
embargo, en sistemas de software más grandes, es común desarrollar múltiples jerarquías de clases
que no tienen un padre común más allá de System.object. Para esto, implementamos las interfaces
Las interfaces son un tipo referencia que especifica un conjunto de funciones sin implementarlas
Pueden especificar métodos, propiedades, indizadores y eventos de instancia. En lugar del código que
los implementa, llevan un ; al final. Por conversión comienzan con la I (i latina mayúscula)
Declaración de interface
public interface IMiInterface
{
public void UnMetodo();
}
Las clases derivan de otras clases y opcionalmente implementan una o más interfaces. SI una clase
implementa una interface debe implementar todos los miembros de la interface que no tienen
implementación determinada. Si una clase deriva de otra clase y además implementa algunas
interfaces, la clase debe ser la primera en la lista después de los dos puntos. Entonces al declarar una
clase se hace de la siguiente manera:
Utilización de interfaces
Es posible definir y usar variables de tipo interface. Entonces:
Las interfaces son tipos de referencias, por lo tanto es posible usar el operador as y puedo
Herencia en interfaces
github.com/ssofiaavila
interface IInterface1 {
void Metodo1();
}
interface IInterface2 {
void Metodo2();
}
interface IInterface3: IInterface1, IInterface2 {
void Metodo3();
}
class A : IInterface3 {
. . .
}
github.com/ssofiaavila
Console.WriteLine("método de Iterface1");
Console.WriteLine("método de Iterface2");
namespace System
// Summary:
// Compares the current instance with another object of the same type and returns
github.com/ssofiaavila
// occurs in the same position in the sort order as the other object.
return st1.CompareTo(st2);
Si queremos otro criterio de orden, podemos usar una sobrecarga del método Sort que espera como
argumento un objeto comparador que debe implementar la interface IComparer
namespace System.Collections
//
// Summary:
//
// Summary:
// Compares two objects and returns a value indicating whether one is less than,
github.com/ssofiaavila
//
Entonces
Empleado e1 = x as Empleado;
Empleado e2 = y as Empleado;
return e1.Legajo.CompareTo(e2.Legajo);
//Luego
};
lista.Sort(new ComparadorPorLegajo());
e.Imprimir();
}
github.com/ssofiaavila
foreach(string st in vector)
namespace System.Collections
Enumerador
Es un objeto que puede devolver los elementos de una colección, uno por uno, en orden según se lo
solicite. Un enumerador “conoce” el orden de los elementos y realiza un seguimiento de dónde está en
la secuencia. Luego devuelve el elemento actual cuando se solicita. Un enumerador debe implementar
la interface System.Collection.IEnumerator
namespace System.Collections
bool MoveNext();
void Reset();
github.com/ssofiaavila
ITERADORES
Los iteradores constituyen una forma mucho más simple de crear enumeradores y enumerables. Usan
la sentencia yield.
Yield return → devuelve un elemento de una colección y mueve la posición al siguiente elemento
Un bloque iterador es un bloque de código que contiene una o más sentencias yield. Puede contener
múltiples sentencias yield return o yield break pero no se permiten sentencias return
Un iterador produce un enumerador y no una lista de elementos. Este enumerador es invocado por la
instrucción foreach. Esto permite iterar a través de grandes cantidades de datos sin leer todos los datos
en memoria de una vez.
PATH
Incluye un conjunto de miembros estáticos diseñados para realizar cómodamente las operaciones más
frecuentes relacionadas con rutas y nombres de archivos. Con los campos públicos
VolumeSeparatorChar, DirectorySeparatorChar, AltDirectorySeparatorChar y PathSeparator se
obtiene el carácter específico de la plataforma que se usa para separar unidades, carpetas y archivos
y el separador de múltiples rutas. EN Windows son: : \ / ;
Ejemplo:
Console.WriteLine(Path.GetFullPath(archivo));
Console.WriteLine(Path.GetFileName(archivo));
Console.WriteLine(Path.GetExtension(archivo));
Console.WriteLine(Path.GetDirectoryName(archivo));
Console.WriteLine(Path.ChangeExtension(archivo, "doc"));
Console.WriteLine(Path.GetFileNameWithoutExtension(archivo));
Console.WriteLine(Path.GetTempPath());
Mostrará:
C:\Documentos\notas.txt
github.com/ssofiaavila
notas.txt
.txt
\Documentos
/Documentos/notas.doc
notas
C:\Users\Leo\AppData\Local\Temp\
Ejemplo:
Console.WriteLine(st);
Imprimirá:
ARCHIVOS DE TEXTO
El trabajo con archivos en .NET está ligado al concepto de stream o flujo de datos, que consiste en
tratar su contenido como una secuencia ordenada de datos. El concepto de stream es aplicable
también a otros tipos de almacenes de información tales como conexiones de red o buffers de memoria.
La BCL proporciona las clases StreamReader y StreamWriter. Los objetos de estas clases facilitan la
lectura y escritura de archivos de textos
Streamreader
Para facilitar la lectura de flujos de texto StreaReader ofrece una familia de métodos que permiten leer
sus caracteres de diferentes formas
✓ De uno en uno: el método int Read() devuelve el próximo carácter del flujo. Tras cada lectura
la posición actual en el flujo se mueve un carácter hacia adelante
✓ Por líneas: el método string ReadLine() devuelve la siguiente línea del flujo (y avanza la
posición en el flujo). Una línea de texto es cualquier secuencia de caracterer terminada en \n,
\y o \r\n.
github.com/ssofiaavila
✓ Por completo: string ReadToEnd(), que nos devuelve una cadena con todo el texto que hubiese
desde la posición actual hasta el final (y avanza hasta el final del flujo)
Streamwritter
Ofrece métodos que permiten:
✓ Escribir cadenas de texto: el método Write() escribe cualquier cadena de texto en el destino
que tenga asociado. Pueden usarse formatos compuestos
✓ Escribir líneas de texto: el método WriteLine() funciona igual que Write() pero añade un
indicador de fin de línea. También pueden usarse formatos compuestos
Dado que el indicador de fin de línea depende de cada sistema operativo, StreamWriter dispone de
una propiedad string NewLine mediante la que puede configurarse este indicador. Su valor por defecto
en Windows es \r\n.
Ejemplo:
string linea;
while (!sr.EndOfStream)
linea = sr.ReadLine();
sw.WriteLine(linea);
sr.Close(); sw.Close(); → el método close() libera los recursos de manera explícita, invocando
un método Dispose()
void Dispose();
INTERFACE IDISPOSABLE
El cual define un mecanismo determinista para liberar recursos no administrados y evita los problemas
relacionados con el recolector de basura inherentes a los finalizadores
Cuando se termina de usar un objeto que implementa IDisposable, se debe invocar el método
Dispose() del objeto. Hay 2 maneras de hacerlo:
try {
bloque de sentencias
} finally {
Instrucción using
En una instrucción using se pueden instanciar más de un objeto del mismo tipo:
f2 = new StreamReader("file2.txt"))
...
sw.Write(sr.ReadToEnd());
Console.WriteLine(e.Message);
DELEGADOS
Es un tipo especial de clase cuyos objetos almacenan referencias a uno o más métodos de manera
de poder ejecutar en cadena esos métodos. Permiten pasar métodos como parámetros a otros
métodos y proporcionan un mecanismo para implementar eventos.
Para definir un tipo de delegado, se usa una sintaxis similar a la definición de una firma de método.
Solo hace falta agregar la palabra delegate
Ejemplo:
{
static void Main(string[] args)
{
FuncionEntera f;
f = SumaUno;
Console.WriteLine(f(10)); → se invoca SumaUno por medio de f
f = SumaDos;
Console.WriteLine(f(10)); → se invoca SumaDos por medio de f
}
static int SumaUno(int n) => n + 1;
static int SumaDos(int n) => n + 2;
}
También se pueden invocar los métodos en los delegados de forma explícita usando el método Invoke
ASIGNACIÓN DE DELEGADOS
Las variables de tipo delegado pueden asignarse directamente con el nombre del método o con su
correspondiente constructor pasando el método como parámetro
MÉTODOS ANONIMOS
En ocasiones los métodos solo se utilizan para crear una instancia de un delegado. Los métodos
anónimos permiten prescindir del método con nombre definido por separado. Un método anónimo es
un método que se declara en línea, en el momento de crear una instancia de un delegado
Entonces:
2) Colocar el operador lambda => entre la lista de parámetros y el cuerpo del método anónimo
Entonces:
f= n => n*2;
Un delgado puede llamar a más de un método cuando se invoca, se conoce como multidifusión.
EVENTOS
Cuando ocurre algo importante, un objeto puede notificar el evento a otras clases u objetos. La clase
que produce el evento recibe el nombre de editor y las clases que están interesadas en conocer la
ocurrencia del evento se denominan suscriptores. Para que un suscriptor sea notificado, necesita
estar suscripto al evento.
Un evento puede tener varios suscriptores. Un suscriptor puede manejar varios eventos de varios
editores. Nunca se provocan eventos que no tienen suscriptores.
Ejemplo:
Dada la clase Program conoce y va a poner a trabajar un objeto t de tipo Trabajador. El objeto t no
conoce a la clase Program. Pero Program se tiene que enterar cuando t termina de trabajar pero
queremos mantener el bajo acoplamiento. Entonces Program se suscribe al evento TrabajoFinalizado
de t. Cuando Program hace trabajar a t, Program es notificado cuando t termina su produce el evento
TrabajoFinalizado pero realmente no conoce quién o quiénes se están notificando
github.com/ssofiaavila
class Program {
public static void Main() {
Trabajador t = new Trabajador();
t.TrabajoFinalizado = ManejadorDelEvento;
t.Trabajar();
}
private static void ManejadorDelEvento() → TrabajoFinalizado es un campo publico de tipo
delegado de t
=> Console.WriteLine("trabajo finalizado");
}
La clase Program se suscribe al evento TrabajoFinalizado del objeto t, asignando su propio método
ManejadorDelEvento para manejar dicho evento
class Trabajador {
public Action TrabajoFinalizado;
public void Trabajar() {
Console.WriteLine("trabajador trabajando...");
// hace algún trabajo útil
if (TrabajoFinalizado != null) { → **
TrabajoFinalizado();
}
}
}
** Aquí se produce el evento invocando la lista de métodos encolados en el delegado. Si no se ha
encolado ningún método la variable tiene el valor null.
EVENTOS- CONVENCIONES
Para los nombres de los eventos se recomiendan verbos en gerundio ( ej: iniciandoTrabajo) o participio
(ej: TrabajoFinalizado) según se produzcan antes o después del hecho de significación
Los delegados usados para invocar a los manejadores de eventos deben tener 2 argumentos: uno de
tipo object que contendrá al objeto que genera el evento y otro de tipo EvenArgs para pasar
argumentos. Además su tipo de retorno debe ser void.
public delegate void EventHandler (object sender, EventArgs e); → es una clase vacía,
no lleva datos pero constituye la clase base de todas las que se usan para pasar argumentos
✓ Es deseable que los nombres que se usen compartan una raíz común
github.com/ssofiaavila
✓ Por ejemplo si defino un evento CapacidadExcedida: la clase para apsar los argumentos se
debería denominar CapacidadExcedidaEventArgs y el delegado asociado al evento, se
debería denominar CapacidadExcedidaEventHandler
Ejemplo:
Si una clase produce el evento TrabajoFinalizado, deberíamos definir los siguientes tipos:
Tarea: se requiere codificar una clase Trabajador, con un método publico Trabajar que producto un
evento TrabajoFinalizado una vez concluida su tarea. Debe además comunicar el tiempo insumido en
la ejecución del trabajo
}
}
class Program
{
public static void Main()
{
Trabajador t = new Trabajador();
t.TrabajoFinalizado = t_TrabajoFinalizado;
t.Trabajar();
}
private static void t_TrabajoFinalizado(object sender, TrabajoFinalizadoEventArgs
e)
{
string st = "Trabajo terminado en ";
st += $"{e.TiempoConsumido.TotalMilliseconds} ms.";
Console.WriteLine(st);
}
}
OBSERVACIONES
Gracias a la capacidad de multidifusión de los delegados, es posible que varias entidades se suscriban
a un mismo evento, solo tienen que conocer al que lo genera para encolar su propio manejador.
Cada uno de los suscriptores debería suscribirse al evento usando el operador += para encolar su
manejador sin eliminar los otros. Pero no podemos garantizarlo porque dejamos publico el campo
delgado que representa al evento
EVENT
Un evento será un miembro definido con la palabra clave Event. Así como una propiedad controla el
acceso a un campo de una clase u objeto, un evento lo hace con respecto a campos de tipo delegados,
permitiendo ejecutar código cada vez que se añade o elimina un método del campo delegado. A
diferencia de los delegados, a los eventos solo se le pueden aplicar dos operaciones: =+ y -=
Sintaxis:
}
1) Código que se ejecutará cuando desde afuera se haga un +=. En este bloque la variable
implícita value contiene el delegado que se desea encolar
2) Código que se ejecutara cuando desde afuera se haga un -=. En este bloque la variable
implícita value contiene el delegado que se desea encolar
En ocasiones no es necesario establecer control alguno en los descriptores de acceso add y remove.
Pasa estos casos C# provee una notación abreviada