programacion en c#
TRANSCRIPT
2
Bienvenida y Obje6vos Quién soy. Qué conocimientos
tengo de .NET.
Introducción a .NET Breve explicación para aterrizar en este mundo
Temario Programación en C#
3
Definiciones básicas
Directrices para la programación en C#
Garbage Collector Recolector de basura
Clases y Objetos Clases, Herencia, Polimorfismo, Interfaces
Framework Design Guidelines
Espacios de nombres, clases, constructores,
campos y propiedades, métodos y Lpos
4
Patrones de Diseño Breve introducción
Enumerados y colecciones Flexibilidad para almacenar, ordenar y gesLonar gran canLdad de datos
Ensamblados, atributos y reflec6on
Bloques de creación de .NET Framework
Lectura y escritura de ficheros Serialización y Deserialización de datos
5
Excepciones GesLón de excepciones existentes y creación de nuevas excepciones
LINQ y expresiones Lambda Cómo hacer que la vida del desarrollador sea más sencilla
Delegados, Eventos y Métodos de extensión
Referencias a métodos. Qué hace el código cuando no le
estamos observando?
Tests unitarios con MSTest El arte de medir y mantener la calidad del soRware
6
Consumo de librerías Consumo de librerías de terceros de
código administrado y no administrado
Servicios Windows Aplicaciones ejecutables de larga duración
Aplicaciones cliente Generación de aplicaciones cliente
para el consumo de servicios remotos
Otros puntos de interés Herramientas de profiling, gesLón de librerías mediante Nuget, librerías para logging, etc.
7
Sobre mí He trabajado durante 13 años en el área de Desarrollo de SoRware realizando trabajos de Arquitectura y Desarrollo de aplicaciones sobre múlLples plataformas y lenguajes. Asimismo, tengo una gran experiencia en el área de la Seguridad de aplicaciones, ya que desde el 2004 soy co-‐autor de hdiv.org; framework de Seguridad para aplicaciones Java y .NET, el cuál está siendo uLlizado por enLdades bancarias, consultoras, etc. de presLgio a nivel mundial.
Gorka Vicente Ingeniero en InformáLca
Bienvenida y Obje6vos gorkavicente.com
Bienvenida y Obje6vos Programación en C#
Crear aplicaciones cliente (web y escritorio) que consuman servicios remotos y servicios publicados por nosotros mismos
Perder el miedo a .NET
Ser capaces de crear librerías y consumirlas desde proyectos tanto locales como remotos
Crear servicios Windows con el objeLvo de crear aplicaciones desatendidas
Conocer herramientas existentes en el mercado que nos faciliten y agilicen el día a día
11Introducción a .NET Conceptos generales
Unidad lógica de despliegue en la plataforma .NET.
AssembliesComponente Windows que admite la compilación y proporciona un entorno de ejecución administrado, un desarrollo e implementación simplificados y la integración con una gran variedad de lenguajes de programación. Consta de 2 componentes principales: • CLR • Biblioteca de clases
Framework .NETCommon Intermediate Language Código intermedio resultante de la compilacion del código fuente y que es interpretado por el CLR.
CILCommon Language Run6me Entorno común de ejecución para lenguajes.
CLRLenguaje de programación orientado a objetos que está incluido en la Plataforma .NET y que se ejecuta en el CLR (Common Language RunLme).
C#
Assembly manifest
Type metadata
CIL code
Resources
MyAssembly.dll
14Introducción a .NET Entorno de desarrollo
Conjunto completo de herramientas de desarrollo para la generación de aplicaciones web ASP.NET, Servicios Web XML, aplicaciones de escritorio y aplicaciones móviles. Visual Basic, Visual C# y Visual C++ uIlizan todos el mismo entorno de desarrollo integrado (IDE), que habilita el uso comparIdo de herramientas y facilita la creación de soluciones en varios lenguajes.
16Introducción a .NET Anatomía de una aplicación
Todas las aplicaciones C# están estructuradas exactamente de la misma forma. Todas hacen uso de espacios de nombres, clases y métodos.
Definiciones básicas Espacios de nombres, clases,
constructores, campos y propiedades, métodos y Lpos
Lenguaje orientado a objetos; lo que significa que todo con lo que vamos a trabajar en este lenguaje son objetos. Un objeto es un agregado de datos y de métodos que permiten manipular dichos datos, y un programa en C# no es más que un conjunto de objetos que interaccionan unos con otros a través de sus métodos.
Definiciones básicas Lenguaje de programación C#
C#
20
posibilidad de crear nuevas clases basadas en una clase existente.
Programación Orientada a Objetos Los 4 pilares
Herencia
Expresa las caracterísLcas esenciales de un objeto.
Abstracción ocultamiento del estado, es decir, de los datos de un objeto de manera que sólo se pueda cambiar mediante las operaciones definidas para ese objeto.
Encapsulamiento
palabra griega que significa "con muchas formas”. Tareas similares son realizadas por métodos con mismo nombre.
Polimorfismo
21
namespace La palabra clave namespace se uLliza para declarar un ámbito que conLene un conjunto de objetos relacionados. Hace que las clases sean fáciles de usar y prevenir colisiones con las clases escritas por otros programadores.
Dentro de un espacio de nombres, se pueden declarar uno o varios de los siguientes 6pos:
Definiciones básicas
otro espacio de nombres class interface struct enum delegate
namespace SampleNamespace { class SampleClass { } interface SampleInterface { } struct SampleStruct { } enum SampleEnum { a, b } delegate void SampleDelegate(int i); namespace SampleNamespace.Nested { class SampleClass2 { } } }
Lenguaje de programación C#
Ejemplo prácLco namespace
namespace SomeNameSpace { public class MyClass { static void Main() { Nested.NestedNameSpaceClass.SayHello(); } } // a nested namespace namespace Nested { public class NestedNameSpaceClass { public static void SayHello() { Console.WriteLine("Hello"); } } } } // Output: Hello
Definiciones básicas Lenguaje de programación C# namespace
En el siguiente ejemplo existen 3 clases:
• Dog • Cat • Fish
Las 3 clases están definidas en el mismo namespace. Por ello, Dog.Bark() puede invocar a Cat.Meow() y/o Fish.Swim() sin problema!!.
Palabra reservada using Hacer uso de clases de otros espacios de nombres
Definiciones básicas Lenguaje de programación C# namespace
Definiciones básicas Lenguaje de programación C# namespace
namespace A { namespace B {
namespace C { public class CClass { } }
} } namespace D { public class DClass { } } namespace F { public class FClass { } }
using System; using A.B.C; namespace E { using D; class Program {
static void Main() { // Can access CClass type directly from A.B.C. CClass var1 = new CClass();
// Can access DClass type from D. DClass var2 = new DClass();
// Must explicitly specify F namespace. F.FClass var3 = new F.FClass();
// Display types. Console.WriteLine(var1); Console.WriteLine(var2); Console.WriteLine(var3); }
} }
?
Definiciones básicas Lenguaje de programación C# namespace
namespace A { namespace B {
namespace C { public class CClass { } }
} } namespace D { public class DClass { } } namespace F { public class FClass { } }
using System; using A.B.C; namespace E { using D; class Program {
static void Main() { // Can access CClass type directly from A.B.C. CClass var1 = new CClass();
// Can access DClass type from D. DClass var2 = new DClass();
// Must explicitly specify F namespace. F.FClass var3 = new F.FClass();
// Display types. Console.WriteLine(var1); Console.WriteLine(var2); Console.WriteLine(var3); }
} }
A.B.C.CClass D.DClass F.FClass
27
Unidad lógica que encapsula un conjunto de datos y comportamientos relacionados. Una declaración de clase o struct es como una planLlla que se uLliza para crear instancias u objetos en Lempo de ejecución. Una clase define las operaciones que un objeto puede realizar y define un valor que manLene el estado del objeto. El Lpo struct es adecuado para representar objetos de poca complejidad.
Definiciones básicas class Person { private string firstName; private string lastName; private int age; }
Si definimos una clase o un struct llamado Person, Person es el nombre del Lpo. Si declaramos e inicializamos una variable p de Lpo Person, se dice que p es un objeto o una instancia de Person.
Se pueden c rea r va r i a s instancias del mismo Lpo Person y cada instancia puede tener diferentes valores en sus propiedades y campos.
Lenguaje de programación C#
Los structs son Lpos de valor y las clases Lpos de referencia.
struct Coord { public int x, y; public Coord(int p1, int p2) { x = p1; y = p2; } }
//Fields, properties, methods and events go here...
Clases y Structs
29
Campos variable de cualquier Lpo que se declara directamente en una clase o struct. Los campos son miembros de su Lpo contenedor.
Métodos bloque de código que conLene una serie de instrucciones.
Constructores permiten al programador establecer valores predeterminados, limitar la creación de instancias.
Destructores se uLlizan para destruir instancias de clases.
Todos los métodos, campos, constantes, propiedades y eventos se deben declarar dentro de un 6po; estos elementos se denominan miembros del 6po. En la lista siguiente se incluyen los diversos 6pos de miembros que pueden declararse en una clase o en un struct.
Operadores símbolo formado por uno o más caracteres que permite realizar una determinada operación entre uno o más datos y produce un resultado.
Eventos habilitan una clase u objeto para noLficarlo a otras clases u objetos.
Constantes valores inmutables que se conocen en Lempo de compilación y no cambian mientras dura el programa.
const
Indizadores permiten indizar las instancias de una clase o struct igual que como se hace con las matrices
this Propiedades miembro que ofrece un mecanismo flexible para leer, escribir o calcular el valor de un campo privado. get; set;
Definiciones básicas Lenguaje de programación C# Clases y Structs
namespace ProgrammingGuide { // Class definition. public class MyCustomClass { // Class members: // Property. public int Number { get; set; } // Method. public int Multiply(int num) { return num * Number; } // Instance Constructor. public MyCustomClass() { Number = 0; } } // Another class definition. This one contains // the Main method, the entry point for the program. class Program { static void Main(string[] args) { // Create an object of type MyCustomClass. MyCustomClass myClass = new MyCustomClass(); // Set the value of a public property. myClass.Number = 27; // Call a public method. int result = myClass.Multiply(4); } } }
Definiciones básicas Lenguaje de programación C# Tipos de miembros
Campos dato común a todos los objetos de una determinada clase. Se trata en realidad de una variable definida dentro de una definición de clase.
Métodos conjunto de instrucciones a las que se les asocia un nombre de modo que si se desea ejecutarlas basta referenciarlas a través de dicho nombre en vez de tener que escribirlas.
Constructores reciben ese nombre debido a que su código suele usarse precisamente para construir el objeto, para inicializar sus miembros.
Propiedades miembros que ofrecen un mecanismo flexible para leer, escribir o calcular los valores de campos privados. Son métodos especiales denominados descriptores de acceso.
// Constantes, Operadores, Eventos
Instrucciones y pautas con las que se pretende ayudar a los desarrolladores de clases a comprender las ventajas y las desventajas entre las disLntas soluciones.
Coherencia
Facilidad de uso
Un diseño de API incoherente afecta negaIvamente a la producIvidad de los desarrolladores y nos desanima a adoptarla
Directrices para la programación Framework Design Guidelines
33
Nomenclatura instrucciones para denominar Lpos y miembros en las bibliotecas
de clases.
Diseño de 6pos instrucciones para uLlizar clases estáLcas y abstractas, interfaces,
enumeraciones y estructuras.
Diseño de miembros instrucciones para diseñar y uLlizar propiedades, métodos,
constructores, campos, eventos y operadores. Esta sección
también describe los procedimientos recomendados para diseñar
parámetros.
Diseño de excepciones instrucciones de diseño para diseñar, iniciar y detectar excepciones.
Directrices para la programación Framework Design Guidelines
Diseño de extensibilidad instrucciones para diseñar bibliotecas que se pueden extender.
34
Nomenclatura instrucciones para denominar Lpos y miembros en las bibliotecas
de clases.
Diseño de 6pos instrucciones para uLlizar clases estáLcas y abstractas, interfaces,
enumeraciones y estructuras.
Diseño de miembros instrucciones para diseñar y uLlizar propiedades, métodos,
constructores, campos, eventos y operadores. Esta sección
también describe los procedimientos recomendados para diseñar
parámetros.
Diseño de excepciones instrucciones de diseño para diseñar, iniciar y detectar excepciones.
Diseño de extensibilidad instrucciones para diseñar bibliotecas que se pueden extender.
Directrices para la programación Framework Design Guidelines
35
Uso de minúsculas y mayúsculas Cuando un idenLficador está compuesto de varias palabras, no uLlizar separadores, como guiones de subrayado ("_") ni guiones ("-‐"), entre las palabras. En su lugar, uLlizar la mayúscula para señalar el principio de cada palabra.
Convenciones generales de nomenclatura Elegir nombres fácilmente legibles para los idenLficadores. Por ejemplo, una propiedad denominada HorizontalAlignment es más legible en inglés que AlignmentHorizontal. Es preferible la legibilidad a la brevedad. El nombre de propiedad CanScrollHorizontally es mejor que ScrollableX (una referencia oculta al eje X). No uLlizar guiones de subrayado, guiones ni ningún otro carácter no alfanumérico.
Framework Design Guidelines
Nombres de ensamblados y bibliotecas DLL Elegir nombres para las DLL que sugieran grandes fragmentos de funcionalidad como System.Data. Seguir el siguiente modelo:
Nombres de espacios de nombres Debería indicar la funcionalidad que proporcionan los Lpos incluidos en el espacio de nombres. Por ejemplo, System.Net.Sockets conLene Lpos que permiten a los desarrolladores uLlizar sockets para realizar comunicaciones a través de las redes.
Nombres de clases, estructuras e interfaces No uLlizar prefijos para los nombres de clases (como la letra C). Las interfaces, que deberían comenzar con la letra I, son la excepción a esta regla. Considerar finalizar los nombres de las clases derivadas con el nombre de la clase base.
Nombres de miembros de Ipos, parámetros Métodos: proporcionar nombres de métodos que sean verbos ya que facilita a los desarrolladores la comprensión de lo que hace el método. Propiedades: asignar nombres a las propiedades mediante un sustanLvo, un sintagma nominal o un adjeLvo.
<Company>.<Component>.dll
Donde <Component> conLene una o más cláusulas separadas por puntos:
Contoso.WebControls.dll
<Company>.(<Product>|<Technology>)[.<Feature>][.<Subnamespace>]
Nomenclatura
Uso de minúsculas y mayúsculas Cuando un idenLficador está compuesto de varias palabras, no uLlizar separadores, como guiones de subrayado ("_") ni guiones ("-‐"), entre las palabras. En su lugar, uLlizar la mayúscula para señalar el principio de cada palabra.
Convenciones generales de nomenclatura
Nombres de ensamblados y bibliotecas DLL Elegir nombres para las DLL que sugieran grandes fragmentos de funcionalidad como System.Data. Seguir el siguiente modelo:
Nombres de espacios de nombres Debería indicar la funcionalidad que proporcionan los Lpos incluidos en el espacio de nombres. Por ejemplo, System.Net.Sockets conLene Lpos que permiten a los desarrolladores uLlizar sockets para realizar comunicaciones a través de las redes.
Nombres de clases, estructuras e interfaces No uLlizar prefijos para los nombres de clases (como la letra C). Las interfaces, que deberían comenzar con la letra I, son la excepción a esta regla. Considerar finalizar los nombres de las clases derivadas con el nombre de la clase base.
Nombres de miembros de Ipos, parámetros Métodos: proporcionar nombres de métodos que sean verbos ya que facilita a los desarrolladores la comprensión de lo que hace el método. Propiedades: asignar nombres a las propiedades mediante un sustanLvo, un sintagma nominal o un adjeLvo.
<Company>.<Component>.dll
Donde <Component> conLene una o más cláusulas separadas por puntos:
Contoso.WebControls.dll
<Company>.(<Product>|<Technology>)[.<Feature>][.<Subnamespace>]
Elegir nombres fácilmente legibles para los idenLficadores. Por ejemplo, una propiedad denominada HorizontalAlignment es más legible en inglés que AlignmentHorizontal. Es preferible la legibilidad a la brevedad. El nombre de propiedad CanScrollHorizontally es mejor que ScrollableX (una referencia oculta al eje X). No uLlizar guiones de subrayado, guiones ni ningún otro carácter no alfanumérico.
Framework Design Guidelines Nomenclatura
37
Case
AppDomain
Ejemplo iden6ficador
class
Tipo de enumeración
Event
Valores de enumeración
Clase de excepción
Campo estáIco de sólo lectura
Pascal
Pascal
Pascal
Pascal
Pascal
Pascal
interface Pascal
Método Pascal
Espacio de nombres Pascal
Parámetro Camel
Propiedad Pascal
ErrorLevel
FatalError
ValueChanged
WebException
RedValue
IDisposable
ToString
System.Drawing
typeName
BackColor
Framework Design Guidelines Nomenclatura
Uso de minúsculas y mayúsculas ULlizar la gra^a Pascal para todos los nombres de miembros públicos, 6pos y espacios de nombres que constan de varias palabras. ULlizar el uso combinado de mayúsculas y minúsculas Lpo Camel para los nombres de parámetros.
Gra^a Pascal La primera letra del idenLficador y la primera letra de las siguientes palabras concatenadas están en mayúsculas. El esLlo de mayúsculas y minúsculas Pascal se puede uLlizar en idenLficadores de tres o más caracteres. Por ejemplo:
Gra^a Camel La primera letra del idenLficador está en minúscula y la primera letra de las siguientes palabras concatenadas en mayúscula. Por ejemplo:
BackColor
backColor
Uso de minúsculas y mayúsculas Cuando un idenLficador está compuesto de varias palabras, no uLlizar separadores, como guiones de subrayado ("_") ni guiones ("-‐"), entre las palabras. En su lugar, uLlizar la mayúscula para señalar el principio de cada palabra.
Convenciones generales de nomenclatura
Nombres de ensamblados y bibliotecas DLL Elegir nombres para las DLL que sugieran grandes fragmentos de funcionalidad como System.Data. Seguir el siguiente modelo:
Nombres de espacios de nombres Debería indicar la funcionalidad que proporcionan los Lpos incluidos en el espacio de nombres. Por ejemplo, System.Net.Sockets conLene Lpos que permiten a los desarrolladores uLlizar sockets para realizar comunicaciones a través de las redes.
Nombres de clases, estructuras e interfaces No uLlizar prefijos para los nombres de clases (como la letra C). Las interfaces, que deberían comenzar con la letra I, son la excepción a esta regla. Considerar finalizar los nombres de las clases derivadas con el nombre de la clase base.
Nombres de miembros de Ipos, parámetros Métodos: proporcionar nombres de métodos que sean verbos ya que facilita a los desarrolladores la comprensión de lo que hace el método. Propiedades: asignar nombres a las propiedades mediante un sustanLvo, un sintagma nominal o un adjeLvo.
<Company>.<Component>.dll
Donde <Component> conLene una o más cláusulas separadas por puntos:
Contoso.WebControls.dll
<Company>.(<Product>|<Technology>)[.<Feature>][.<Subnamespace>]
Elegir nombres fácilmente legibles para los idenLficadores. Por ejemplo, una propiedad denominada HorizontalAlignment es más legible en inglés que AlignmentHorizontal. Es preferible la legibilidad a la brevedad. El nombre de propiedad CanScrollHorizontally es mejor que ScrollableX (una referencia oculta al eje X). No uLlizar guiones de subrayado, guiones ni ningún otro carácter no alfanumérico.
Framework Design Guidelines Nomenclatura
Uso de minúsculas y mayúsculas Cuando un idenLficador está compuesto de varias palabras, no uLlizar separadores, como guiones de subrayado ("_") ni guiones ("-‐"), entre las palabras. En su lugar, uLlizar la mayúscula para señalar el principio de cada palabra.
Convenciones generales de nomenclatura
Nombres de ensamblados y bibliotecas DLL Elegir nombres para las DLL que sugieran grandes fragmentos de funcionalidad como System.Data. Seguir el siguiente modelo:
Nombres de espacios de nombres Debería indicar la funcionalidad que proporcionan los Lpos incluidos en el espacio de nombres. Por ejemplo, System.Net.Sockets conLene Lpos que permiten a los desarrolladores uLlizar sockets para realizar comunicaciones a través de las redes.
Nombres de clases, estructuras e interfaces No uLlizar prefijos para los nombres de clases (como la letra C). Las interfaces, que deberían comenzar con la letra I, son la excepción a esta regla. Considerar finalizar los nombres de las clases derivadas con el nombre de la clase base.
Nombres de miembros de Ipos, parámetros Métodos: proporcionar nombres de métodos que sean verbos ya que facilita a los desarrolladores la comprensión de lo que hace el método. Propiedades: asignar nombres a las propiedades mediante un sustanLvo, un sintagma nominal o un adjeLvo.
<Company>.<Component>.dll
Donde <Component> conLene una o más cláusulas separadas por puntos:
Contoso.WebControls.dll
<Company>.(<Product>|<Technology>)[.<Feature>][.<Subnamespace>]
Elegir nombres fácilmente legibles para los idenLficadores. Por ejemplo, una propiedad denominada HorizontalAlignment es más legible en inglés que AlignmentHorizontal. Es preferible la legibilidad a la brevedad. El nombre de propiedad CanScrollHorizontally es mejor que ScrollableX (una referencia oculta al eje X). No uLlizar guiones de subrayado, guiones ni ningún otro carácter no alfanumérico.
Framework Design Guidelines Nomenclatura
Uso de minúsculas y mayúsculas Cuando un idenLficador está compuesto de varias palabras, no uLlizar separadores, como guiones de subrayado ("_") ni guiones ("-‐"), entre las palabras. En su lugar, uLlizar la mayúscula para señalar el principio de cada palabra.
Convenciones generales de nomenclatura
Nombres de ensamblados y bibliotecas DLL Elegir nombres para las DLL que sugieran grandes fragmentos de funcionalidad como System.Data. Seguir el siguiente modelo:
Nombres de espacios de nombres Debería indicar la funcionalidad que proporcionan los Lpos incluidos en el espacio de nombres. Por ejemplo, System.Net.Sockets conLene Lpos que permiten a los desarrolladores uLlizar sockets para realizar comunicaciones a través de las redes.
Nombres de clases, estructuras e interfaces No uLlizar prefijos para los nombres de clases (como la letra C). Las interfaces, que deberían comenzar con la letra I, son la excepción a esta regla. Considerar finalizar los nombres de las clases derivadas con el nombre de la clase base.
Nombres de miembros de Ipos, parámetros Métodos: proporcionar nombres de métodos que sean verbos ya que facilita a los desarrolladores la comprensión de lo que hace el método. Propiedades: asignar nombres a las propiedades mediante un sustanLvo, un sintagma nominal o un adjeLvo.
<Company>.<Component>.dll
Donde <Component> conLene una o más cláusulas separadas por puntos:
Contoso.WebControls.dll
<Company>.(<Product>|<Technology>)[.<Feature>][.<Subnamespace>]
Elegir nombres fácilmente legibles para los idenLficadores. Por ejemplo, una propiedad denominada HorizontalAlignment es más legible en inglés que AlignmentHorizontal. Es preferible la legibilidad a la brevedad. El nombre de propiedad CanScrollHorizontally es mejor que ScrollableX (una referencia oculta al eje X). No uLlizar guiones de subrayado, guiones ni ningún otro carácter no alfanumérico.
Framework Design Guidelines Nomenclatura
Uso de minúsculas y mayúsculas Cuando un idenLficador está compuesto de varias palabras, no uLlizar separadores, como guiones de subrayado ("_") ni guiones ("-‐"), entre las palabras. En su lugar, uLlizar la mayúscula para señalar el principio de cada palabra.
Convenciones generales de nomenclatura
Nombres de ensamblados y bibliotecas DLL Elegir nombres para las DLL que sugieran grandes fragmentos de funcionalidad como System.Data. Seguir el siguiente modelo:
Nombres de espacios de nombres Debería indicar la funcionalidad que proporcionan los Lpos incluidos en el espacio de nombres. Por ejemplo, System.Net.Sockets conLene Lpos que permiten a los desarrolladores uLlizar sockets para realizar comunicaciones a través de las redes.
Nombres de clases, estructuras e interfaces No uLlizar prefijos para los nombres de clases (como la letra C). Las interfaces, que deberían comenzar con la letra I, son la excepción a esta regla. Considerar finalizar los nombres de las clases derivadas con el nombre de la clase base.
Nombres de miembros de Ipos, parámetros Métodos: proporcionar nombres de métodos que sean verbos ya que facilita a los desarrolladores la comprensión de lo que hace el método. Propiedades: asignar nombres a las propiedades mediante un sustanLvo, un sintagma nominal o un adjeLvo.
<Company>.<Component>.dll
Donde <Component> conLene una o más cláusulas separadas por puntos:
Contoso.WebControls.dll
<Company>.(<Product>|<Technology>)[.<Feature>][.<Subnamespace>]
Elegir nombres fácilmente legibles para los idenLficadores. Por ejemplo, una propiedad denominada HorizontalAlignment es más legible en inglés que AlignmentHorizontal. Es preferible la legibilidad a la brevedad. El nombre de propiedad CanScrollHorizontally es mejor que ScrollableX (una referencia oculta al eje X). No uLlizar guiones de subrayado, guiones ni ningún otro carácter no alfanumérico.
Framework Design Guidelines Nomenclatura
42
Nomenclatura instrucciones para denominar Lpos y miembros en las bibliotecas
de clases.
Diseño de 6pos instrucciones para uLlizar clases estáLcas y abstractas, interfaces,
enumeraciones y estructuras.
Diseño de miembros instrucciones para diseñar y uLlizar propiedades, métodos,
constructores, campos, eventos y operadores. Esta sección
también describe los procedimientos recomendados para diseñar
parámetros.
Diseño de excepciones instrucciones de diseño para diseñar, iniciar y detectar excepciones.
Directrices para la programación Framework Design Guidelines
Diseño de extensibilidad instrucciones para diseñar bibliotecas que se pueden extender.
43
Diseño de clases abstractas GaranLzar que la funcionalidad de la clase abstracta sea correcta y se pueda extender con facilidad. No definir constructores de Lpo public. Deberán ser los Lpos concretos (hijos) quienes deban tener constructores públicos.
Framework Design Guidelines Diseño de 6pos
Una interfaz define las firmas para un conjunto de miembros (métodos, etc.) que deben proporcionar los implementadores. Las interfaces no pueden proporcionar los detalles de implementación para los miembros. Las clases pueden implementar varias interfaces. Considerar la posibilidad de definir interfaces para lograr un efecto similar al de la herencia múlLple.
Elegir entre clases e interfaces
Diseño de enumeraciones Las enumeraciones proporcionan conjuntos de valores constantes que son úLles para la definición inflexible de Lpos de miembros y mejorar la legibilidad del código. No uLlizar una enumeración para conjuntos abiertos como la versión del sistema operaLvo.
44
Diseño de clases abstractas GaranLzar que la funcionalidad de la clase abstracta sea correcta y se pueda extender con facilidad. No definir constructores de Lpo public. Deberán ser los Lpos concretos (hijos) quienes deban tener constructores públicos.
Framework Design Guidelines Diseño de 6pos
Una interfaz define las firmas para un conjunto de miembros (métodos, etc.) que deben proporcionar los implementadores. Las interfaces no pueden proporcionar los detalles de implementación para los miembros. Las clases pueden implementar varias interfaces. Considerar la posibilidad de definir interfaces para lograr un efecto similar al de la herencia múlLple.
Elegir entre clases e interfaces
Diseño de enumeraciones Las enumeraciones proporcionan conjuntos de valores constantes que son úLles para la definición inflexible de Lpos de miembros y mejorar la legibilidad del código. No uLlizar una enumeración para conjuntos abiertos como la versión del sistema operaLvo.
45
Diseño de clases abstractas GaranLzar que la funcionalidad de la clase abstracta sea correcta y se pueda extender con facilidad. No definir constructores de Lpo public. Deberán ser los Lpos concretos (hijos) quienes deban tener constructores públicos.
Framework Design Guidelines Diseño de 6pos
Una interfaz define las firmas para un conjunto de miembros (métodos, etc.) que deben proporcionar los implementadores. Las interfaces no pueden proporcionar los detalles de implementación para los miembros. Las clases pueden implementar varias interfaces. Considerar la posibilidad de definir interfaces para lograr un efecto similar al de la herencia múlLple.
Elegir entre clases e interfaces
Diseño de enumeraciones
public static class BadFurnishings { public static int Table = 1; public static int Chair = 2; public static int Lamp = 3; }
public enum GoodFurnishings { Table, Chair, Lamp }
El ejemplo de código siguiente muestra un diseño incorrecto.
la enumeración que se debería uLlizar en lugar de las constantes estáLcas.
Las enumeraciones proporcionan conjuntos de valores constantes que son úLles para la definición inflexible de Lpos de miembros y mejorar la legibilidad del código. No uLlizar una enumeración para conjuntos abiertos como la versión del sistema operaLvo.
46
Nomenclatura instrucciones para denominar Lpos y miembros en las bibliotecas
de clases.
Diseño de 6pos instrucciones para uLlizar clases estáLcas y abstractas, interfaces,
enumeraciones y estructuras.
Diseño de miembros instrucciones para diseñar y uLlizar propiedades, métodos,
constructores, campos, eventos y operadores. Esta sección
también describe los procedimientos recomendados para diseñar
parámetros.
Diseño de excepciones instrucciones de diseño para diseñar, iniciar y detectar excepciones.
Directrices para la programación Framework Design Guidelines
Diseño de extensibilidad instrucciones para diseñar bibliotecas que se pueden extender.
47
Sobrecarga de métodos GaranLzar que la funcionalidad de la clase abstracta sea correcta y se pueda extender con facilidad. No definir constructores de Lpo public. Deberán ser los Lpos concretos (hijos) quienes deban tener constructores públicos.
Framework Design Guidelines Diseño de miembros
En general, los métodos representan acciones y las propiedades representan datos. ULlizar una propiedad, en lugar de un método, si el valor de la propiedad está almacenado en la memoria del proceso (clase) y la propiedad sólo proporcionaría acceso al valor.
Elegir entre propiedades y métodos
Diseño de propiedades Crear propiedades de sólo lectura si el llamador no debería poder cambiar sus valores. Proporcionar valores predeterminados sensatos para todas las propiedades, garanLzando que esos valores predeterminados no producen una vulnerabilidad de seguridad o un diseño sumamente ineficiente.
Diseño de constructores
Diseño de eventos
Proporcionar constructores sencillos. Un constructor sencillo Lene un número muy pequeño de parámetros.
Los eventos son mecanismos que permiten al código específico de la aplicación ejecutarse cuando se produce una acción. ULlice System.EventHandler<T> en lugar de crear manualmente nuevos delegados que se van a uLlizar como controladores de eventos.
Diseño de campos No proporcione campos de instancia que sean públicos o protegidos. En lugar de uLlizar campos públicamente visibles, uLlice campos privados y expóngalos mediante propiedades. ULlizar campos constantes para las constantes que nunca vayan a cambiar.
Sobrecarga de métodos GaranLzar que la funcionalidad de la clase abstracta sea correcta y se pueda extender con facilidad. No definir constructores de Lpo public. Deberán ser los Lpos concretos (hijos) quienes deban tener constructores públicos.
Framework Design Guidelines Diseño de miembros
En general, los métodos representan acciones y las propiedades representan datos. ULlizar una propiedad, en lugar de un método, si el valor de la propiedad está almacenado en la memoria del proceso (clase) y la propiedad sólo proporcionaría acceso al valor.
Elegir entre propiedades y métodos
Diseño de propiedades Crear propiedades de sólo lectura si el llamador no debería poder cambiar sus valores. Proporcionar valores predeterminados sensatos para todas las propiedades, garanLzando que esos valores predeterminados no producen una vulnerabilidad de seguridad o un diseño sumamente ineficiente.
public class EmployeeRecord { private int employeeId; private int department; public EmployeeRecord() { } public EmployeeRecord (int id, int departmentId) { EmployeeId = id; Department = departmentId; } public int Department { get {return department;} set {department = value;} } public int EmployeeId { get {return employeeId;} set {employeeId = value;} } public EmployeeRecord Clone() { return new EmployeeRecord(employeeId, department); } }
Sobrecarga de métodos GaranLzar que la funcionalidad de la clase abstracta sea correcta y se pueda extender con facilidad. No definir constructores de Lpo public. Deberán ser los Lpos concretos (hijos) quienes deban tener constructores públicos.
Framework Design Guidelines Diseño de miembros
En general, los métodos representan acciones y las propiedades representan datos. ULlizar una propiedad, en lugar de un método, si el valor de la propiedad está almacenado en la memoria del proceso (clase) y la propiedad sólo proporcionaría acceso al valor.
Elegir entre propiedades y métodos
Diseño de propiedades Crear propiedades de sólo lectura si el llamador no debería poder cambiar sus valores. Proporcionar valores predeterminados sensatos para todas las propiedades, garanLzando que esos valores predeterminados no producen una vulnerabilidad de seguridad o un diseño sumamente ineficiente.
Diseño de constructores
Diseño de eventos
Proporcionar constructores sencillos. Un constructor sencillo Lene un número muy pequeño de parámetros.
Los eventos son mecanismos que permiten al código específico de la aplicación ejecutarse cuando se produce una acción. ULlice System.EventHandler<T> en lugar de crear manualmente nuevos delegados que se van a uLlizar como controladores de eventos.
Diseño de campos No proporcione campos de instancia que sean públicos o protegidos. En lugar de uLlizar campos públicamente visibles, uLlice campos privados y expóngalos mediante propiedades. ULlizar campos constantes para las constantes que nunca vayan a cambiar.
Sobrecarga de métodos GaranLzar que la funcionalidad de la clase abstracta sea correcta y se pueda extender con facilidad. No definir constructores de Lpo public. Deberán ser los Lpos concretos (hijos) quienes deban tener constructores públicos.
Framework Design Guidelines Diseño de miembros
En general, los métodos representan acciones y las propiedades representan datos. ULlizar una propiedad, en lugar de un método, si el valor de la propiedad está almacenado en la memoria del proceso (clase) y la propiedad sólo proporcionaría acceso al valor.
Elegir entre propiedades y métodos
Diseño de propiedades Crear propiedades de sólo lectura si el llamador no debería poder cambiar sus valores. Proporcionar valores predeterminados sensatos para todas las propiedades, garanLzando que esos valores predeterminados no producen una vulnerabilidad de seguridad o un diseño sumamente ineficiente.
Diseño de constructores Proporcionar constructores sencillos. Un constructor sencillo Lene un número muy pequeño de parámetros.
Diseño de eventos Los eventos son mecanismos que permiten al código específico de la aplicación ejecutarse cuando se produce una acción. ULlice System.EventHandler<T> en lugar de crear manualmente nuevos delegados que se van a uLlizar como controladores de eventos.
Diseño de campos No proporcione campos de instancia que sean públicos o protegidos. En lugar de uLlizar campos públicamente visibles, uLlice campos privados y expóngalos mediante propiedades. ULlizar campos constantes para las constantes que nunca vayan a cambiar.
Sobrecarga de métodos GaranLzar que la funcionalidad de la clase abstracta sea correcta y se pueda extender con facilidad. No definir constructores de Lpo public. Deberán ser los Lpos concretos (hijos) quienes deban tener constructores públicos.
Framework Design Guidelines Diseño de miembros
En general, los métodos representan acciones y las propiedades representan datos. ULlizar una propiedad, en lugar de un método, si el valor de la propiedad está almacenado en la memoria del proceso (clase) y la propiedad sólo proporcionaría acceso al valor.
Elegir entre propiedades y métodos
Diseño de propiedades Crear propiedades de sólo lectura si el llamador no debería poder cambiar sus valores. Proporcionar valores predeterminados sensatos para todas las propiedades, garanLzando que esos valores predeterminados no producen una vulnerabilidad de seguridad o un diseño sumamente ineficiente.
Diseño de constructores Proporcionar constructores sencillos. Un constructor sencillo Lene un número muy pequeño de parámetros.
Diseño de eventos
Diseño de campos No proporcione campos de instancia que sean públicos o protegidos. En lugar de uLlizar campos públicamente visibles, uLlice campos privados y expóngalos mediante propiedades. ULlizar campos constantes para las constantes que nunca vayan a cambiar.
Los eventos son mecanismos que permiten al código específico de la aplicación ejecutarse cuando se produce una acción. ULlice System.EventHandler<T> en lugar de crear manualmente nuevos delegados que se van a uLlizar como controladores de eventos.
Sobrecarga de métodos GaranLzar que la funcionalidad de la clase abstracta sea correcta y se pueda extender con facilidad. No definir constructores de Lpo public. Deberán ser los Lpos concretos (hijos) quienes deban tener constructores públicos.
Framework Design Guidelines Diseño de miembros
En general, los métodos representan acciones y las propiedades representan datos. ULlizar una propiedad, en lugar de un método, si el valor de la propiedad está almacenado en la memoria del proceso (clase) y la propiedad sólo proporcionaría acceso al valor.
Elegir entre propiedades y métodos
Diseño de propiedades Crear propiedades de sólo lectura si el llamador no debería poder cambiar sus valores. Proporcionar valores predeterminados sensatos para todas las propiedades, garanLzando que esos valores predeterminados no producen una vulnerabilidad de seguridad o un diseño sumamente ineficiente.
Diseño de constructores
Diseño de eventos
Diseño de campos No proporcione campos de instancia que sean públicos o protegidos. En lugar de uLlizar campos públicamente visibles, uLlice campos privados y expóngalos mediante propiedades. ULlizar campos constantes para las constantes que nunca vayan a cambiar.
Proporcionar constructores sencillos. Un constructor sencillo Lene un número muy pequeño de parámetros.
Los eventos son mecanismos que permiten al código específico de la aplicación ejecutarse cuando se produce una acción. ULlice System.EventHandler<T> en lugar de crear manualmente nuevos delegados que se van a uLlizar como controladores de eventos.
53
Nomenclatura instrucciones para denominar Lpos y miembros en las bibliotecas
de clases.
Diseño de 6pos instrucciones para uLlizar clases estáLcas y abstractas, interfaces,
enumeraciones y estructuras.
Diseño de miembros instrucciones para diseñar y uLlizar propiedades, métodos,
constructores, campos, eventos y operadores. Esta sección
también describe los procedimientos recomendados para diseñar
parámetros.
Diseño de excepciones instrucciones de diseño para diseñar, iniciar y detectar excepciones.
Directrices para la programación Framework Design Guidelines
Diseño de extensibilidad instrucciones para diseñar bibliotecas que se pueden extender.
Framework Design Guidelines Diseño de extensibilidad
Capacidad de agregar o modificar el comportamiento de objetos
Framework Design Guidelines Diseño de extensibilidad
Miembros virtuales Un miembro definido como virtual permite al desarrollador cambiar el comportamiento del miembro proporcionando una implementación diferente.
Clases no selladas Una clase no sellada permite a otras clases heredar de ella. De forma predeterminada, la mayoría de las clases no deberían estar selladas. Los desarrolladores pueden agregar un constructor a un Lpo derivado de la clase, y uLlizar ese constructor para inicializar las propiedades de la clase base con los valores necesarios para el escenario.
Tipos e interfaces abstractos Son mecanismos para especificar abstracciones de programación. Una abstracción especifica un contrato al que se deben adherir los herederos o implementadores.
Clases base para implementar abstracciones Son clases diseñadas para ayudar a los desarrolladores a implementar clases abstractas e interfaces (abstracciones). Proporcionan algunos de los detalles de implementación de una abstracción y en algunos casos pueden uLlizarse sin herencia.
Framework Design Guidelines Diseño de extensibilidad
Miembros virtuales Un miembro definido como virtual permite al desarrollador cambiar el comportamiento del miembro proporcionando una implementación diferente.
Clases no selladas Una clase no sellada permite a otras clases heredar de ella. De forma predeterminada, la mayoría de las clases no deberían estar selladas. Los desarrolladores pueden agregar un constructor a un Lpo derivado de la clase, y uLlizar ese constructor para inicializar las propiedades de la clase base con los valores necesarios para el escenario.
class A { public virtual void G() { Console.WriteLine("A.G"); } } class B : A { public override void G() { Console.WriteLine("B.G"); } }
Tipos e interfaces abstractos Son mecanismos para especificar abstracciones de programación. Una abstracción especifica un contrato al que se deben adherir los herederos o implementadores.
Framework Design Guidelines Diseño de extensibilidad
Miembros virtuales Un miembro definido como virtual permite al desarrollador cambiar el comportamiento del miembro proporcionando una implementación diferente.
Clases no selladas Una clase no sellada permite a otras clases heredar de ella. De forma predeterminada, la mayoría de las clases no deberían estar selladas. Los desarrolladores pueden agregar un constructor a un Lpo derivado de la clase, y uLlizar ese constructor para inicializar las propiedades de la clase base con los valores necesarios para el escenario.
Tipos e interfaces abstractos Son mecanismos para especificar abstracciones de programación. Una abstracción especifica un contrato al que se deben adherir los herederos o implementadores.
Clases base para implementar abstracciones Son clases diseñadas para ayudar a los desarrolladores a implementar clases abstractas e interfaces (abstracciones). Proporcionan algunos de los detalles de implementación de una abstracción y en algunos casos pueden uLlizarse sin herencia.
Framework Design Guidelines Diseño de extensibilidad
Miembros virtuales Un miembro definido como virtual permite al desarrollador cambiar el comportamiento del miembro proporcionando una implementación diferente.
Clases no selladas Una clase no sellada permite a otras clases heredar de ella. De forma predeterminada, la mayoría de las clases no deberían estar selladas. Los desarrolladores pueden agregar un constructor a un Lpo derivado de la clase, y uLlizar ese constructor para inicializar las propiedades de la clase base con los valores necesarios para el escenario.
Tipos e interfaces abstractos Son mecanismos para especificar abstracciones de programación. Una abstracción especifica un contrato al que se deben adherir los herederos o implementadores.
Clases base para implementar abstracciones Son clases diseñadas para ayudar a los desarrolladores a implementar clases abstractas e interfaces (abstracciones). Proporcionan algunos de los detalles de implementación de una abstracción y en algunos casos pueden uLlizarse sin herencia.
59
Nomenclatura instrucciones para denominar Lpos y miembros en las bibliotecas
de clases.
Diseño de 6pos instrucciones para uLlizar clases estáLcas y abstractas, interfaces,
enumeraciones y estructuras.
Diseño de miembros instrucciones para diseñar y uLlizar propiedades, métodos,
constructores, campos, eventos y operadores. Esta sección
también describe los procedimientos recomendados para diseñar
parámetros.
Diseño de excepciones instrucciones de diseño para diseñar, iniciar y detectar excepciones.
Directrices para la programación Framework Design Guidelines
Diseño de extensibilidad instrucciones para diseñar bibliotecas que se pueden extender.
Framework Design Guidelines Diseño de excepciones
Generación de excepciones No devolver códigos de error. Las excepciones son el principal medio de informar de los errores producidos.
public void ProcessMessage(string message) { if (message == null) { throw new ArgumentNullException("message"); } … }
Diseñar excepciones personalizadas Evitar la jerarquía de excepciones profunda. Derivar las excepciones de System.Exception o de una de las demás excepciones de base comunes. Finalizar los nombres de clases de excepción con el sufijo Exception.
public class NewException : BaseException, ISerializable { public NewException() { // Add implementation. } public NewException(string message) { // Add implementation. } public NewException(string message, Exception inner) { // Add implementation. } // This constructor is needed for serialization. protected NewException(SerializationInfo info, StreamingContext context) { // Add implementation. } }
Framework Design Guidelines Diseño de excepciones
Generación de excepciones No devolver códigos de error. Las excepciones son el principal medio de informar de los errores producidos.
public void ProcessMessage(string message) { if (message == null) { throw new ArgumentNullException("message"); } … }
Diseñar excepciones personalizadas Evitar la jerarquía de excepciones profunda. Derivar las excepciones de System.Exception o de una de las demás excepciones de base comunes. Finalizar los nombres de clases de excepción con el sufijo Exception.
public class YourException : BaseException, ISerializable { public YourException() { // Add implementation. } public YourException(string message) { // Add implementation. } public YourException(string message, Exception inner) { // Add implementation. } // This constructor is needed for serialization. protected YourException(SerializationInfo info, StreamingContext context) { // Add implementation. } }
Una clase define un 6po de objeto, pero no es propiamente un objeto
Clases y Objetos ¿Quién es quién?
Un objeto es una en6dad concreta basada en una clase. Se suele denominar instancia de una clase.
Clases y Objetos ¿Quién es quién?
Los objetos se pueden crear con la palabra clave new seguida del nombre de la clase en la que se
basará el objeto
Clases y Objetos ¿Quién es quién?
new <nombreClase>(<parámetros>)
Customer object1 = new Customer();
Palabra reservada this Hace referencia a la instancia actual de la clase
Clases y Objetos ¿Quién es quién?
class Person { private string firstName; private string lastName; private int age; public Person(string firstname) { this.firstname = firstname; } }
Calificar miembros con el fin de evitar ambigüedades con nombres similares:
Palabra reservada this
Pasar un objeto como parámetro a otros métodos:
PrintReport(this)
Declarar indizadores:
public int this[int param] { get { return array[param]; } set { array[param] = value; } }
Clases y Objetos ¿Quién es quién?
Tipos, variables y valores C# es un lenguaje fuertemente Lpado. Todas las variables y constantes Lenen un Lpo.
La biblioteca de clases .NET Framework define un conjunto de Lpos numéricos integrados y Lpos más complejos que representan una amplia variedad de construcciones lógicas, como el sistema de archivos, conexiones de red, colecciones y matrices de objetos y fechas.
Clases y Objetos Tipos, valores y variables
Al declarar una variable o una constante en un programa, debemos especificar su 6po o u6lizar la palabra clave var para permiLr que el compilador infiera el Lpo.
// Declaration only float temperature; string name; MyClass myClass; // Declaration with initializers (four examples) char firstLetter = 'C'; var limit = 3; int[] source = { 0, 1, 2, 3, 4, 5 }; var query = from item in source where item <= limit select item;
Tipos integrados
Tipos personalizados
conjunto estándar que C# proporciona de Lpos numéricos integrados para representar enteros, valores de punto flotante, expresiones Boolean, caracteres de texto, valores decimales y otros Lpos de datos. También hay Lpos object y string integrados. int, bool, byte, char, float, double, object, string, …
las construcciones struct, class, interface y enum se uLlizan para crear sus propios Lpos personalizados. La biblioteca de clases de .NET Framework en sí es una colección de Lpos personalizados proporcionada por MicrosoR que el programador puede uLlizar en sus propias aplicaciones.
Clases y Objetos Tipos, valores y variables
Dos puntos fundamentales sobre el sistema de Lpos en .NET Framework:
• admite el principio de herencia
• cada uno de los Lpos se define como un 6po de valor o un 6po de
referencia
SISTEMA DE TIPOS
Los Lpos pueden derivarse de otros Lpos denominados Lpos base. El Lpo derivado hereda (con algunas restricciones) los métodos, las propiedades y otros miembros del Lpo base.
Esto incluye todos los Lpos personalizados de la biblioteca de clases .NET Framework y también los Lpos propios definidos por el usuario. Los Lpos que definamos mediante la palabra clave struct son Lpos de valor; todos los Lpos numéricos integrados son structs. Los Lpos que definamos mediante la palabra clave class son Lpos de referencia.
Clases y Objetos Tipos, valores y variables Tipos de valor y referencia
C# 6ene dos variedades de 6pos: valor y referencia
Las variables de 6pos referencia almacenan referencias a sus datos (objetos)
Las variables de 6pos de valor con6enen directamente los datos
Las variables de Lpo de valor con6enen directamente sus valores en la memoria asignada en la pila. Los Lpos de valor son todos los 6pos de datos integrados básicos o una estructura definida por el usuario. Una excepción es el Lpo de datos string, que es un Lpo de referencia.
Los Lpos de valor derivan de System.ValueType, que a su vez deriva de System.Object. Con Lpos de valor, cada variable Lene su propia copia de los datos, y no es posible que las operaciones en una variable afecten a otra.
Tipos de valor
int x = 42; Cuando la variable x queda fuera de ámbito, porque el método en que se definió ha finalizado su ejecución, el valor se descarta de la pila.
Clases y Objetos Tipos, valores y variables Tipos de valor y referencia
74
REPRESENTS DEFAULT VALUE
Boolean value
8-‐bit unsigned integer
16-‐bit Unicode character
128-‐bit precise decimal values with 28-‐29 significant digits
64-‐bit double-‐precision floaIng point type
32-‐bit single-‐precision floaIng point type
-‐2.147.483.648 to 2.147.483.647
false
0
’\0’
0.0M
0
true or false
0 to 255
U +0000 to U +ffff
(-‐7.9 x 1028 to 7.9 x 1028) / 100 to 28
(+/-‐)5.0x10-‐324 to (+/-‐)1.7x10308
-‐3.4x1038 to +3.4x1038
-‐128 to 127
RANGE TYPE
bool
byte
decimal
char
double
int
float
short
sbyte
32-‐bit signed integer type
long 64-‐bit signed integer type
8-‐bit signed integer type
-‐923.372.036.854.775.808 to 9.223.372.036.854.775.807
0.0D
0.0F
0L
0
16-‐bit signed integer type
uint 32-‐bit unsigned integer type
ulong 64-‐bit unsigned integer type
-‐32.768 to 32,767
0 to 4.294.967.295
0 to 18.446.744.073.709.551.615
0
0
ushort 16-‐bit unsigned integer type 0 to 65535
0
0
Tipos de valor
Tipos de referencia
Las variables de Lpos referencia almacenan referencias a sus datos (objetos). Con los Lpos referencia, dos variables pueden hacer referencia al mismo objeto; por consiguiente, las operaciones en una variable pueden afectar al objeto referenciado por otra variable.
La memoria consumida por c1 no se devuelve al montón cuando finaliza el método; sólo se reclama cuando el sistema de recolección de elementos no uBlizados de C# determina que ya no la necesita.
Customer c1 = new Customer(”Joe");
Las palabras clave siguientes se usan para declarar Lpos de referencia:
class
interface
delegate
C# también proporciona los siguientes Ipos de referencia integrados:
dynamic
Object
string
Se dice que c1 es una referencia a un objeto de Lpo Customer. Esta referencia apunta al objeto pero no conLene los datos.
Clases y Objetos Tipos, valores y variables Tipos de valor y referencia
Ejemplo prácLco namespace
En general, las clases se uLlizan para modelar comportamiento más complejo o datos que se piensan modificar una vez creado un objeto de clase. Los structs son más adecuadas para pequeñas estructuras de datos que conLenen principalmente datos que no se piensan modificar una vez creado el struct.
Una clase es un 6po de referencia Cuando se crea un objeto de la clase, la variable a la que se asigna el objeto sólo incluye una referencia a dicha memoria. Cuando la referencia a objeto se asigna a una nueva variable, la nueva variable hace referencia al objeto original. Los cambios realizados en una variable se reflejan en la otra variable porque ambas hacen referencia a los mismos datos.
Un struct es de 6po de valor Cuando se crea un struct, la variable a la que se asigna incluye los datos reales del struct. Cuando el struct se asigna a una nueva variable, se copia. La nueva variable y la variable original conLenen por tanto dos copias independientes de los mismos datos. Los cambios realizados en una copia no afectan a la otra copia.
Clases y Objetos Tipos, valores y variables Tipos de referencia y de valor
Los structs son Bpos de valor y las clases Bpos de referencia
struct
class
class TheClass { public string willIChange; } struct TheStruct { public string willIChange; }
class TestClassAndStruct { static void ClassTaker(TheClass c) { c.willIChange = "Changed"; } static void StructTaker(TheStruct s) { s.willIChange = "Changed"; } static void Main() { TheClass testClass = new TheClass(); TheStruct testStruct = new TheStruct(); testClass.willIChange = "Not Changed"; testStruct.willIChange = "Not Changed"; ClassTaker(testClass); StructTaker(testStruct); Console.WriteLine("Class field = {0}", testClass.willIChange); Console.WriteLine("Struct field = {0}", testStruct.willIChange); // Keep the console window open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); } }
Diferencias entre pasar a un método un struct y una referencia a clase
Clases y Objetos Tipos, valores y variables Tipos de referencia y de valor
Class field = ? Struct field = ? Press any key to exit.
class TheClass { public string willIChange; } struct TheStruct { public string willIChange; }
class TestClassAndStruct { static void ClassTaker(TheClass c) { c.willIChange = "Changed"; } static void StructTaker(TheStruct s) { s.willIChange = "Changed"; } static void Main() { TheClass testClass = new TheClass(); TheStruct testStruct = new TheStruct(); testClass.willIChange = "Not Changed"; testStruct.willIChange = "Not Changed"; ClassTaker(testClass); StructTaker(testStruct); Console.WriteLine("Class field = {0}", testClass.willIChange); Console.WriteLine("Struct field = {0}", testStruct.willIChange); // Keep the console window open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); } }
Class field = Changed Struct field = Not Changed Press any key to exit.
Diferencias entre pasar a un método un struct y una referencia a clase
Clases y Objetos Tipos, valores y variables Tipos de referencia y de valor
Recordemos lo que decíamos hace un rato…
“Las variables de Ipos referencia almacenan referencias a sus datos (objetos). Con los Ipos referencia, dos variables pueden hacer referencia al mismo objeto; por consiguiente, las operaciones en una variable pueden afectar al objeto referenciado por otra variable.”
Recordemos qué decíamos hace un rato…
“Las variables de Ipos referencia almacenan referencias a sus datos (objetos). Con los Ipos referencia, dos variables pueden hacer referencia al mismo objeto; por consiguiente, las operaciones en una variable pueden afectar al objeto referenciado por otra variable.”
Clases y Objetos Tipos, valores y variables
SISTEMA DE TIPOS
Nullables
int? i = 10; double? d1 = 3.14; bool? flag = null; char? letter = 'a'; int?[] arr = new int?[10];
Tipo de dato especial que nos permite indicar a las variables de este Lpo, además de los valores del rango admiLdo, el valor null.
System.Nullable<T> variable_name T? variable_name
Los Lpos que aceptan valores NULL se declaran de dos formas:
T es el Lpo subyacente del Lpo que acepta valores NULL. T puede ser cualquier Lpo de valor incluido struct; no puede ser Lpo de referencia.
using System; namespace CalculatorApplication { class NullablesAtShow { static void Main(string[] args) { int? num1 = null; int? num2 = 45; double? num3 = new double?(); double? num4 = 3.1415; bool? boolval = new bool?(); // display the values Console.WriteLine("Nullables at Show: {0}, {1}, {2}, {3}", num1, num2, num3, num4); Console.WriteLine("A Nullable boolean value: {0}”, boolval); Console.ReadLine(); } } }
?
Nullables EJEMPLO PRÁCTICO
using System; namespace CalculatorApplication { class NullablesAtShow { static void Main(string[] args) { int? num1 = null; int? num2 = 45; double? num3 = new double?(); double? num4 = 3.1415; bool? boolval = new bool?(); // display the values Console.WriteLine("Nullables at Show: {0}, {1}, {2}, {3}", num1, num2, num3, num4); Console.WriteLine("A Nullable boolean value: {0}”, boolval); Console.ReadLine(); } } }
EJEMPLO PRÁCTICO
Nullables at Show: , 45 , , 3.1415 A Nullable boolean value:
Nullables
Clases y Objetos Tipos, valores y variables Nullables
Este Lpo de dato cuenta con dos propiedades de sólo lectura que serán muy ú6les a la hora de trabajar con ellos.
int? x = 10; if (x.HasValue) { System.Console.WriteLine(x.Value); } else { System.Console.WriteLine("Undefined"); }
Es de Lpo bool. Se establece como true cuando la variable conLene un valor que no es null.
HasValue
Value es del mismo Lpo que el Lpo subyacente. Si HasValue es true, Value conLene un valor significaLvo. Si HasValue es false, al tener acceso a Value se producirá una excepción InvalidOperationException.
Value int? y = 10; if (y != null) { System.Console.WriteLine(y.Value); } else { System.Console.WriteLine("Undefined"); }
int i; i = "Hello"; // Error: "Cannot implicitly convert type 'string' to 'int'"
Dado que a C# se le asignan Lpos estáLcos en Lempo de compilación, después de declarar una variable, no se puede volver a declarar ni tampoco uLlizar para almacenar valores de otro Lpo, a menos que dicho Lpo pueda converLrse en el Lpo de la variable.
CONVERSIÓN DE TIPOS
Clases y Objetos Tipos, valores y variables Conversión de 6pos
93
Conversiones implícitas
En los Lpos numéricos integrados, puede realizarse una conversión implícita cuando el valor que se va a almacenar puede ajustarse a la variable sin necesidad de truncamiento o redondeo.
int num = 2147483647; long bigNum = num;
una variable de Bpo long (entero de 8 bytes) puede almacenar cualquier valor que pueda almacenar a su vez
un elemento int (4 bytes en un equipo de 32 bits)
Conversiones explícitas
Requieren un operador de conversión. La conversión se requiere cuando es posible que se pierda información en el proceso. El compilador requiere que se realice una conversión explícita, denominada conversión de Lpo.
double x = 1234.7; int a; // Cast double to int. a = (int)x; // Output // 1234
Conversiones definidas por el usuario
Se realizan a través de métodos especiales que el usuario puede definir para habilitar las conversiones explícitas e implícitas entre Lpos personalizados que no Lenen una relación de clase base-‐clase derivada.
class SampleClass { public static explicit operator SampleClass(int i) { SampleClass temp = new SampleClass(); // code to convert from int to SampleClass... return temp; } }
Conversiones con clases auxiliares
Para realizar conversiones entre Lpos no compaLbles, como los enteros y los objetos System.DateTime, o bien cadenas hexadecimales y matrices de by t e s , puede uL l i z a r l a c l a s e S y s t em .B i tConve r t e r , l a c l a s e System.Convert y los métodos Parse de los Lpos numéricos integrados, como Int32.Parse.
Convert.ToInt32("1234")
Las conversiones declaradas como implicit se producen automáBcamente cuando son necesarias. Las conversiones declaradas como explicit requieren que se llame a una conversión de Bpos. Todas las conversiones se deben declarar como staBc.
Clases y Objetos Tipos, valores y variables Conversión de 6pos
COFFEE BREAK El InsLtuto Tecnológico de Massachusess (MIT) ha realizado un estudio que señala que el “coffee break ” puede incrementar el rendimiento laboral en 8%. El moLvo está más en el descanso y la relación con los compañeros, ya que ésta genera moLvación y aumenta la socialización produciendo confianza y mayor producLvidad.
95
posibilidad de crear nuevas clases basadas en una clase existente.
Programación Orientada a Objetos Los 4 pilares
Herencia
Abstracción
palabra griega que significa "con muchas formas”. Tareas similares son realizadas por métodos con mismo nombre.
Polimorfismo
Expresa las caracterísLcas esenciales de un objeto.
ocultamiento del estado, es decir, de los datos de un objeto de manera que sólo se pueda cambiar mediante las operaciones definidas para ese objeto.
Encapsulamiento
96
Child B Child A Child C
Parent
Programación Orientada a Objetos Los 4 pilares Herencia
La herencia es transi6va. Las clases Child D y Child E heredan los miembros declarados en Child A y Parent. Child D Child E
Una clase derivada sólo puede tener una clase base directa.
La clase derivada obLene implícitamente todos los miembros de la clase base, salvo sus constructores y destructores.
No se admite la herencia múl6ple; es decir, sólo se puede especificar una clase base para una clase derivada.
public class Parent { }
public class ChildA : Parent { }
public class ChildD : ChildA { }
public class ChildE : ChildA { }
public class ChildC : Parent { }
100
Hacer uso de : para heredar de una clase padre
public class B : A { }
Clases y Objetos Programación Orientada a Objetos Herencia
101Los 4 pilares Herencia
When a subclass inherits from a base class, all of the fields, properLes, and methods in the base class are automa6cally added to the subclass.
102
Para especificar que una clase NO se puede usar como clase base
public sealed class A { }
Clases y Objetos Programación Orientada a Objetos Herencia
Palabra reservada sealed
103Los 4 pilares Herencia
Qué podemos hacer si una clase base 6ene un método que una subclase necesita modificar?
Algunas aves no vuelan!
104
Cuando una clase base declara un método como virtual, una clase derivada puede sobreescribir
el método con su propia implementación
Clases y Objetos Programación Orientada a Objetos Herencia
Clases y Objetos Programación Orientada a Objetos
Herencia múl6ple en C#?
Child A
Parent 1 Parent 2
No se admite la herencia múlLple; es decir, sólo se puede especificar una clase base para una clase derivada.
Clases y Objetos Programación Orientada a Objetos
Herencia múl6ple en C#?
Child A
Parent 1 Parent 2
No se admite la herencia múlLple; es decir, sólo se puede especificar una clase base para una clase derivada.
Se permiten múl6ples interfaces.
Clases y Objetos Programación Orientada a Objetos
contrato en donde se especifican las definiciones de un grupo de funcionalidades relacionadas.
…pero qué son los Interfaces?
Clases y Objetos Programación Orientada a Objetos
contrato en donde se especifican las definiciones de un grupo de funcionalidades relacionadas.
o definiciones de métodos, eventos, indizadores y propiedades que una clase o struct debe cumplir.
…pero qué son los Interfaces?
Clases y Objetos Programación Orientada a Objetos Interfaces
public interface ISampleInterface { void SampleMethod(); } public class ImplementationClass : ISampleInterface { void SampleMethod() { // Method implementation. } }
115
Las interfaces no con6enen implementaciones de métodos.
Una interfaz es como una clase base abstracta. Cualquier clase o struct que implemente la interfaz debe implementar todos sus miembros.
Las interfaces pueden contener eventos, métodos, indizadores y propiedades.
Una interfaz no puede ser instanciada directamente.
Clases y Objetos Programación Orientada a Objetos
Una clase o struct puede implementar varias interfaces. Una clase puede heredar una clase base y también implementar una o más interfaces.
Una interfaz 6ene las siguientes propiedades:
Una interfaz puede heredar de una o varias interfaces base.
116Clases y Objetos Programación Orientada a Objetos
public interface IFlyable { void Fly(); } public class Bird : IFlyable { public void Fly() { } } public class Plane : IFlyable { public void Fly() { } }
List<IFlyable> things = GetBirdInstancesAndPlaneInstancesMixed(); foreach(IFlyable item in things) { item.Fly(); }
Child A
Parent 1 Interface 1
Clases y Objetos Programación Orientada a Objetos
Con las interfaces, a través de sus contratos, podemos crear el efecto de herencia múl6ple
Podemos observar como la clase ChildA hereda de la clase Parent1 y también implementa la interfaz Interface1. Se suele decir que:
extends
ChildA extends Parent1 ChildA implements Interface1
implements
Ejemplo prácLco: Beehive simulator
Herencia e Interfaces
Analizar el código fuente del ejemplo de la colmena en GitHub:
hsps://github.com/dbaker3/head-‐first-‐c-‐sharp/tree/master/BeehiveSimulatorCh7
122
posibilidad de crear nuevas clases basadas en una clase existente.
Programación Orientada a Objetos Los 4 pilares
Herencia
Expresa las caracterísLcas esenciales de un objeto.
Abstracción
palabra griega que significa "con muchas formas”. Tareas similares son realizadas por métodos con mismo nombre.
Polimorfismo
ocultamiento del estado, es decir, de los datos de un objeto de manera que sólo se pueda cambiar mediante las operaciones definidas para ese objeto.
Encapsulamiento
123Los 4 pilares Abstracción
Algunas clases nunca pueden ser instanciadas. Recordemos nuestra jerarquía en el simulador del zoo. DefiniLvamente teníamos grupos de instancias de leones, hipopótamos y perros. Pero ¿qué pasa con las clases Feline y Canine? ¿y con Animal? Hay clases que simplemente no necesitan ser instanciadas…y de hecho, no 6ene ningún sen6do que se instancien.
Clases abstractas
124Los 4 pilares Abstracción
Clases abstractas
Una clase abstracta es como una clase normal. ConLene campos y métodos y pueden heredar de otras, exactamente igual que una clase normal.
Una clase abstracta es como un interfaz. Cuando creamos una clase que implementa un interfaz, nos comprometemos a implementar todas las propiedades y métodos definidos en el interfaz. Una clase abstracta funciona de la misma forma, puede incluir declaraciones de propiedades y métodos que, al igual que un interfaz, deben ser implementados por las clases heredadas.
Pero una clase abstracta no puede ser instanciada. La principal diferencia entre una clase abstracta y una clase concreta es que no es posible hacer un new y crear una instancias de la clase abstracta.
125Los 4 pilares Abstracción
Clases abstractas
Una clase abstracta es como una clase normal. ConLene campos y métodos y pueden heredar de otras, exactamente igual que una clase normal.
Una clase abstracta es como un interfaz. Cuando creamos una clase que implementa un interfaz, nos comprometemos a implementar todas las propiedades y métodos definidos en el interfaz. Una clase abstracta funciona de la misma forma, puede incluir declaraciones de propiedades y métodos que, al igual que un interfaz, deben ser implementados por las clases heredadas.
Pero una clase abstracta no puede ser instanciada. La principal diferencia entre una clase abstracta y una clase concreta es que no es posible hacer un new y crear una instancias de la clase abstracta.
126Los 4 pilares Abstracción
Clases abstractas
Una clase abstracta es como una clase normal. ConLene campos y métodos y pueden heredar de otras, exactamente igual que una clase normal.
Una clase abstracta es como un interfaz. Cuando creamos una clase que implementa un interfaz, nos comprometemos a implementar todas las propiedades y métodos definidos en el interfaz. Una clase abstracta funciona de la misma forma, puede incluir declaraciones de propiedades y métodos que, al igual que un interfaz, deben ser implementados por las clases heredadas.
Pero una clase abstracta no puede ser instanciada. La principal diferencia entre una clase abstracta y una clase concreta es que no es posible hacer un new y crear una instancias de la clase abstracta.
public abstract class Stream { public abstract void Write(char ch); public void WriteString(string s) { foreach (char ch in s) { Write(s); } } } public class File : Stream { public override void Write(char ch) { ... write ch to disk... } }
Clases y Objetos Programación Orientada a Objetos Abstracción
public abstract class Stream { public abstract void Write(char ch); public void WriteString(string s) { foreach (char ch in s) { Write(s); } } } public class File : Stream { public override void Write(char ch) { ... write ch to disk... } }
Clases y Objetos Programación Orientada a Objetos Abstracción
Los métodos abstract no Lenen
implementación
public abstract class Stream { public abstract void Write(char ch); public void WriteString(string s) { foreach (char ch in s) { Write(s); } } } public class File : Stream { public override void Write(char ch) { ... write ch to disk... } }
Clases y Objetos Programación Orientada a Objetos Abstracción
Los métodos abstract no Lenen
implementación
Los métodos abstract son virtual implícitamente
public abstract class Stream { public abstract void Write(char ch); public void WriteString(string s) { foreach (char ch in s) { Write(s); } } } public class File : Stream { public override void Write(char ch) { ... write ch to disk... } }
Clases y Objetos Programación Orientada a Objetos Abstracción
Los métodos abstract no Lenen
implementación
Los métodos abstract son virtual implícitamente
Si una clase Lene métodos abstract, la clase debe declararse también como
abstract
public abstract class Stream { public abstract void Write(char ch); public void WriteString(string s) { foreach (char ch in s) { Write(s); } } } public class File : Stream { public override void Write(char ch) { ... write ch to disk... } }
Clases y Objetos Programación Orientada a Objetos Abstracción
Los métodos abstract no Lenen
implementación
Los métodos abstract son virtual implícitamente
Si una clase Lene métodos abstract, la clase debe declararse también como
abstract
No pueden crearse objetos de clases abstractas
new Stream()
public abstract class Stream { public abstract void Write(char ch); public void WriteString(string s) { foreach (char ch in s) { Write(s); } } } public class File : Stream { public override void Write(char ch) { ... write ch to disk... } }
Clases y Objetos Programación Orientada a Objetos Abstracción
Los métodos abstract no Lenen
implementación
Los métodos abstract son virtual implícitamente
Si un clase Lene métodos abstract, la clase debe declararse también como
abstract
No pueden crearse objetos de clases abstractas
new Stream()
Ejemplo prácLco: Planet Mission
Abstract classes
Analizar el código fuente del ejemplo Planet Mission en Codeplex (chapter 7) :
hsps://hfcsharp.codeplex.com
134
posibilidad de crear nuevas clases basadas en una clase existente.
Programación Orientada a Objetos Los 4 pilares
Herencia
Expresa las caracterísLcas esenciales de un objeto.
Abstracción
palabra griega que significa "con muchas formas”. Tareas similares son realizadas por métodos con mismo nombre.
Polimorfismo
ocultamiento del estado, es decir, de los datos de un objeto de manera que sólo se pueda cambiar mediante las operaciones definidas para ese objeto.
Encapsulamiento
135
Estaremos haciendo uso de polimorfismo cuando tomemos una instancia de una clase
y la u6licemos en una declaración o un método que espera un 6po diferente; como una clase padre o una interfaz
que la clase implemente
Clases y Objetos Programación Orientada a Objetos Polimorfismo
class Shape { // A few example members public int X { get; private set; } public int Y { get; private set; } public int Height { get; set; } public int Width { get; set; } // Virtual method public virtual void Draw() { Console.WriteLine("Performing base class drawing tasks"); } }
class Circle : Shape { public override void Draw() { // Code to draw a circle... Console.WriteLine("Drawing a circle"); base.Draw(); } }
class Rectangle : Shape { public override void Draw() { // Code to draw a rectangle... Console.WriteLine("Drawing a rectangle"); base.Draw(); } }
public class Triangle : Shape { public override void Draw() { // Code to draw a triangle... Console.WriteLine("Drawing a triangle"); base.Draw(); } }
class Program { static void Main(string[] args) { // Polymorphism at work #1: a Rectangle, Triangle and Circle // can all be used whereever a Shape is expected. No cast is // required because an implicit conversion exists from a derived // class to its base class. IList<Shape> shapes = new List<Shape>(); shapes.Add(new Rectangle()); shapes.Add(new Triangle()); shapes.Add(new Circle()); // Polymorphism at work #2: the virtual method Draw is // invoked on each of the derived classes, not the base class. foreach (Shape s in shapes) { s.Draw(); } // Keep the console open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); } }
?
class Program { static void Main(string[] args) { // Polymorphism at work #1: a Rectangle, Triangle and Circle // can all be used whereever a Shape is expected. No cast is // required because an implicit conversion exists from a derived // class to its base class. System.Collections.Generic.List<Shape> shapes = new System.Collections.Generic.List<Shape>(); shapes.Add(new Rectangle()); shapes.Add(new Triangle()); shapes.Add(new Circle()); // Polymorphism at work #2: the virtual method Draw is // invoked on each of the derived classes, not the base class. foreach (Shape s in shapes) { s.Draw(); } // Keep the console open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); } }
class Circle : Shape { public override void Draw() { // Code to draw a circle... Console.WriteLine("Drawing a circle"); base.Draw(); } }
class Shape { // A few example members public int X { get; private set; } public int Y { get; private set; } public int Height { get; set; } public int Width { get; set; } // Virtual method public virtual void Draw() { Console.WriteLine("Performing base class drawing tasks"); } }
Drawing a rectangle Performing base class drawing tasks Drawing a triangle Performing base class drawing tasks Drawing a circle Performing base class drawing tasks Press any key to exit.
public class Triangle : Shape { public override void Draw() { // Code to draw a triangle... Console.WriteLine("Drawing a triangle"); base.Draw(); } }
Ejemplo prácLco
Let’s build a house
Analizar el código fuente del ejemplo Let’s build a house en Codeplex (chapter 7) :
hsps://hfcsharp.codeplex.com
142
Qué es? Es el responsable de liberar
memoria, eliminando todos aquellos objetos que están inaccesibles.
Qué es un objeto inaccesible?
Un objeto inaccesible es un objeto al cual NO apunta ninguna referencia; es decir, un objeto al cual no se puede
acceder de ninguna manera.
Cuándo libera memoria el Garbage Collector? El motor de opLmización del
recolector de elementos no uLlizados determina cuál es el mejor momento para realizar una recolección, según
las asignaciones que se estén realizando.
Puedo hacer algo cuando un objeto es destruido por el
Garbage Collector? Sí. Hay un metodo especial que el Garbage Collector invoca cuando destruye un objeto: destructor
No libera las referencias en el momento en el que se dejan de uLlizar
Garbage Collector Recolector de basura
143
Generación 0
Generación 0 Es la generación más joven y conLene los objetos de corta duración. Un ejemplo de objeto de corta duración es una variable temporal. La recolección de elementos no uLlizados se produce con mayor frecuencia en esta generación. Los objetos recién asignados consLtuyen una nueva generación de objetos e implícitamente son recolecciones de generación 0, a menos que sean objetos grandes, en cuyo caso entran en el montón de objetos grandes en una recolección de la generación 2. La mayoría de los objetos se reclaman para la recolección de elementos no uLlizados en la generación 0 y no sobreviven a la generación siguiente.
Generación 1 Esta generación conLene objetos de corta duración y sirve como búfer entre los objetos de corta y larga duración.
Generación 2 Esta generación conLene los objetos de larga duración. Un ejemplo de objeto de larga duración es un objeto de una aplicación de servidor que conLene datos estáLcos que están acLvos mientras dura el proceso.
Hay tres generaciones de objetos en el montón:
Organización de memoria El montón se organiza en generaciones, para poder administrar objetos de larga y corta duración. 84%
Garbage Collector Recolector de basura
Generación 1
Generación 2
Para que un objeto se mantenga en el montón de memoria, éste debe ser refenciado. Una vez deja de ser referenciado, pasado un Lempo, el objeto es eliminado.
Garbage Collector Recolector de basura
149Patrones de Diseño Breve introducción
Los patrones de diseño son el esqueleto de las soluciones a problemas comunes en el desarrollo de soXware.
150Patrones de Diseño Breve introducción
Los patrones de diseño brindan una solución ya probada y documentada a problemas de desarrollo de soRware que están sujetos a contextos similares.
Creacionales solucionan problemas de creación de instancias. Nos ayudan a encapsular y abstraer dicha creación (Factory, Singleton, Builder, etc.)
Estructurales solucionan problemas de composición (agregación) de clases y objetos (Adapter, Facade, Proxy, Composite, etc.)
De comportamiento ofrecen soluciones respecto a la interacción y responsabilidades entre clases y objetos, así como los algoritmos que encapsulan (Iterator, Observer, Strategy, State, etc.)
153Enumerados y Colecciones Breve introducción
enumeración Manera eficaz de definir un conjunto de constantes integrales con nombre que pueden asignarse a una variable
enum Days { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday };
El desarrollador ve claramente qué valores son válidos para la variable.
En Visual Studio, IntelliSense muestra los valores definidos.
De forma predeterminada, el Ipo subyacente de cada elemento de la enumeración es int
Days today = Days.Monday; int dayNumber =(int)today; Console.WriteLine("{0} is day number #{1}.", today, dayNumber);
Monday is day number #0
156Enumerados y Colecciones Breve introducción
Colecciones Estructura de datos flexible para trabajar con grupos de objetos
.NET Framework proporciona colecciones en los siguientes espacios de nombres:
System.Collections.Generic System.Collections.Concurrent System.Collections
Hacen uso de la memoria dinámicamente.
Capacidad para enumerar la colección.
Ofrecen métodos para agregar, quitar o buscar elementos en la colección.
Genéricas Se agregaron en la versión 2.0 de .NET Framework y son colecciones fuertemente Lpadas en Lempo de
compilación.
No genéricas Almacenan elementos como
Object y requieren conversión.
Enumerados y Colecciones Breve introducción
Las colecciones almacenan elementos de… cualquier 6po
List<T> name = new List<T>
Enumerados y Colecciones Breve introducción
Las colecciones almacenan elementos de… cualquier 6po
List<T> name = new List<T>
La <T> en List<T> significa que la lista es genérica. La T es reemplazada por un Lpo – List<string> significa una lista de strings.
Enumerados y Colecciones Breve introducción
Las colecciones almacenan elementos de… cualquier 6po
List<T> name = new List<T>
La <T> en List<T> significa que la lista es genérica. La T es reemplazada por un Lpo – List<string> significa una lista de strings.
List<string> strings = new List<string>(); List<int> ints = new List<int>(); List<byte> bytes = new List<byte>(); List<User> users = new List<User>(); List<WorkItem> workItems = new List<WorkItem>();
List<string> salmons = new List<string>(); salmons.Add("chinook"); salmons.Add("coho"); salmons.Add("pink"); salmons.Add("sockeye"); // Iterate through the list. foreach (string salmon in salmons) { Console.Write(salmon + " "); } // Output: chinook coho pink sockeye
Enumerados y Colecciones Breve introducción
LinkedList Acceso a elementos de forma secuencial.
ObservableCollec6on Recepción de noLficaciones cuando se quitan o se
agregan elementos a la colección.
Stack LIFO (Last Input First Output).
HashSet Conjunto de funciones matemáLcas.
Dic6onary Almacena elementos como pares clave/valor para una
consulta rápida por clave.
List Acceso a elementos por índice.
Queue FIFO (First Input First Output).
SortedList Colección ordenada.
COFFEE BREAK El InsLtuto Tecnológico de Massachusess (MIT) ha realizado un estudio que señala que el “coffee break ” puede incrementar el rendimiento laboral en 8%. El moLvo está más en el descanso y la relación con los compañeros, ya que ésta genera moLvación y aumenta la socialización produciendo confianza y mayor producLvidad.
[Author("Brian Kernighan")] class MyClass { ... }
ATRIBUTOS
Atributos, Ensamblados y Reflec6on Bloques de creación de .NET Framework
Se puede decir que un atributo es una clase que se puede uLlizar para “decorar” a otras clases o elementos (métodos, variables, etc.)
Qué esLos atributos se guardan con los datos y puesto que ofrecen información sobre éstos, se les llama metadatos.
MetadatosDicha información se guarda en 6empo de compilación, en el assembly, junto a los datos y puede ser consultada durante la ejecución.
Assembly
Permiten al desarrollador especificar información declaraIva en enLdades definidas en el código
Todos los atributos heredan directa o indirectamente de System.Attribute
Atributos, Ensamblados y Reflec6on
[Author("Brian Kernighan")] class MyClass { ... }
[System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct) ] public class Author : System.Attribute { private string name; public double version; public Author(string name) { this.name = name; version = 1.0; } }
[Author("John Curry")] struct MyStruct { ... }
especifica los elementos del lenguaje a los que se puede aplicar el atributo
Bloques de creación de .NET Framework
Todos los atributos heredan directa o indirectamente de System.Attribute
[Author("Brian Kernighan")] class MyClass { ... }
[System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct) ] public class Author : System.Attribute { private string name; public double version; public Author(string name) { this.name = name; version = 1.0; } }
[Author("John Curry")] struct MyStruct { ... }
especifica los elementos del lenguaje a los que se puede aplicar el atributo
Atributos, Ensamblados y Reflec6on Bloques de creación de .NET Framework
Todos los atributos heredan directa o indirectamente de System.Attribute
[Author("Brian Kernighan")] class MyClass { ... }
[System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct) ] public class Author : System.Attribute { private string name; public double version; public Author(string name) { this.name = name; version = 1.0; } }
[Author("John Curry")] struct MyStruct { ... }
especifica los elementos del lenguaje a los que se puede aplicar el atributo
Atributos, Ensamblados y Reflec6on Bloques de creación de .NET Framework
172
System.AttributeUsage es un atributo que puede aplicarse a definiciones de atributos personalizados para controlar cómo se aplica el nuevo atributo.
System.AttributeUsage
All, Assembly, Class, Constructor, Delegate, Enum, Event, Field, GenericParameter, Interface, Method, Module, Parameter, Property, ReturnValue, Struct
[System.AttributeUsage( )] public class Author : System.Attribute { private string name; public double version; public Author(string name) { this.name = name; version = 1.0; } }
173
System.AttributeUsage es un atributo que puede aplicarse a definiciones de atributos personalizados para controlar cómo se aplica el nuevo atributo.
System.AttributeUsage
All, Assembly, Class, Constructor, Delegate, Enum, Event, Field, GenericParameter, Interface, Method, Module, Parameter, Property, ReturnValue, Struct
[System.AttributeUsage(System.AttributeTargets.Class)] public class Author : System.Attribute { private string name; public double version; public Author(string name) { this.name = name; version = 1.0; } }
[Author("Brian Kernighan")] class MyClass { ... }
174
System.AttributeUsage es un atributo que puede aplicarse a definiciones de atributos personalizados para controlar cómo se aplica el nuevo atributo.
System.AttributeUsage
All, Assembly, Class, Constructor, Delegate, Enum, Event, Field, GenericParameter, Interface, Method, Module, Parameter, Property, ReturnValue, Struct
[System.AttributeUsage(System.AttributeTargets.Method)] public class Author : System.Attribute { private string name; public double version; public Author(string name) { this.name = name; version = 1.0; } }
[Author("Brian Kernighan")] void MyMethod1(int param1) { ... }
[Author("Brian Kernighan")] bool MyMethod2() { ... }
175
System.AttributeUsage es un atributo que puede aplicarse a definiciones de atributos personalizados para controlar cómo se aplica el nuevo atributo.
System.AttributeUsage
All, Assembly, Class, Constructor, Delegate, Enum, Event, Field, GenericParameter, Interface, Method, Module, Parameter, Property, ReturnValue, Struct
[System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method | System.AttributeTargets.Parameter)] public class Author : System.Attribute { private string name; public double version; public Author(string name) { this.name = name; version = 1.0; } }
[Author("Brian Kernighan")] bool MyMethod2() { ... }
[Author(”John Curry")] class MyClass { ... }
bool MyMethod2([Author("Brian Kernighan")] int param1) { ... }
[Serializable] Indica que el objeto es Serializable
El objeto puede converIrse en una secuencia de bytes para almacenar el objeto o transmiIrlo a memoria, una base de datos o a un archivo.
public class Test { public static void Main() { //Creates a new TestSimpleObject object. TestSimpleObject obj = new TestSimpleObject(); Console.WriteLine("Before serialization the object contains: "); obj.Print(); //Opens a file and serializes the object into it in binary format. Stream stream = File.Open("data.xml", FileMode.Create); BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(stream, obj); stream.Close(); //Empties obj. obj = null; //Opens file "data.xml" and deserializes the object from it. stream = File.Open("data.xml", FileMode.Open); formatter = new BinaryFormatter(); obj = (TestSimpleObject)formatter.Deserialize(stream); stream.Close(); Console.WriteLine(""); Console.WriteLine("After deserialization the object contains: "); obj.Print(); } }
[Serializable()] public class TestSimpleObject { public int member1; public string member2; public string member3; public double member4; // A field that is not serialized. [NonSerialized()] public string member5; public TestSimpleObject() { member1 = 11; member2 = "hello"; member3 = "hello"; member4 = 3.14159265; member5 = "hello world!"; } public void Print() { Console.WriteLine("member1 = '{0}'", member1); Console.WriteLine("member2 = '{0}'", member2); Console.WriteLine("member3 = '{0}'", member3); Console.WriteLine("member4 = '{0}'", member4); Console.WriteLine("member5 = '{0}'", member5); } }
Assembly manifest
Type metadata
CIL code
Resources
ASSEMBLIES Colección de Lpos y recursos que forman una unidad lógica de funcionalidad y que se compilan para trabajar conjuntamente.
Se puede obtener información mediante programación sobre un ensamblado usando la reflexión.
Es posible comparLr un ensamblado entre aplicaciones colocándolo en la caché global de ensamblados.
Los ensamblados sólo se cargan en la memoria si son necesarios. Si no se uLlizan, no se cargan.
Los ensamblados se implementan como archivos .exe o .dll. Unidad lógica de despliegue en la plataforma .NET.
MyAssembly.dll
Atributos, Ensamblados y Reflec6on Bloques de creación de .NET Framework
REFLECTION Permite obtener información acerca de los ensamblados cargados y los Lpos definidos en los mismos, como clases, interfaces y 6pos de valor, así como instanciar objetos, invocar métodos o tener acceso a sus campos y propiedades en 6empo de ejecución.
System.Reflection
.NET Framework proporciona un espacio de nombres dedicado que conLene los Lpos que recuperan la información sobre los ensamblados, módulos, miembros, parámetros y otras enLdades del código administrado examinando sus metadatos:
Es úLl cuando es necesario obtener acceso a atributos en los metadatos del programa.
Para examinar e instanciar Lpos en un ensamblado.
Atributos, Ensamblados y Reflec6on Bloques de creación de .NET Framework
Es úLl cuando es necesario obtener acceso a atributos en los metadatos del programa.
Recuperemos el atributo Author definido anteriormente…
Atributos, Ensamblados y Reflec6on ReflecLon
[Author("Brian Kernighan")] class MyClass { ... }
Atributos, Ensamblados y Reflec6on Acceso a los atributos mediante reflecLon
Necesitamos leer "Brian Kernighan" para saber el autor de la clase? cómo podemos hacerlo?
[Author("Brian Kernighan")] class MyClass { ... }
Atributos, Ensamblados y Reflec6on Acceso a los atributos mediante reflecLon
Necesitamos leer "Brian Kernighan" para saber el autor de la clase? cómo podemos hacerlo?
¡¡ Reflec6on !!
[Author("Brian Kernighan")] class MyClass { ... }
Atributos, Ensamblados y Reflec6on Acceso a los atributos mediante reflecLon
Necesitamos leer "Brian Kernighan" para saber el autor de la clase? cómo podemos hacerlo?
¡¡ Reflec6on !! El hecho de poder definir atributos personalizados y colocarlos en el código fuente tendría un valor escaso si no se dispone de un método para recuperar la información y actuar sobre ella. Mediante el uso de la reflexión se puede recuperar la información definida con atributos personalizados.
[Author("Brian Kernighan")] class MyClass { ... }
Atributos, Ensamblados y Reflec6on Acceso a los atributos mediante reflecLon
// Class with the Author attribute. [Author("P. Ackerman")] public class FirstClass { // ... } // Class without the Author attribute. public class SecondClass { // ... } // Class with multiple Author attributes. [Author("P. Ackerman"), Author("R. Koch", version = 2.0)] public class ThirdClass { // ... }
class TestAuthorAttribute { static void Test() { PrintAuthorInfo(typeof(FirstClass)); PrintAuthorInfo(typeof(SecondClass)); PrintAuthorInfo(typeof(ThirdClass)); } private static void PrintAuthorInfo(System.Type t) { System.Console.WriteLine("Author information for {0}", t); // Using reflection. System.Attribute[] attrs = System.Attribute.GetCustomAttributes(t); // Reflection. // Displaying output. foreach (System.Attribute attr in attrs) { if (attr is Author) { Author a = (Author)attr; System.Console.WriteLine( "{0}, version {1:f}", a.GetName(), a.version ); } } } } ?
[System.AttributeUsage(System.AttributeTargets.Class)] public class Author : System.Attribute { private string name; public double version; public Author(string name) { this.name = name; version = 1.0; } public string GetName() { return name; } }
// Class with the Author attribute. [Author("P. Ackerman")] public class FirstClass { // ... } // Class without the Author attribute. public class SecondClass { // ... } // Class with multiple Author attributes. [Author("P. Ackerman"), Author("R. Koch", version = 2.0)] public class ThirdClass { // ... }
class TestAuthorAttribute { static void Test() { PrintAuthorInfo(typeof(FirstClass)); PrintAuthorInfo(typeof(SecondClass)); PrintAuthorInfo(typeof(ThirdClass)); } private static void PrintAuthorInfo(System.Type t) { System.Console.WriteLine("Author information for {0}", t); // Using reflection. System.Attribute[] attrs = System.Attribute.GetCustomAttributes(t); // Reflection. // Displaying output. foreach (System.Attribute attr in attrs) { if (attr is Author) { Author a = (Author)attr; System.Console.WriteLine( "{0}, version {1:f}", a.GetName(), a.version ); } } } }
[System.AttributeUsage(System.AttributeTargets.Class)] public class Author : System.Attribute { private string name; public double version; public Author(string name) { this.name = name; version = 1.0; } public string GetName() { return name; } }
Author information for FirstClass P. Ackerman, version 1.00 Author information for SecondClass Author information for ThirdClass R. Koch, version 2.00 P. Ackerman, version 1.00
[assembly:AssemblyVersionAttribute("1.0.2000.0")] public class Example { private int factor; public Example(int f) { factor = f; } public int SampleMethod(int x) { Console.WriteLine( "\nExample.SampleMethod({0}) executes.", x ); return x * factor; } }
using System; using System.Reflection; using System.Security.Permissions; public static void Main() { Assembly assem = Assembly.GetExecutingAssembly(); Console.WriteLine("Assembly Full Name:"); Console.WriteLine(assem.FullName); // The AssemblyName type can be used to parse the full name. AssemblyName assemName = assem.GetName(); Console.WriteLine("\nName: {0}", assemName.Name); Console.WriteLine("Version: {0}.{1}", assemName.Version.Major, assemName.Version.Minor); Console.WriteLine("\nAssembly CodeBase:"); Console.WriteLine(assem.CodeBase); // Create an object from the assembly, passing in the correct // number and type of arguments for the constructor. object o = assem.CreateInstance("Example", false, BindingFlags.ExactBinding, null, new Object[] { 2 }, null, null); // Make a late-bound call to an instance method of the object. MethodInfo m = assem.GetType("Example").GetMethod("SampleMethod"); Object ret = m.Invoke(o, new Object[] { 42 }); Console.WriteLine("SampleMethod returned {0}.", ret); Console.WriteLine("\nAssembly entry point:"); Console.WriteLine(assem.EntryPoint); }
?
[assembly:AssemblyVersionAttribute("1.0.2000.0")] public class Example { private int factor; public Example(int f) { factor = f; } public int SampleMethod(int x) { Console.WriteLine( "\nExample.SampleMethod({0}) executes.", x ); return x * factor; } }
using System; using System.Reflection; using System.Security.Permissions; public static void Main() { Assembly assem = Assembly.GetExecutingAssembly(); Console.WriteLine("Assembly Full Name:"); Console.WriteLine(assem.FullName); // The AssemblyName type can be used to parse the full name. AssemblyName assemName = assem.GetName(); Console.WriteLine("\nName: {0}", assemName.Name); Console.WriteLine("Version: {0}.{1}", assemName.Version.Major, assemName.Version.Minor); Console.WriteLine("\nAssembly CodeBase:"); Console.WriteLine(assem.CodeBase); // Create an object from the assembly, passing in the correct // number and type of arguments for the constructor. object o = assem.CreateInstance("Example", false, BindingFlags.ExactBinding, null, new Object[] { 2 }, null, null); // Make a late-bound call to an instance method of the object. MethodInfo m = assem.GetType("Example").GetMethod("SampleMethod"); Object ret = m.Invoke(o, new Object[] { 42 }); Console.WriteLine("SampleMethod returned {0}.", ret); Console.WriteLine("\nAssembly entry point:"); Console.WriteLine(assem.EntryPoint); }
Assembly Full Name: source, Version=1.0.2000.0, Culture=neutral, PublicKeyToken=null Name: source Version: 1.0 Assembly CodeBase: file:///C:/sdtree/AssemblyClass/cs/source.exe Example.SampleMethod(42) executes. SampleMethod returned 84. Assembly entry point: Void Main()
using System; using System.Reflection; class ListMembers { public static void Main(String[] args) { Type t = typeof(System.String); Console.WriteLine( "Listing all the public constructors of the {0} type", t ); // Constructors. ConstructorInfo[] ci = t.GetConstructors( BindingFlags.Public | BindingFlags.Instance); Console.WriteLine("//Constructors"); PrintMembers(ci); } public static void PrintMembers(MemberInfo[] ms) { foreach (MemberInfo m in ms) { Console.WriteLine("{0}{1}", " Console.WriteLine(); } } }
Listing all the public constructors of the System.String type //Constructors Void.ctor(Char*) Void.ctor(Char*, Int32, Int32) Void.ctor(SByte*) Void.ctor(SByte*, Int32, Int32) Void.ctor(SByte*, Int32, Int32, System.Text.Encoding) Void.ctor(Char[], Int32, Int32) Void.ctor(Char[]) Void.ctor(Char, Int32) Press any key to continue...
195Lectura y escritura de ficheros Serialización y Deserialización de datos
Cada vez que deseemos leer datos de un archivo o escribir datos en un archivo, deberemos hacer uso del objeto Stream que .NET Framework nos ofrece.
Clase Stream La clase Stream es una clase abstracta, por lo que no es posible uLlizarla directamente.
Clase Stream
Cada subclase añade métodos y propiedades específicas a la funcionalidad de la clase
La clase Stream es una clase abstracta, por lo que no es posible uLlizarla directamente.
Debemos hacer uso de sus clases derivadas que se especializan en el tratamiento de streams para diferentes orígenes y desLnos.
Clase Stream
Cada subclase añade métodos y propiedades específicas a la funcionalidad de la clase
La clase Stream es una clase abstracta, por lo que no es posible uLlizarla directamente.
Podemos escribir datos en el stream a través del método Write().
Podemos obtener o establecer la posición dentro del stream mediante el método Seek().
A través del método Read() podemos leer datos desde un fichero, desde la red o desde memoria.
Clase FileStream
Actúa como intermediario entre el sistema de archivos y nuestra aplicación, permiLendo realizar de una manera limpia y sencilla operaciones de escritura y lectura en archivos.
// Se crea el FileStream mediante el método Create de File Filestream fs = File.Create(@"C:\FileStream.txt"); // Se define el texto que vamos a escribir string data = "hello world"; // Se obtiene la equivalencia en bytes de la cadena utilizando // codificación UTF8 byte[] bytes = Encoding.UTF8.GetBytes(data.ToString()); fs.Write(bytes, 0, bytes.Length); fs.Flush(); fs.Close();
Clase FileStream
Todo stream se debe cerrar al finalizar la operación que se realiza sobre él, ya que de lo contrario el archivo quedaría bloqueado y no se liberarían recursos del sistema operaLvo.
Clases StreamWriter y StreamReader
La plataforma .NET ofrece otras maneras de administrar Streams para hacerle la vida más fácil al desarrollador:
Reciben Ipos de datos naIvos del lenguaje: int, bool, decimal, float, string, char, etc.
Hacen uso por defecto de la codificación UTF8, pudiendo definir una disLnta en los constructores.
StreamWriter StreamReader
Hacer uso del constructor de StreamWriter para abrir o crear un fichero. 1
Clases StreamWriter y StreamReader Escribamos texto en un fichero en 3 sencillos pasos
Hacer uso del constructor de StreamWriter para abrir o crear un fichero.
Hacer uso de los métodos Write() y WriteLine() para escribir en el fichero.
1
2
Clases StreamWriter y StreamReader Escribamos texto en un fichero en 3 sencillos pasos
Hacer uso del constructor de StreamWriter para abrir o crear un fichero.
Hacer uso de los métodos Write() y WriteLine() para escribir en el fichero.
Invocar a Close() para garanLzar que todos los datos se escriben correctamente.
1
2
3
Clases StreamWriter y StreamReader Escribamos texto en un fichero en 3 sencillos pasos
Filestream fs = File.Create(@"C:\FileStream.txt"); string data = "hello world”; byte[] bytes = Encoding.UTF8.GetBytes(data.ToString()); fs.Write(bytes, 0, bytes.Length); fs.Flush(); fs.Close();
FileStream vs. StreamWriter
FileStream
Filestream fs = File.Create(@"C:\FileStream.txt"); string data = "hello world”; byte[] bytes = Encoding.UTF8.GetBytes(data.ToString()); fs.Write(bytes, 0, bytes.Length); fs.Flush(); fs.Close();
StreamWriter writer = new StreamWriter(@"C:\FileStream.txt"); writer.WriteLine("hello world"); writer.Close();
FileStream vs. StreamWriter
StreamWriter
FileStream
Filestream fs = File.Create(@"C:\FileStream.txt"); string data = "hello world”; byte[] bytes = Encoding.UTF8.GetBytes(data.ToString()); fs.Write(bytes, 0, bytes.Length); fs.Flush(); fs.Close();
StreamWriter writer = new StreamWriter(@"C:\FileStream.txt"); writer.WriteLine("hello world"); writer.Close();
FileStream vs. StreamWriter
StreamWriter
FileStream
208Clases File y Directory
El espacio de nombres System.IO dispone de las clases File, FileInfo, Directory y DirectoryInfo ideales para trabajar con ficheros y directorios.
StreamWriter writer = new StreamWriter(@"C:\FileStream.txt"); writer.WriteLine("hello world"); writer.Close();
C# nos ofrece el mecanismo para evitar olvidarnos cerrar los streams IDisposable, Dispose()
Gran parte de los bugs vienen derivados de despistes de los desarrolladores al no cerrar éstos
using (StreamWriter writer = new StreamWriter(@"C:\FileStream.txt”)) { writer.WriteLine("hello world"); writer.WriteLine(”another genius secret plan"); }
C# nos ofrece el mecanismo para evitar olvidarnos cerrar los streams IDisposable, Dispose()
StreamWriter writer = new StreamWriter(@"C:\FileStream.txt"); writer.WriteLine("hello world"); writer.Close();
Gran parte de los bugs vienen derivados de despistes de los desarrolladores al no cerrar éstos
Evitemos errores del sistema de ficheros haciendo uso de palabra using
Evitemos errores del sistema de ficheros haciendo uso de palabra using
using (StreamWriter writer = new StreamWriter(@"C:\FileStream.txt”)) { writer.WriteLine("hello world"); writer.WriteLine(”another genius secret plan"); }
C# nos ofrece el mecanismo para evitar olvidarnos cerrar los streams IDisposable, Dispose()
StreamWriter writer = new StreamWriter(@"C:\FileStream.txt"); writer.WriteLine("hello world"); writer.Close();
Gran parte de los bugs vienen derivados de despistes de los desarrolladores al no cerrar éstos
Evitemos errores del sistema de ficheros haciendo uso de palabra using
using (StreamWriter writer = new StreamWriter(@"C:\FileStream.txt”)) { writer.WriteLine("hello world"); writer.WriteLine(”another genius secret plan"); }
C# nos ofrece el mecanismo para evitar olvidarnos cerrar los streams IDisposable, Dispose()
StreamWriter writer = new StreamWriter(@"C:\FileStream.txt"); writer.WriteLine("hello world"); writer.Close();
Gran parte de los bugs vienen derivados de despistes de los desarrolladores al no cerrar éstos
Evitemos errores del sistema de ficheros haciendo uso de palabra using
using (StreamWriter writer = new StreamWriter(@"C:\FileStream.txt”)) { writer.WriteLine("hello world"); writer.WriteLine(”another genius secret plan"); }
C# nos ofrece el mecanismo para evitar olvidarnos cerrar los streams IDisposable, Dispose()
StreamWriter writer = new StreamWriter(@"C:\FileStream.txt"); writer.WriteLine("hello world"); writer.Close();
Gran parte de los bugs vienen derivados de despistes de los desarrolladores al no cerrar éstos
Gran parte de los bugs vienen derivados de despistes de los desarrolladores al no cerrar éstos
Evitemos errores del sistema de ficheros haciendo uso de palabra using
using (StreamWriter writer = new StreamWriter(@"C:\FileStream.txt”)) { writer.WriteLine("hello world"); writer.WriteLine(”another genius secret plan"); }
C# nos ofrece el mecanismo para evitar olvidarnos cerrar los streams IDisposable, Dispose()
StreamWriter writer = new StreamWriter(@"C:\FileStream.txt"); writer.WriteLine("hello world"); writer.Close();
Lectura y escritura de ficheros Serialización y Deserialización de datos
Sólo puedo escribir y leer texto en los ficheros? Si quisiera guardar la información
de un objeto… podría hacerlo?
Lectura y escritura de ficheros Serialización y Deserialización de datos
Sólo puedo escribir y leer texto en los ficheros? Si quisiera guardar la información
de un objeto… podría hacerlo?
¡¡¡ SÍ !!! Podríamos guardar en cada línea del fichero el valor de cada campo del objeto pero esto supondría un gran trabajo y poco flexible a cambios. Lo que haremos es…
Lectura y escritura de ficheros Serialización y Deserialización de datos
Sólo puedo escribir y leer texto en los ficheros? Si quisiera guardar la información
de un objeto… podría hacerlo?
Serializar y Deserializar el objeto.
¡¡¡ SÍ !!! Podríamos guardar en cada línea del fichero el valor de cada campo del objeto pero esto supondría un gran trabajo y poco flexible a cambios. Lo que haremos es…
Lectura y escritura de ficheros Serialización y Deserialización de datos
Sólo puedo escribir y leer texto en los ficheros? Si quisiera guardar la información
de un objeto… podría hacerlo?
Serializar y Deserializar el objeto.
¡¡¡ SÍ !!!
Proceso de conver6r un objeto en una secuencia de bytes para almacenar el objeto o transmiLrlo a memoria, una base de datos, o en un archivo. Su propósito principal es guardar el estado de un objeto para poder crearlo de nuevo cuando se necesita. El proceso inverso se denomina deserialización.
Podríamos guardar en cada línea del fichero el valor de cada campo del objeto pero esto supondría un gran trabajo y poco flexible a cambios. Lo que haremos es…
Qué le pasa a un objeto cuando éste es serializado?
Qué es exactamente el estado de un objeto? El estado de un objeto son los valores de cada uno de los campos que componen dicho objeto.
Qué le pasa a un objeto cuando éste es serializado? Cada campo del objeto será serializado a excepción de aquellos que tengan el atributo NonSerializedAttribute.
Si un objeto referencia a otros objetos, éstos también se serializan… incluso los objetos referenciados por éstos.
Excepciones GesLón de excepciones existentes y creación
de nuevas excepciones
Mecanismo de ges6ón o control de errores que provee el lenguaje de programación y que representa el medio para lograr la escritura de programas más robustos y tolerantes a fallos.
226
C# permite controlar las excepciones a través de las palabras clave try, catch, finally.
Excepciones Control de excepciones
try { … // código propenso a generar excepciones } catch (DivideByZeroException e) { … // tratamiento de cualquier excepción de tipo // DivideByZeroException ocurrida en el bloque try }
Palabras reservadas try-catch Permiten controlar las excepciones
try { … // código propenso a generar excepciones } catch (DivideByZeroException e) { … // tratamiento de cualquier excepción de tipo // DivideByZeroException ocurrida en el bloque try }
Palabras reservadas try-catch Permiten controlar las excepciones
Cuándo debo hacer uso de try-‐catch? Un consejo sería sólo hacer uso cuando el código implementado Lene cierto riesgo. Por ejemplo, código que se ejecuta con la entrada de datos por parte del usuario de aplicación. Debemos darle información de lo que está pasando y no mostrar un error inesperado que pueda causar mala impresión e incluso pueda mostrar información confidencial que nos pueda comprometer.
try { … // código propenso a generar excepciones } catch (DivideByZeroException e) { … // tratamiento de cualquier excepción de tipo // DivideByZeroException ocurrida en el bloque try }
Palabras reservadas try-catch Permiten controlar las excepciones
Cuándo debo hacer uso de try-‐catch? Un consejo sería sólo hacer uso cuando el código implementado Lene cierto riesgo. Por ejemplo, código que se ejecuta con la entrada de datos por parte del usuario de aplicación. Debemos darle información de lo que está pasando y no mostrar un error inesperado que pueda causar mala impresión e incluso pueda mostrar información confidencial que nos pueda comprometer.
El bloque del catch sólo se ejecutará si en la parte del try ha ocurrido alguna excepción.
try { … // código propenso a generar excepciones } catch { … // tratamiento de cualquier excepción ocurrida // en el bloque try }
Palabras reservadas try-catch Permiten controlar las excepciones
Cuándo debo hacer uso de try-‐catch? Un consejo sería sólo hacer uso cuando el código implementado Lene cierto riesgo. Por ejemplo, código que se ejecuta con la entrada de datos por parte del usuario de aplicación. Debemos darle información de lo que está pasando y no mostrar un error inesperado que pueda causar mala impresión e incluso pueda mostrar información confidencial que nos pueda comprometer.
El bloque del catch sólo se ejecutará si en la parte del try ha ocurrido alguna excepción.
Sin el bloque del catch no se indica ninguna excepción; cualquier excepción que ocurra en el try será capturada por este bloque.
Si tenemos código que se debe ejecutar SIEMPRE, haremos uso de finally
Palabra reservada finally
Al finalizar el bloque try
Cuando un programa eleva una excepción, pueden pasar mulLtud de escenarios. Si la excepción no es controlada, el programa finalizará y fallará. Si la excepción es controlada, el código saltará al bloque del catch. Pero qué pasa con el resto del código existente en el bloque del try? Qué pasa si estábamos cerrando un stream, o eliminando ciertos recursos? Dicho código necesita ejecutarse, incluso aunque ocurra una excepción. Es aquí donde entra en juego el bloque del finally. El bloque del finally siempre se ejecuta, ocurra o no una excepción.
Uso de las sentencias de salto (p.e., goto o return) localizadas en el bloque try
Después de finalizar un bloque catch
try { … } catch { … } finally { … // código que se ejecutará // independientemente de si // ha ocurrido una // excepción o no en el bloque // try }
class ExampleWithoutExceptionHandling { static double UnsafeDivision(double x, double y) { return x / y; } static void Main() { double a = 98; double b = 0; double result = 0; result = UnsafeDivision(a, b); Console.WriteLine("{0} divided by {1} = {2}", a, b, result); } }
class ExampleWithoutExceptionHandling { static double UnsafeDivision(double x, double y) { return x / y; } static void Main() { double a = 98; double b = 0; double result = 0; result = UnsafeDivision(a, b); Console.WriteLine("{0} divided by {1} = {2}", a, b, result); } }
Unhandled Exception: System.DivideByZeroException: Division by zero at ExampleWithoutExceptionHandling.Main()
El mensaje de excepción nos indica que la excepción no ha sido controlada o manejada.
Localización en donde se ha generado.
El programa finaliza su ejecución de forma abrupta debido a que la excepción no ha sido manejada.
class ExampleWithoutExceptionHandling { static double UnsafeDivision(double x, double y) { return x / y; } static void Main() { double a = 98; double b = 0; double result = 0; result = UnsafeDivision(a, b); Console.WriteLine("{0} divided by {1} = {2}", a, b, result); } }
Unhandled Exception: System.DivideByZeroException: Division by zero at ExampleWithoutExceptionHandling.Main()
El mensaje de excepción nos indica que la excepción no ha sido controlada o manejada.
Localización en donde se ha generado.
El programa finaliza su ejecución de forma abrupta debido a que la excepción no ha sido manejada.
class ExampleWithoutExceptionHandling { static double UnsafeDivision(double x, double y) { return x / y; } static void Main() { double a = 98; double b = 0; double result = 0; result = UnsafeDivision(a, b); Console.WriteLine("{0} divided by {1} = {2}", a, b, result); } }
Unhandled Exception: System.DivideByZeroException: Division by zero at ExampleWithoutExceptionHandling.Main()
Localización en donde se ha generado.
El programa finaliza su ejecución de forma abrupta debido a que la excepción no ha sido manejada.
El mensaje de excepción nos indica que la excepción no ha sido controlada o manejada.
class ExceptionExample { static double SafeDivision(double x, double y) { if (y == 0) throw new System.DivideByZeroException(); return x / y; } static void Main() { double a = 98, b = 0; double result = 0; try { result = SafeDivision(a, b); Console.WriteLine("{0} divided by {1} = {2}", a, b, result); } catch (DivideByZeroException e) { Console.WriteLine("Attempted divide by zero."); } } }
class ExampleWithoutExceptionHandling { static double UnsafeDivision(double x, double y) { return x / y; } static void Main() { double a = 98; double b = 0; double result = 0; result = UnsafeDivision(a, b); Console.WriteLine("{0} divided by {1} = {2}", a, b, result); } }
class ExceptionExample { static double SafeDivision(double x, double y) { if (y == 0) throw new System.DivideByZeroException(); return x / y; } static void Main() { double a = 98, b = 0; double result = 0; try { result = SafeDivision(a, b); Console.WriteLine("{0} divided by {1} = {2}", a, b, result); } catch (DivideByZeroException e) { Console.WriteLine("Attempted divide by zero."); } } }
class ExampleWithoutExceptionHandling { static double UnsafeDivision(double x, double y) { return x / y; } static void Main() { double a = 98; double b = 0; double result = 0; result = UnsafeDivision(a, b); Console.WriteLine("{0} divided by {1} = {2}", a, b, result); } }
Attempted divide by zero Press any key to continue...
Los usuarios son impredecibles! Proporcionan todo Lpo de datos extraños y hacen click en siLos que nunca esperaríamos. Debemos, por tanto, controlar la entrada de datos con un buen manejo de excepciones.
¿Qué sucede cuando un método al que deseamos llamar es arriesgado?
Hacer uso de varios bloques catch para tratar múl6ples excepciones
Orden de ejecución de los catch
Cuando existen varios bloques catch, éstos son examinados en orden. En este ejemplo, en primer lugar se comprobará si es de Lpo VatEmptyExcepLon; en segundo lugar si es de Lpo HiveLogExcepLon y por úlLmo si es de Lpo IOExcepLon.
Hacer uso de varios bloques catch para tratar múl6ples excepciones Variable ex
Si la excepción no se va a uLlizar, no es necesario declararla. Orden de ejecución de los catch
Cuando existen varios bloques catch, éstos son examinados en orden. En este ejemplo, en primer lugar se comprobará si es de Lpo VatEmptyExcepLon; en segundo lugar si es de Lpo HiveLogExcepLon y por úlLmo si es de Lpo IOExcepLon.
Hacer uso de varios bloques catch para tratar múl6ples excepciones
Mismo nombre
Es aconsejable uLlizar el mismo nombre (“ex”) para las excepciones.
Variable ex Si la excepción no se va a uLlizar, no es necesario declararla. Orden de ejecución de los catch
Cuando existen varios bloques catch, éstos son examinados en orden. En este ejemplo, en primer lugar se comprobará si es de Lpo VatEmptyExcepLon; en segundo lugar si es de Lpo HiveLogExcepLon y por úlLmo si es de Lpo IOExcepLon.
Hacer uso de varios bloques catch para tratar múl6ples excepciones
throw En ciertas ocasiones nos puede ineteresar elevar una excepción al método llamante. Para relanzar una excepción podemos hacerlo mediante throw.
Mismo nombre
Es aconsejable uLlizar el mismo nombre (“ex”) para las excepciones.
Variable ex Si la excepción no se va a uLlizar, no es necesario declararla. Orden de ejecución de los catch
Cuando existen varios bloques catch, éstos son examinados en orden. En este ejemplo, en primer lugar se comprobará si es de Lpo VatEmptyExcepLon; en segundo lugar si es de Lpo HiveLogExcepLon y por úlLmo si es de Lpo IOExcepLon.
245
A pesar de que la biblioteca base de clases de .NET Framework cuenta con un conjunto enriquecido de clases de excepciones, surgirán situaciones en donde como desarrolladores requeriremos crear un nivel de granularidad adicional para el lanzamiento y captura de excepciones de acuerdo a la lógica de negocio y el dominio de nuestra aplicación.
Para ello, crearemos nuestras propias excepciones personalizadas.
Excepciones Creación de excepciones personalizadas
[Serializable()] public class YourException : System.Exception { public YourException() : base() { } public YourException(string message) : base(message) { } public YourException (string message, System.Exception inner) : base(message, inner) { } // A constructor is needed for serialization when an // exception propagates from a remoting server to the client. protected YourException (System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } }
Recordemos que cuando declaramos una referencia en un “using”, su método Dispose() es invocado automáLcamente al finalizar el bloque.
Aquellas clases que implementan la interfaz System.IDisposable y que encapsulan recursos no administrados por el CLR, como: archivos, gráficos, o bases de datos, etc. implementan el método abstracto Dispose() para la liberación de los recursos (e.g., memoria) ocupados. Para este Lpo de clases, la sentencia using provee una sintaxis más cómoda y versáLl que usar la sentencia try-catch-finally
Una manera de evitar muchos problemas: using en lugar de try-finally
Los streams son perfectos puesto que Lenen su propia implementación para cuando el objeto es eliminado y hacer que el stream se cierre. Pero qué pasa si tenemos nuestro propio objeto en el cuál siempre necesitamos hacer algo cuando éste es eliminado? No sería buena idea implementar un código que se ejecutara siempre cuando el objeto es eliminado para poder uLlizarlo en la instrucción using?
Implementa el interfaz IDisposable y escribe el código para liberar recursos en el método Dispose()
LINQ Language Integrated Query
Permite consultar datos de forma sencilla e intuiLva, agruparlos, ordenarlos, mezclar datos de diferentes orígenes de datos y muchas cosas más!
LINQ Language
Integrated Query
Conjunto de tecnologías que consiste en la integración directa de funciones de consulta en el lenguaje C#
Conjunto de tecnologías que consiste en la integración directa de funciones de consulta en el lenguaje C#
Qué es una función de consulta?
Qué es una función de consulta? es una expresión que recupera datos de un origen de datos
Conjunto de tecnologías que consiste en la integración directa de funciones de consulta en el lenguaje C#
Con LINQ podemos consultar cualquier objeto que implemente el interfaz IEnumerable<T>
Qué es una función de consulta? es una expresión que recupera datos de un origen de datos
LINQ permite realizar consultas de forma sencilla
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; // numQuery is an IEnumerable<int> var numQuery = from num in numbers where (num % 2) == 0 select num; foreach (int num in numQuery) { Console.Write("{0,1} ", num); }
Todas las operaciones de consulta LINQ se componen de tres acciones disLntas:
1 Obtención del origen de datos.
Creación de la consulta. 2
Ejecución de la consulta. 3
LINQ permite realizar consultas de forma sencilla
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; // numQuery is an IEnumerable<int> var numQuery = from num in numbers where (num % 2) == 0 select num; foreach (int num in numQuery) { Console.Write("{0,1} ", num); }
Todas las operaciones de consulta LINQ se componen de tres acciones disLntas:
1 Obtención del origen de datos.
Creación de la consulta. 2
Ejecución de la consulta. 3
LINQ permite realizar consultas de forma sencilla
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; // numQuery is an IEnumerable<int> var numQuery = from num in numbers where (num % 2) == 0 select num; foreach (int num in numQuery) { Console.Write("{0,1} ", num); }
Todas las operaciones de consulta LINQ se componen de tres acciones disLntas:
Creación de la consulta. 2
Ejecución de la consulta. 3
1 Obtención del origen de datos.
LINQ permite realizar consultas de forma sencilla
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; // numQuery is an IEnumerable<int> var numQuery = from num in numbers where (num % 2) == 0 select num; foreach (int num in numQuery) { Console.Write("{0,1} ", num); }
Todas las operaciones de consulta LINQ se componen de tres acciones disLntas:
Creación de la consulta. 2
Ejecución de la consulta. 3
1 Obtención del origen de datos.
Sintaxis de consulta.
LINQ permite realizar consultas de forma sencilla
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; // numQuery is an IEnumerable<int> var numQuery = from num in numbers where (num % 2) == 0 select num; foreach (int num in numQuery) { Console.Write("{0,1} ", num); }
Todas las operaciones de consulta LINQ se componen de tres acciones disLntas:
Creación de la consulta. 2
Ejecución de la consulta. 3
1 Obtención del origen de datos.
Sintaxis de consulta.
LINQ permite realizar consultas de forma sencilla
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; // numQuery is an IEnumerable<int> var numQuery = from num in numbers where (num % 2) == 0 select num; foreach (int num in numQuery) { Console.Write("{0,1} ", num); }
Todas las operaciones de consulta LINQ se componen de tres acciones disLntas:
1 Obtención del origen de datos.
Creación de la consulta. 2
Ejecución de la consulta. 3
LINQ permite realizar consultas de forma sencilla
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; // numQuery is an IEnumerable<int> var numQuery = from num in numbers where (num % 2) == 0 select num; foreach (int num in numQuery) { Console.Write("{0,1} ", num); }
Todas las operaciones de consulta LINQ se componen de tres acciones disLntas:
1 Obtención del origen de datos.
Creación de la consulta. 2
Ejecución de la consulta. 3
LINQ permite realizar consultas de forma sencilla
Todas las operaciones de consulta LINQ se componen de tres acciones disLntas:
1 Obtención del origen de datos.
Creación de la consulta. 2
Ejecución de la consulta. 3
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; // numQuery is an IEnumerable<int> var numQuery = numbers .Where(num => num % 2 == 0) .OrderBy(n => n); foreach (int num in numQuery) { Console.Write("{0,1} ", num); }
Sintaxis de método.
LINQ permite realizar consultas de forma sencilla
Todas las operaciones de consulta LINQ se componen de tres acciones disLntas:
1 Obtención del origen de datos.
Creación de la consulta. 2
Ejecución de la consulta. 3
Origen de datos. Un Lpo que se puede consultar no requiere ninguna modificación o tratamiento especial para servir como origen de datos LINQ
La consulta. especifica qué información se va a recuperar de uno o varios orígenes de datos. Opcionalmente, una consulta también especifica cómo debería ordenarse, agruparse y darse forma a esa información antes de ser devuelta. Una consulta se almacena en una variable de consulta y se inicializa con una expresión de consulta. Lo importante es que, en LINQ, la propia variable de consulta no realiza ninguna acción ni devuelve datos. Simplemente almacena la información necesaria para generar los resultados cuando la consulta se ejecute posteriormente.
La ejecución. La ejecución real de la consulta se aplaza hasta que se procese una iteración en la variable de consulta, en una instrucción foreach.
Northwnd db = new Northwnd(@"c:\northwnd.mdf");
LINQ permite realizar consultas de forma sencilla
Todas las operaciones de consulta LINQ se componen de tres acciones disLntas:
1 Obtención del origen de datos.
Creación de la consulta. 2
Ejecución de la consulta. 3
IQueryable<Customer> custQuery = from cust in db.Customers where cust.City == "London" select cust;
Origen de datos. Un Lpo que se puede consultar no requiere ninguna modificación o tratamiento especial para servir como origen de datos LINQ
La consulta. especifica qué información se va a recuperar de uno o varios orígenes de datos. Opcionalmente, una consulta también especifica cómo debería ordenarse, agruparse y darse forma a esa información antes de ser devuelta. Una consulta se almacena en una variable de consulta y se inicializa con una expresión de consulta. Lo importante es que, en LINQ, la propia variable de consulta no realiza ninguna acción ni devuelve datos. Simplemente almacena la información necesaria para generar los resultados cuando la consulta se ejecute posteriormente.
La ejecución. La ejecución real de la consulta se aplaza hasta que se procese una iteración en la variable de consulta, en una instrucción foreach.
LINQ permite realizar consultas de forma sencilla
Todas las operaciones de consulta LINQ se componen de tres acciones disLntas:
1 Obtención del origen de datos.
Creación de la consulta. 2
Ejecución de la consulta. 3
Origen de datos. Un Lpo que se puede consultar no requiere ninguna modificación o tratamiento especial para servir como origen de datos LINQ
La consulta. especifica qué información se va a recuperar de uno o varios orígenes de datos. Opcionalmente, una consulta también especifica cómo debería ordenarse, agruparse y darse forma a esa información antes de ser devuelta. Una consulta se almacena en una variable de consulta y se inicializa con una expresión de consulta. Lo importante es que, en LINQ, la propia variable de consulta no realiza ninguna acción ni devuelve datos. Simplemente almacena la información necesaria para generar los resultados cuando la consulta se ejecute posteriormente.
La ejecución. La ejecución real de la consulta se aplaza hasta que se procese una iteración en la variable de consulta, en una instrucción foreach.
foreach (var c in custQuery) { Console.Write("{0}, {1}", c.Name, c.City); }
LINQ permite realizar consultas de forma sencilla
Todas las operaciones de consulta LINQ se componen de tres acciones disLntas:
1 Obtención del origen de datos.
Creación de la consulta. 2
Ejecución de la consulta. 3
Origen de datos. Un Lpo que se puede consultar no requiere ninguna modificación o tratamiento especial para servir como origen de datos LINQ
La consulta. especifica qué información se va a recuperar de uno o varios orígenes de datos. Opcionalmente, una consulta también especifica cómo debería ordenarse, agruparse y darse forma a esa información antes de ser devuelta. Una consulta se almacena en una variable de consulta y se inicializa con una expresión de consulta. Lo importante es que, en LINQ, la propia variable de consulta no realiza ninguna acción ni devuelve datos. Simplemente almacena la información necesaria para generar los resultados cuando la consulta se ejecute posteriormente.
La ejecución. La ejecución real de la consulta se aplaza hasta que se procese una iteración en la variable de consulta, en una instrucción foreach.
foreach (var c in custQuery) { Console.Write("{0}, {1}", c.Name, c.City); }
IQueryable<Customer> custQuery = from cust in db.Customers where cust.City == "London" select cust;
Northwnd db = new Northwnd(@"c:\northwnd.mdf");
using System; using System.Linq; static void Main(string[] args) { string[] names = { "Alonso", "Zheng", "Smith", "Jones", "Smythe", "Small", "Ruiz", "Hsieh", "Jorgenson", "Ilyich", "Singh", "Samba” }; var queryResults = Console.WriteLine("Names beginning with S:"); foreach (var item in queryResults) { Console.WriteLine(item); } Console.Write("Program finished, press Enter/Return to continue…"); Console.ReadLine(); }
Names beginning with S: Smith Smythe Small Singh Samba Program finished, press Enter/Return to continue...
using System; using System.Linq; static void Main(string[] args) { string[] names = { "Alonso", "Zheng", "Smith", "Jones", "Smythe", "Small", "Ruiz", "Hsieh", "Jorgenson", "Ilyich", "Singh", "Samba” }; var queryResults = Console.WriteLine("Names beginning with S:"); foreach (var item in queryResults) { Console.WriteLine(item); } Console.Write("Program finished, press Enter/Return to continue:"); Console.ReadLine(); }
Names beginning with S: Smith Smythe Small Singh Samba Program finished, press Enter/Return to continue:
from n in names where n.StartsWith("S") select n;
Expresiones Lambda Son un Lpo especial de métodos anónimos que uLlizan => como operador y que se pueden uLlizar para crear Lpos delegados o árboles de expresión. Son especialmente úLles para escribir expresiones de consulta LINQ.
(a, b) => { return a + b; }
You can think of lambda expressions as anonymous methods that take parameters and can return values.
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; var numQuery = from num in numbers where (num % 2) == 0 select num; foreach (int num in numQuery) { Console.Write("{0,1} ", num); }
Reimplementación del ejemplo haciendo uso de expresiones lambda.
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; var numQuery = numbers .Where(num => num % 2 == 0) .OrderBy(n => n); foreach (int num in numQuery) { Console.Write("{0,1} ", num); }
expresión lambda manera sencilla de escribir código que de lo contrario sería más complejo y debería escribirse como método anónimo, delegado genérico o árbol de expresión.
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; var numQuery = from num in numbers where (num % 2) == 0 select num; foreach (int num in numQuery) { Console.Write("{0,1} ", num); }
Reimplementación del ejemplo haciendo uso de expresiones lambda.
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; var numQuery = numbers .Where(num => num % 2 == 0) .OrderBy(n => n); foreach (int num in numQuery) { Console.Write("{0,1} ", num); }
expresión lambda manera sencilla de escribir código que de lo contrario sería más complejo y debería escribirse como método anónimo, delegado genérico o árbol de expresión.
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; var numQuery = from num in numbers where (num % 2) == 0 select num; foreach (int num in numQuery) { Console.Write("{0,1} ", num); }
Reimplementación del ejemplo haciendo uso de expresiones lambda.
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; var numQuery = numbers .Where(num => num % 2 == 0) .OrderBy(n => n); foreach (int num in numQuery) { Console.Write("{0,1} ", num); }
expresión lambda manera sencilla de escribir código que de lo contrario sería más complejo y debería escribirse como método anónimo, delegado genérico o árbol de expresión.
variable de entrada
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; var numQuery = from num in numbers where (num % 2) == 0 select num; foreach (int num in numQuery) { Console.Write("{0,1} ", num); }
Reimplementación del ejemplo haciendo uso de expresiones lambda.
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; var numQuery = numbers .Where(num => num % 2 == 0) .OrderBy(n => n); foreach (int num in numQuery) { Console.Write("{0,1} ", num); }
expresión lambda manera sencilla de escribir código que de lo contrario sería más complejo y debería escribirse como método anónimo, delegado genérico o árbol de expresión.
variable de entrada En el cuerpo de una expresión se pueden incluir llamadas a métodos y código más complejo.
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; var numQuery = from num in numbers where (num % 2) == 0 select num; foreach (int num in numQuery) { Console.Write("{0,1} ", num); }
Reimplementación del ejemplo haciendo uso de expresiones lambda.
Entendemos la signatura del método Where?
var numQuery = numbers .Where(num => num % 2 == 0) .OrderBy(n => n);
Enumerable. Where<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate )
Entendemos la signatura del método Where?
var numQuery = numbers .Where(num => num % 2 == 0) .OrderBy(n => n);
Clase a la que realmente pertenece el método Where. Proporciona un conjunto de métodos static que implementan IEnumerable<T>.
Colección de Lpo IEnumerable<TSource> sobre la que se va a aplicar el predicado predicate.
Enumerable. Where<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate )
Entendemos la signatura del método Where?
var numQuery = numbers .Where(num => num % 2 == 0) .OrderBy(n => n);
Clase a la que realmente pertenece el método Where. Proporciona un conjunto de métodos static que implementan IEnumerable<T>.
Colección de Lpo IEnumerable<TSource> sobre la que se va a aplicar el predicado predicate.
Enumerable. Where<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate )
Entendemos la signatura del método Where?
var numQuery = numbers .Where(num => num % 2 == 0) .OrderBy(n => n);
Función que se aplicará sobre cada elemento de source. En una función se especifican los parámetros de entrada y el Ipo del resultado. Aquí por tanto se espera 1 parámetro de Ipo TSource de entrada y un bool como resultado.
Clase a la que realmente pertenece el método Where. Proporciona un conjunto de métodos static que implementan IEnumerable<T>.
Colección de Lpo IEnumerable<TSource> sobre la que se va a aplicar el predicado predicate.
Enumerable. Where<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate )
Entendemos la signatura del método Where?
var numQuery = numbers .Where(num => num % 2 == 0) .OrderBy(n => n);
Función que se aplicará sobre cada elemento de source. En una función se especifican los parámetros de entrada y el Ipo del resultado. Aquí por tanto se espera 1 parámetro de Ipo TSource de entrada y un bool como resultado.
Clase a la que realmente pertenece el método Where. Proporciona un conjunto de métodos static que implementan IEnumerable<T>.
Delegados, Eventos y Métodos de extensión Referencias a métodos. Qué hace el código
cuando no le estamos observando?
Delegados
Son básicamente un puntero de función en C++, pero Lenen seguridad de Lpos (fuertemente Lpados).
Permiten pasar los métodos como parámetros.
Tipo que representa referencias a métodos con una lista de parámetros determinada y un Ipo de valor devuelto.
Has pensado alguna vez pasar un método como argumento a otros métodos?
Pueden uLlizarse para definir métodos de devolución de llamada.
Pueden encadenarse entre sí; por ejemplo, se puede llamar a varios métodos en un solo evento.
Un delegado es un Ipo de referencia, como otro cualquiera, que en lugar de apuntar a un objeto, apunta a un método.
Delegados Declaración de delegados
{modificador acceso} delegate {tipo retorno} {identificador}({lista argumentos});
public delegate int MyDelegate(string s);
En este ejemplo el delegado puede uLlizarse para referenciar a cualquier método que contenga como parámetro de entrada un string y como resultado de salida un int.
La declaración de un delegado determina los métodos que pueden ser referenciados por el delegado.
Delegados Instanciación de delegados
public delegate void PrintString(string s); ... PrintString ps1 = new PrintString(WriteToScreen); PrintString ps2 = new PrintString(WriteToFile);
Una vez que el delegado se ha declarado, debemos crear un objeto delegado con la palabra reservada new y asociarlo a algún método en parLcular que cumpla con la signatura del delegado declarado.
Cuando se instancia un delegado, el argumento que se le pasa al delegado es solamente el nombre del método. No se deben indicar los parámetros de entrada del método!
Delegados Invocación de métodos haciendo uso de los delegados instanciados
public delegate void PrintString(string s); ... PrintString ps1 = new PrintString(WriteToScreen); PrintString ps2 = new PrintString(WriteToFile); ps1("Texto a escribir en pantalla"); ps2("Texto a escribir en fichero");
Declaración de delegado.
public class Program { static void Main(string[] args) { //create delegate instances PerformCalculation pc1 = new PerformCalculation(Add); PerformCalculation pc2 = new PerformCalculation(Mult); //calling the methods using the delegate objects int result1 = pc1(5, 7); Console.WriteLine(”Result Add: {0}", result1); int result1 = pc1(5, 7); Console.WriteLine(”Result Mult: {0}", result2); } public static int Add(int a, int b) { return a + b; } public static int Mult(int a, int b) { return a * b; } }
public delegate int PerformCalculation(int x, int y);
Instanciación de delegados.
3 Invocación de métodos mediante los delegados instanciados
Result Add: 12 Result Mult: 35
1
2
Ejemplo del delegado printString.
Ejemplo prácLco
Delegados Implementar una aplicación de consola que haga uso del delegado printString y los métodos WriteToScreen y WriteToFile.
Ejemplo de delegado.
public void Increment(MagicNumber mn) {
mn.Numer++; } public void Decrement(MagicNumber mn) {
mn.Numer--; }
public class MagicNumber { public int Number { get; set; } }
public delegate void MagicNumberModifier(MagicNumber mn);
List<MagicNumber> magicNumbers = new List<MagicNumber>(); magicNumbers.Add(new MagicNumber() { Number = 4}); magicNumbers.Add(new MagicNumber() { Number = 6}); magicNumbers.Add(new MagicNumber() { Number = 9}); magicNumbers.Add(new MagicNumber() { Number = 13}); magicNumbers.Add(new MagicNumber() { Number = 20});
Creamos una lista de MagicNumber
Ejemplo prácLco
Delegados Definir un método que aplique el delegado MagicNumberModifier a la lista magicNumbers.
Eventos Mensaje que envía un objeto cuando ocurre una acción. La acción puede estar causada por la interacción del usuario, como un click, o por otra lógica del programa. El objeto que provoca el evento se conoce como remitente del evento. El objeto que captura el evento y responde a él se denomina receptor del evento.
C# permite hacer uso del patrón publicador-‐subscriptor a través del uso de delegados y eventos.
El remitente determina cuándo se produce un evento; los receptores o suscriptores determinan qué operación se realiza en respuesta al evento.
Un evento puede tener varios suscriptores. Un suscriptor puede controlar varios eventos de varios editores.
Nunca se provocan eventos que no Lenen suscriptores.
Si un evento Lene varios suscriptores, se invoca a los controladores de eventos síncronamente cuando se produce el evento.
En la biblioteca de clases .NET Framework, los eventos se basan en el delegado EventHandler y en la clase base EventArgs.
Eventos Sintaxis a seguir para declarar un evento.
{modificador acceso} event {delegado} {identificador};
Para declarar un evento en una clase en primer lugar debemos declarar un delegado para dicho evento.
public delegate void NumManipulationHandler();
Después declaramos el evento:
public event NumManipulationHandler ChangeNum;
1
2
Declaración de delegado. public class EventSample { private int value; public delegate void NumManipulationHandler(); public event NumManipulationHandler ChangeNum; protected virtual void OnNumChanged() { if (ChangeNum != null) { ChangeNum(); } else { Console.WriteLine("Event fired!"); } } public EventTest(int n) { SetValue(n); } public void SetValue(int n) { if (value != n) { value = n; OnNumChanged(); } } }
Declaración del evento.
Event Fired! Event Fired! Event Fired! Press any key to continue...
1
2
public class MainClass { public static void Main() { EventTest e = new EventTest(5); e.SetValue(7); e.SetValue(11); Console.ReadKey(); } }
public class BoilerEventAppl { class Boiler { private int temp; private int pressure; public Boiler(int t, int p) { temp = t; pressure = p; } public int getTemp() { return temp; } public int getPressure() { return pressure; } } } // this class keeps a provision for writing into the log file class BoilerInfoLogger { FileStream fs; StreamWriter sw; public BoilerInfoLogger(string filename) { fs = new FileStream(filename, FileMode.Append, FileAccess.Write); sw = new StreamWriter(fs); } public void Logger(string info) { sw.WriteLine(info); } public void Close() { sw.Close(); fs.Close(); } }
// event publisher class DelegateBoilerEvent { public delegate void BoilerLogHandler(string status); //Defining event based on the above delegate public event BoilerLogHandler BoilerEventLog; public void LogProcess() { string remarks = "O. K"; Boiler b = new Boiler(100, 12); int t = b.getTemp(); int p = b.getPressure(); if (t > 150 || t < 80 || p < 12 || p > 15) remarks = "Need Maintenance”; OnBoilerEventLog("Logging Info:\n"); OnBoilerEventLog("Temparature " + t + "\nPressure: " + p); OnBoilerEventLog("\nMessage: " + remarks); } protected void OnBoilerEventLog(string message) { if (BoilerEventLog != null) { BoilerEventLog(message); } } }
eventos Ejemplo prácLco
Logging info: Temperature 100 Pressure 12 Message: O.K
public class RecordBoilerInfo { static void Logger(string info) { Console.WriteLine(info); } static void Main(string[] args) { BoilerInfoLogger filelog = new BoilerInfoLogger("e:\\boiler.txt"); DelegateBoilerEvent boilerEvent = new DelegateBoilerEvent(); boilerEvent.BoilerEventLog += new DelegateBoilerEvent.BoilerLogHandler(Logger); boilerEvent.BoilerEventLog += new DelegateBoilerEvent.BoilerLogHandler(filelog.Logger); boilerEvent.LogProcess(); Console.ReadLine(); filelog.Close(); } }
[modificador_acceso] static class Nombre_Clase_Estatica { [modificador_acceso] static bool Nombre_Metodo(this Tipo_A_Extender nombre [,otros_parametros] { // Implementación } }
Métodos de extensión permiten "agregar" métodos a los Lpos existentes sin crear un nuevo Lpo derivado, recompilar o modificar de otra manera el Lpo original.
[modificador_acceso] static class Nombre_Clase_Estatica { [modificador_acceso] static bool Nombre_Metodo(this Tipo_A_Extender nombre [,otros_parametros] { // Implementación } }
Métodos de extensión permiten "agregar" métodos a los Lpos existentes sin crear un nuevo Lpo derivado, recompilar o modificar de otra manera el Lpo original.
namespace ExtensionMethods { public static class StringExtensions { public static int WordCount(this String str) { return str.Split(new char[] { ' ', '.', '?' }, StringSplitOptions.RemoveEmptyEntries).Length; } } }
Método de extensión para la clase String
Tests unitarios Beneficios de las pruebas unitarias
Fomentan el cambio y la refactorización. Podemos cambiar sin ningún problema nuestro código si lo consideramos mejorable. Si el cambio no estuviera realizado correctamente, las pruebas nos avisarían de ello. Seguramente la frase “si funciona no lo toques” a más de uno nos resultará familiar. Si hubiera pruebas unitarias, no sería necesario pronunciarla.
Se reducen drás6camente los problemas y 6empos dedicados a la integración. En las pruebas se simulan las dependencias, lo que nos permite que podamos probar nuestro código sin disponer del resto de módulos. Ya sabemos, por experiencia, que los procesos de integración son más de una vez traumáLcos, dejándolos habitualmente para el final del proyecto. La frase “sólo queda integrar”, haciendo referencia a que el proyecto está cerca de terminar, suele ser engañosa, ya que el periodo de integración suele estar lleno de curvas.
Nos ayudan a entender mejor el código. A través de las pruebas podemos comprender mejor qué hace un método y qué se espera de él.
Nos permiten probar o depurar un módulo sin necesidad de disponer del sistema completo. Aunque seamos los propietarios de toda la aplicación, en algunas situaciones montar un entorno para poder probar una incidencia es más costoso que corregir la incidencia propiamente dicha. Si parLmos de la prueba unitaria podemos centrarnos en corregir el error de una forma más rápida y lógicamente, asegurándonos posteriormente que todo funciona según lo esperado.
Forma de probar el correcto funcionamiento de una parte del código.
Tests unitarios Beneficios de las pruebas unitarias
Se reducen drás6camente los problemas y 6empos dedicados a la integración. En las pruebas se simulan las dependencias, lo que nos permite que podamos probar nuestro código sin disponer del resto de módulos. Ya sabemos, por experiencia, que los procesos de integración son más de una vez traumáLcos, dejándolos habitualmente para el final del proyecto. La frase “sólo queda integrar”, haciendo referencia a que el proyecto está cerca de terminar, suele ser engañosa, ya que el periodo de integración suele estar lleno de curvas.
Forma de probar el correcto funcionamiento de una parte del código.
Nos ayudan a entender mejor el código. A través de las pruebas podemos comprender mejor qué hace un método y qué se espera de él.
Nos permiten probar o depurar un módulo sin necesidad de disponer del sistema completo. Aunque seamos los propietarios de toda la aplicación, en algunas situaciones montar un entorno para poder probar una incidencia es más costoso que corregir la incidencia propiamente dicha. Si parLmos de la prueba unitaria podemos centrarnos en corregir el error de una forma más rápida y lógicamente, asegurándonos posteriormente que todo funciona según lo esperado.
Fomentan el cambio y la refactorización. Podemos cambiar sin ningún problema nuestro código si lo consideramos mejorable. Si el cambio no estuviera realizado correctamente, las pruebas nos avisarían de ello. Seguramente la frase “si funciona no lo toques” a más de uno nos resultará familiar. Si hubiera pruebas unitarias, no sería necesario pronunciarla.
Tests unitarios Beneficios de las pruebas unitarias
Nos ayudan a entender mejor el código. A través de las pruebas podemos comprender mejor qué hace un método y qué se espera de él.
Forma de probar el correcto funcionamiento de una parte del código.
Nos permiten probar o depurar un módulo sin necesidad de disponer del sistema completo. Aunque seamos los propietarios de toda la aplicación, en algunas situaciones montar un entorno para poder probar una incidencia es más costoso que corregir la incidencia propiamente dicha. Si parLmos de la prueba unitaria podemos centrarnos en corregir el error de una forma más rápida y lógicamente, asegurándonos posteriormente que todo funciona según lo esperado.
Fomentan el cambio y la refactorización. Podemos cambiar sin ningún problema nuestro código si lo consideramos mejorable. Si el cambio no estuviera realizado correctamente, las pruebas nos avisarían de ello. Seguramente la frase “si funciona no lo toques” a más de uno nos resultará familiar. Si hubiera pruebas unitarias, no sería necesario pronunciarla.
Se reducen drás6camente los problemas y 6empos dedicados a la integración. En las pruebas se simulan las dependencias, lo que nos permite que podamos probar nuestro código sin disponer del resto de módulos. Ya sabemos, por experiencia, que los procesos de integración son más de una vez traumáLcos, dejándolos habitualmente para el final del proyecto. La frase “sólo queda integrar”, haciendo referencia a que el proyecto está cerca de terminar, suele ser engañosa, ya que el periodo de integración suele estar lleno de curvas.
Tests unitarios Beneficios de las pruebas unitarias
Nos permiten probar o depurar un módulo sin necesidad de disponer del sistema completo. Aunque seamos los propietarios de toda la aplicación, en algunas situaciones montar un entorno para poder probar una incidencia es más costoso que corregir la incidencia propiamente dicha. Si parLmos de la prueba unitaria podemos centrarnos en corregir el error de una forma más rápida y lógicamente, asegurándonos posteriormente que todo funciona según lo esperado.
Forma de probar el correcto funcionamiento de una parte del código.
Fomentan el cambio y la refactorización. Podemos cambiar sin ningún problema nuestro código si lo consideramos mejorable. Si el cambio no estuviera realizado correctamente, las pruebas nos avisarían de ello. Seguramente la frase “si funciona no lo toques” a más de uno nos resultará familiar. Si hubiera pruebas unitarias, no sería necesario pronunciarla.
Se reducen drás6camente los problemas y 6empos dedicados a la integración. En las pruebas se simulan las dependencias, lo que nos permite que podamos probar nuestro código sin disponer del resto de módulos. Ya sabemos, por experiencia, que los procesos de integración son más de una vez traumáLcos, dejándolos habitualmente para el final del proyecto. La frase “sólo queda integrar”, haciendo referencia a que el proyecto está cerca de terminar, suele ser engañosa, ya que el periodo de integración suele estar lleno de curvas.
Nos ayudan a entender mejor el código. A través de las pruebas podemos comprender mejor qué hace un método y qué se espera de él.
Tests unitarios Forma de probar el correcto funcionamiento de una parte del código.
¡¡ La vida del desarrollador será mucho más fácil !!
La calidad de nuestro código mejorará, se reducirán los Bempos de depuración y la corrección de incidencias. Por tanto, el cliente estará mucho más contento porque la aplicación hace lo que él quiere que haga, que realmente es por lo que ha pagado.
Beneficios de las pruebas unitarias
Tests unitarios Caracterís6cas de una buena prueba unitaria
Automa6zable. Las pruebas unitarias se Lenen que poder ejecutar sin necesidad de intervención manual. Esta caracterísLca posibilita que podamos automaLzar su ejecución, siendo muy úLl en integración conLnua.
Tienen que poder repe6rse tantas veces como uno quiera. Por este moLvo, la rapidez de las pruebas Lene un factor clave. Si pasar las pruebas es un proceso lento no se pasarán de forma habitual, por lo que se perderán los beneficios que éstas nos ofrecen.
Deben poder cubrir casi la totalidad del código (o por lo menos el más crí6co) de nuestra aplicación. Una prueba unitaria sera tan buena como su cobertura de código. La cobertura de código marca la canLdad de código de la aplicación que está someLdo a una prueba. Por tanto, si la cobertura es baja, significará que gran parte de nuestro código está sin probar.
Independientes. La ejecución de una prueba no debe afectar a la ejecución de otra. Después de la ejecución de una prueba el entorno debería quedar igual que estaba antes de realizar la prueba. Profesionales. Cualquier desarrollador debería poder conocer claramente cuál es el objeLvo de la prueba y su funcionamiento. Esto sólo se consigue si se trata el código de pruebas como el código de la aplicación, con la misma profesionalidad, documentación, etc.
Tests unitarios Caracterís6cas de una buena prueba unitaria
Automa6zable. Las pruebas unitarias se Lenen que poder ejecutar sin necesidad de intervención manual. Esta caracterísLca posibilita que podamos automaLzar su ejecución, siendo muy úLl en integración conLnua.
Tienen que poder repe6rse tantas veces como uno quiera. Por este moLvo, la rapidez de las pruebas Lene un factor clave. Si pasar las pruebas es un proceso lento no se pasarán de forma habitual, por lo que se perderán los beneficios que éstas nos ofrecen.
Deben poder cubrir casi la totalidad del código (o por lo menos el más crí6co) de nuestra aplicación. Una prueba unitaria sera tan buena como su cobertura de código. La cobertura de código marca la canLdad de código de la aplicación que está someLdo a una prueba. Por tanto, si la cobertura es baja, significará que gran parte de nuestro código está sin probar.
Independientes. La ejecución de una prueba no debe afectar a la ejecución de otra. Después de la ejecución de una prueba el entorno debería quedar igual que estaba antes de realizar la prueba. Profesionales. Cualquier desarrollador debería poder conocer claramente cuál es el objeLvo de la prueba y su funcionamiento. Esto sólo se consigue si se trata el código de pruebas como el código de la aplicación, con la misma profesionalidad, documentación, etc.
Tests unitarios Caracterís6cas de una buena prueba unitaria
Automa6zable. Las pruebas unitarias se Lenen que poder ejecutar sin necesidad de intervención manual. Esta caracterísLca posibilita que podamos automaLzar su ejecución, siendo muy úLl en integración conLnua.
Tienen que poder repe6rse tantas veces como uno quiera. Por este moLvo, la rapidez de las pruebas Lene un factor clave. Si pasar las pruebas es un proceso lento no se pasarán de forma habitual, por lo que se perderán los beneficios que éstas nos ofrecen.
Deben poder cubrir casi la totalidad del código (o por lo menos el más crí6co) de nuestra aplicación. Una prueba unitaria sera tan buena como su cobertura de código. La cobertura de código marca la canLdad de código de la aplicación que está someLdo a una prueba. Por tanto, si la cobertura es baja, significará que gran parte de nuestro código está sin probar.
Independientes. La ejecución de una prueba no debe afectar a la ejecución de otra. Después de la ejecución de una prueba el entorno debería quedar igual que estaba antes de realizar la prueba. Profesionales. Cualquier desarrollador debería poder conocer claramente cuál es el objeLvo de la prueba y su funcionamiento. Esto sólo se consigue si se trata el código de pruebas como el código de la aplicación, con la misma profesionalidad, documentación, etc.
Tests unitarios Caracterís6cas de una buena prueba unitaria
Automa6zable. Las pruebas unitarias se Lenen que poder ejecutar sin necesidad de intervención manual. Esta caracterísLca posibilita que podamos automaLzar su ejecución, siendo muy úLl en integración conLnua.
Tienen que poder repe6rse tantas veces como uno quiera. Por este moLvo, la rapidez de las pruebas Lene un factor clave. Si pasar las pruebas es un proceso lento no se pasarán de forma habitual, por lo que se perderán los beneficios que éstas nos ofrecen.
Deben poder cubrir casi la totalidad del código (o por lo menos el más crí6co) de nuestra aplicación. Una prueba unitaria sera tan buena como su cobertura de código. La cobertura de código marca la canLdad de código de la aplicación que está someLdo a una prueba. Por tanto, si la cobertura es baja, significará que gran parte de nuestro código está sin probar.
Independientes. La ejecución de una prueba no debe afectar a la ejecución de otra. Después de la ejecución de una prueba el entorno debería quedar igual que estaba antes de realizar la prueba. Profesionales. Cualquier desarrollador debería poder conocer claramente cuál es el objeLvo de la prueba y su funcionamiento. Esto sólo se consigue si se trata el código de pruebas como el código de la aplicación, con la misma profesionalidad, documentación, etc.
Tests unitarios Caracterís6cas de una buena prueba unitaria
Automa6zable. Las pruebas unitarias se Lenen que poder ejecutar sin necesidad de intervención manual. Esta caracterísLca posibilita que podamos automaLzar su ejecución, siendo muy úLl en integración conLnua.
Tienen que poder repe6rse tantas veces como uno quiera. Por este moLvo, la rapidez de las pruebas Lene un factor clave. Si pasar las pruebas es un proceso lento no se pasarán de forma habitual, por lo que se perderán los beneficios que éstas nos ofrecen.
Deben poder cubrir casi la totalidad del código (o por lo menos el más crí6co) de nuestra aplicación. Una prueba unitaria sera tan buena como su cobertura de código. La cobertura de código marca la canLdad de código de la aplicación que está someLdo a una prueba. Por tanto, si la cobertura es baja, significará que gran parte de nuestro código está sin probar.
Independientes. La ejecución de una prueba no debe afectar a la ejecución de otra. Después de la ejecución de una prueba el entorno debería quedar igual que estaba antes de realizar la prueba. Profesionales. Cualquier desarrollador debería poder conocer claramente cuál es el objeLvo de la prueba y su funcionamiento. Esto sólo se consigue si se trata el código de pruebas como el código de la aplicación, con la misma profesionalidad, documentación, etc.
Tests unitarios Aunque los beneficios de las pruebas unitarias puedan parecer claros, todavía existen hoy en día proyectos que carecen de éstas. Pero sin son tan buenas, ¿por qué hay desarrolladores que no las usan? La razón principal es que existe bastante desconocimiento en esta materia, poca tradición y algunos falsos mitos.
Mitos de las pruebas unitarias
Creer que escribir pruebas unitarias es escribir el doble de código. Escribir una prueba nunca es escribir el doble de código, aunque lógicamente sí es escribir más código. El mito es totalmente falso. Debes estar convencido de que el uso de pruebas unitarias es el enfoque correcto y no ser flexible; las pruebas unitarias no son opcionales y deben realizarse a medida que se desarrolla.
Desarrollar pruebas incrementan los 6empos de desarrollo, incrementando los costes del proyecto. Entre desarrollar y no probar y desarrollar haciendo pruebas unitarias, reconoceremos que es más rápido desarrollar sin probar. Si no desarrollamos código de calidad y no realizamos pruebas, los Lempos de desarrollo se podrán disparar enormemente: Lempo de integración, Lempo de depuración, Lempo de incidencias, etc. y existe un problema mayor: la confianza del cliente. Un producto de baja calidad, lleno de incidencias, es la peor tarjeta de presentación.
Tests unitarios Mitos de las pruebas unitarias
Creer que escribir pruebas unitarias es escribir el doble de código. Escribir una prueba nunca es escribir el doble de código, aunque lógicamente sí es escribir más código. El mito es totalmente falso. Debes estar convencido de que el uso de pruebas unitarias es el enfoque correcto y no ser flexible; las pruebas unitarias no son opcionales y deben realizarse a medida que se desarrolla.
Desarrollar pruebas incrementan los 6empos de desarrollo, incrementando los costes del proyecto. Entre desarrollar y no probar y desarrollar haciendo pruebas unitarias, reconoceremos que es más rápido desarrollar sin probar. Si no desarrollamos código de calidad y no realizamos pruebas, los Lempos de desarrollo se podrán disparar enormemente: Lempo de integración, Lempo de depuración, Lempo de incidencias, etc. y existe un problema mayor: la confianza del cliente. Un producto de baja calidad, lleno de incidencias, es la peor tarjeta de presentación.
Aunque los beneficios de las pruebas unitarias puedan parecer claros, todavía existen hoy en día proyectos que carecen de éstas. Pero sin son tan buenas, ¿por qué hay desarrolladores que no las usan? La razón principal es que existe bastante desconocimiento en esta materia, poca tradición y algunos falsos mitos.
Tests unitarios Nos proporciona un sistema sencillo para poder crear nuestras pruebas unitarias. Nos facilita la creación de los proyectos de pruebas y nos genera la estructura básica que Lenen que tener las pruebas.
Visual Studio
Visual Studio Unit TesLng Framework
MSTest Una de las herramientas más poderosas que tenemos los desarrolladores actualmente.
Tests unitarios
hsps://msdn.microsoR.com/es-‐es/library/ms182532.aspx#bkmk_create_a_unit_test_project
Ejemplo prácLco
Visual Studio Unit TesLng Framework
MSTest
Anatomía: sección superior Tests unitarios
using System; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace BankAccountTests { [TestClass] public class BankAccountTests { private TestContext testContextInstance; public TestContext TestContext {
get { return testContextInstance; } set { testContextInstance = value; }
} ... } }
Microsoft.VisualStudio.TestTools.UnitTesting
al crear una prueba unitaria, se agrega al proyecto de prueba una referencia al espacio de nombres Microsoft.VisualStudio.TestTools.UnitTesting. El espacio de nombres Lene muchas clases para ayudarnos con las pruebas unitarias: Clases Assert que se pueden uLlizar para comprobar las condiciones en las pruebas unitarias, Atributos de inicialización y limpieza para ejecutar código antes o después de ejecutar las pruebas unitarias, a fin de asegurarse un estado inicial y final concretos, la clase TestContext que almacena la información que se proporciona a las pruebas unitarias, como la conexión de datos para las pruebas controladas por datos, etc.
TestClassAttribute
indica que esta clase determinada puede contener métodos marcados con el atributo [TestMethod()]. Sin TestClassAttribute los métodos de prueba se omiten.
TestContext
se incluye una variable denominada testContextInstance para cada clase de prueba. Las propiedades de la clase TestContext almacenan información referente a la prueba actual.
Tests unitarios
using System; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace BankAccountTests { [TestClass] public class BankAccountTests { private TestContext testContextInstance; public TestContext TestContext {
get { return testContextInstance; } set { testContextInstance = value; }
} ... } }
TestClassAttribute
indica que esta clase determinada puede contener métodos marcados con el atributo [TestMethod()]. Sin TestClassAttribute los métodos de prueba se omiten.
TestContext
se incluye una variable denominada testContextInstance para cada clase de prueba. Las propiedades de la clase TestContext almacenan información referente a la prueba actual.
Microsoft.VisualStudio.TestTools.UnitTesting
al crear una prueba unitaria, se agrega al proyecto de prueba una referencia al espacio de nombres Microsoft.VisualStudio.TestTools.UnitTesting. El espacio de nombres Lene muchas clases para ayudarnos con las pruebas unitarias: Clases Assert que se pueden uLlizar para comprobar las condiciones en las pruebas unitarias, Atributos de inicialización y limpieza para ejecutar código antes o después de ejecutar las pruebas unitarias, a fin de asegurarse un estado inicial y final concretos, la clase TestContext que almacena la información que se proporciona a las pruebas unitarias, como la conexión de datos para las pruebas controladas por datos, etc.
Anatomía: sección superior
Tests unitarios
using System; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace BankAccountTests { [TestClass] public class BankAccountTests { private TestContext testContextInstance; public TestContext TestContext {
get { return testContextInstance; } set { testContextInstance = value; }
} ... } }
Microsoft.VisualStudio.TestTools.UnitTesting
al crear una prueba unitaria, se agrega al proyecto de prueba una referencia al espacio de nombres Microsoft.VisualStudio.TestTools.UnitTesting. El espacio de nombres Lene muchas clases para ayudarnos con las pruebas unitarias: Clases Assert que se pueden uLlizar para comprobar las condiciones en las pruebas unitarias, Atributos de inicialización y limpieza para ejecutar código antes o después de ejecutar las pruebas unitarias, a fin de asegurarse un estado inicial y final concretos, la clase TestContext que almacena la información que se proporciona a las pruebas unitarias, como la conexión de datos para las pruebas controladas por datos, etc.
TestClassAttribute
indica que esta clase determinada puede contener métodos marcados con el atributo [TestMethod()]. Sin TestClassAttribute los métodos de prueba se omiten.
TestContext
se incluye una variable denominada testContextInstance para cada clase de prueba. Las propiedades de la clase TestContext almacenan información referente a la prueba actual.
Anatomía: sección superior
Tests unitarios
using System; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace BankAccountTests { [TestClass] public class BankAccountTests { private TestContext testContextInstance; public TestContext TestContext {
get { return testContextInstance; } set { testContextInstance = value; }
} ... } }
Microsoft.VisualStudio.TestTools.UnitTesting
al crear una prueba unitaria, se agrega al proyecto de prueba una referencia al espacio de nombres Microsoft.VisualStudio.TestTools.UnitTesting. El espacio de nombres Lene muchas clases para ayudarnos con las pruebas unitarias: Clases Assert que se pueden uLlizar para comprobar las condiciones en las pruebas unitarias, Atributos de inicialización y limpieza para ejecutar código antes o después de ejecutar las pruebas unitarias, a fin de asegurarse un estado inicial y final concretos, la clase TestContext que almacena la información que se proporciona a las pruebas unitarias, como la conexión de datos para las pruebas controladas por datos, etc.
TestClassAttribute
indica que esta clase determinada puede contener métodos marcados con el atributo [TestMethod()]. Sin TestClassAttribute los métodos de prueba se omiten.
TestContext
se incluye una variable denominada testContextInstance para cada clase de prueba. Las propiedades de la clase TestContext almacenan información referente a la prueba actual.
Anatomía: sección superior
[TestMethod] public void Debit_WithValidAmount_UpdatesBalance() { // arrange double beginningBalance = 11.99; double debitAmount = 4.55; double expected = 7.44; BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance); // act account.Debit(debitAmount); // assert double actual = account.Balance; Assert.AreEqual(expected, actual, 0.001, "Account not debited correctly"); }
Tests unitarios
Additional test attribute
Anatomía: sección inferior
[TestMethod] public void Debit_WithValidAmount_UpdatesBalance() { // arrange double beginningBalance = 11.99; double debitAmount = 4.55; double expected = 7.44; BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance); // act account.Debit(debitAmount); // assert double actual = account.Balance; Assert.AreEqual(expected, actual, 0.001, "Account not debited correctly"); }
Tests unitarios
Additional test attribute
Atributos de prueba adicionales
[ClassInitialize] para ejecutar código antes de la primera prueba de la clase. [ClassCleanUp]
para ejecutar código cuando todas las pruebas de una clase se hayan ejecutado. [TestInitialize] para ejecutar código antes de hacer cada prueba. [TestCleanUp]
para ejecutar código cuando cada prueba se haya ejecutado.
Anatomía: sección inferior
[TestMethod] public void Debit_WithValidAmount_UpdatesBalance() { // arrange double beginningBalance = 11.99; double debitAmount = 4.55; double expected = 7.44; BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance); // act account.Debit(debitAmount); // assert double actual = account.Balance; Assert.AreEqual(expected, actual, 0.001, "Account not debited correctly"); }
Tests unitarios
Additional test attribute
Atributos de prueba adicionales
[ClassInitialize] para ejecutar código antes de la primera prueba de la clase. [ClassCleanUp]
para ejecutar código cuando todas las pruebas de una clase se hayan ejecutado. [TestInitialize] para ejecutar código antes de hacer cada prueba. [TestCleanUp]
para ejecutar código cuando cada prueba se haya ejecutado.
TestMethodAttribute
cada método de prueba unitaria se marca con el atributo [TestMethod]. Sin este atributo, la prueba unitaria no se ejecuta.
Anatomía: sección inferior
[TestMethod] public void Debit_WithValidAmount_UpdatesBalance() { // arrange double beginningBalance = 11.99; double debitAmount = 4.55; double expected = 7.44; BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance); // act account.Debit(debitAmount); // assert double actual = account.Balance; Assert.AreEqual(expected, actual, 0.001, "Account not debited correctly"); }
Tests unitarios
Additional test attribute
Atributos de prueba adicionales
[ClassInitialize] para ejecutar código antes de la primera prueba de la clase. [ClassCleanUp]
para ejecutar código cuando todas las pruebas de una clase se hayan ejecutado. [TestInitialize] para ejecutar código antes de hacer cada prueba. [TestCleanUp]
para ejecutar código cuando cada prueba se haya ejecutado.
TestMethodAttribute
cada método de prueba unitaria se marca con el atributo [TestMethod]. Sin este atributo, la prueba unitaria no se ejecuta.
Lógica del método de prueba
El contenido de los métodos de prueba varía dependiendo del Lpo de prueba unitaria y de la naturaleza del método que se prueba.
Anatomía: sección inferior
Interoperabilidad Cómo u6lizar clases de código no administrado desde
aplicaciones .NET y viceversa
Consumo de librerías Código administrado y no administrado
Assembly manifest Type metadata
CIL code Resources
Platform invoke
C#
C L R
Managed source code
Compiler
DLL
func6on DLL
U n m a n a g e d M a n a g e d
Consumo de librerías Es el código que ha sido creado con lenguajes de .NET, por ejemplo Visual Basic .NET, y que es uLlizado desde otro lenguaje, también de .NET, por ejemplo C#.
Código administrado
Es código que se ejecuta bajo el control de CLR (Common Language Run6me)
Consumo de librerías Para poder uLlizar las librerías creadas en cualquier lenguaje de .NET desde nuestro proyecto, tendremos que seguir los mismos pasos que para añadir referencias de cualquier otra librería: por medio de la opción “Add Reference…” en la pestaña “SoluIon Explorer”.
Código administrado en Visual Studio
Si la librería ya está compilada tendremos que pulsar en el botón “Browse” y localizar el ensamblado (que ya debe estar compilado como .dll), seleccionarlo y agregarlo. Si esa librería que queremos referenciar es un proyecto creado (desarrollado) por nosotros, podemos añadirlo a la solución actual y agregar la referencia indicando el proyecto, desde la pestaña “Projects”, de esta forma tendremos oportunidad de depurar la librería junto a nuestra aplicación cliente.
Consumo de librerías Es el código que se ejecuta fuera del control de Common Language RunLme (CLR). Los componentes COM, COM+, C++, los componentes de AcLveX y la API de MicrosoR Win32 son ejemplos de código no administrado.
Código no administrado
Interoperabilidad COM Proporciona compaLbilidad con versiones anteriores para permiLr el acceso a componentes COM, también conocidos como componentes de automaLzación OLE o simplemente AcLveX, existentes sin necesidad de modificar el componente original. Este Lpo de componentes los podemos generar con lenguajes capaces de crear controles o librerías AcLveX, como Visual Basic 6.0. Esta forma de comunicación la podemos realizar en dos direcciones, una para poder acceder desde .NET a componentes COM, y la otra para acceder a componentes creados en .NET desde lenguajes capaces de uLlizar COM.
Invocación de plataforma -‐ PInvoke Posibilidad de llamar a funciones no administradas implementadas en bibliotecas de vínculos dinámicos (DLL), como las que se encuentran en la API de MicrosoR Win32.
1
2
Consumo de librerías Es el código que se ejecuta fuera del control de Common Language RunLme (CLR). Los componentes COM, COM+, C++, los componentes de AcLveX y la API de MicrosoR Win32 son ejemplos de código no administrado.
Código no administrado
Interoperabilidad COM Proporciona compaLbilidad con versiones anteriores para permiLr el acceso a componentes COM, también conocidos como componentes de automaLzación OLE o simplemente AcLveX, existentes sin necesidad de modificar el componente original. Este Lpo de componentes los podemos generar con lenguajes capaces de crear controles o librerías AcLveX, como Visual Basic 6.0. Esta forma de comunicación la podemos realizar en dos direcciones, una para poder acceder desde .NET a componentes COM, y la otra para acceder a componentes creados en .NET desde lenguajes capaces de uLlizar COM.
Invocación de plataforma -‐ PInvoke Posibilidad de llamar a funciones no administradas implementadas en bibliotecas de vínculos dinámicos (DLL), como las que se encuentran en la API de MicrosoR Win32.
1
2
Consumo de librerías Es el código que se ejecuta fuera del control de Common Language RunLme (CLR). Los componentes COM, COM+, C++, los componentes de AcLveX y la API de MicrosoR Win32 son ejemplos de código no administrado.
Código no administrado
Interoperabilidad COM Proporciona compaLbilidad con versiones anteriores para permiLr el acceso a componentes COM, también conocidos como componentes de automaLzación OLE o simplemente AcLveX, existentes sin necesidad de modificar el componente original. Este Lpo de componentes los podemos generar con lenguajes capaces de crear controles o librerías AcLveX, como Visual Basic 6.0. Esta forma de comunicación la podemos realizar en dos direcciones, una para poder acceder desde .NET a componentes COM, y la otra para acceder a componentes creados en .NET desde lenguajes capaces de uLlizar COM.
System.Runtime.InteropServices
.NET Framework proporciona un espacio de nombres dedicado que habilita la interoperabilidad con el código no administrado a través de los servicios de invocación de plataforma:
Invocación de plataforma -‐ PInvoke Posibilidad de llamar a funciones no administradas implementadas en bibliotecas de vínculos dinámicos (DLL), como las que se encuentran en la API de MicrosoR Win32.
1
2
1 Interoperabilidad COM Cómo hacer uso de componentes COM desde aplicaciones .NET en Visual Studio.
Trabajar con componentes COM (o componentes AcLveX) desde Visual Studio .NET es relaLvamente fácil y no requiere hacer nada especial por nuestra parte, ya que el proceso es el mismo que el indicado cuando hacemos uso de código administrado: agregar una referencia en nuestro proyecto al componente COM (ya sea una DLL un control OCX e incluso un EXE), que queramos usar. De forma predeterminada, y tal como funciona COM, todos los controles (OCX) y las librerías (DLL) deben estar previamente registrados en el sistema, por tanto esos componentes registrados serán los que se muestren en la pestaña COM del cuadro de diálogo de agregar referencias. Seleccionamos el que nos interese y sera el propio Visual Studio el que se encargue de los “pormenores” para que podamos usar ese componente en nuestro proyecto de Visual Studio.
2 Invocación de plataforma -‐ PInvoke Cómo hacer uso de funciones definidas en librerías creadas con lenguajes que no están amparados bajo las tecnologías expuestas por .NET Framework. Un ejemplo de estas librerías pueden ser librerías implementadas en lenguajes como C/C++ o Delphi. El caso más habitual es el uso de las funciones del API de Windows.
Atributo que permite invocar funciones de código no administrado desde una aplicación administrada. Debemos aplicarlo a la declaración de una función que nos servirá de puente para acceder a la función original del API.
[DllImport]
DWORD GetLongPathName( LPCTSTR lpszShortPath, LPTSTR lpszLongPath, DWORD cchBuffer );
2 Invocación de plataforma -‐ PInvoke Por ejemplo, si tenemos esta declaración del API de Windows:
En C# la podríamos declarar de esta otra:
System.Runtime.InteropServices.DllImport("kernel32.dll")] private extern static int GetLongPathName( string lpszShortPath, StringBuilder lpszLongPath, int cchBuffer );
DWORD GetLongPathName( LPCTSTR lpszShortPath, LPTSTR lpszLongPath, DWORD cchBuffer );
2 Invocación de plataforma -‐ PInvoke Por ejemplo, si tenemos esta declaración del API de Windows:
En C# la podríamos declarar de esta otra:
System.Runtime.InteropServices.DllImport("kernel32.dll")] private extern static int GetLongPathName( string lpszShortPath, StringBuilder lpszLongPath, int cchBuffer );
DWORD GetLongPathName( LPCTSTR lpszShortPath, LPTSTR lpszLongPath, DWORD cchBuffer );
2 Invocación de plataforma -‐ PInvoke Por ejemplo, si tenemos esta declaración del API de Windows:
indicamos que la función se encuentra en la librería “kernel32.dll”
En C# la podríamos declarar de esta otra:
System.Runtime.InteropServices.DllImport("kernel32.dll")] private extern static int GetLongPathName( string lpszShortPath, StringBuilder lpszLongPath, int cchBuffer );
DWORD GetLongPathName( LPCTSTR lpszShortPath, LPTSTR lpszLongPath, DWORD cchBuffer );
2 Invocación de plataforma -‐ PInvoke Por ejemplo, si tenemos esta declaración del API de Windows:
indicamos que la función se encuentra en la librería “kernel32.dll”
siempre debemos declarar los métodos como extern static
En C# la podríamos declarar de esta otra:
System.Runtime.InteropServices.DllImport("kernel32.dll")] private extern static int GetLongPathName( string lpszShortPath, StringBuilder lpszLongPath, int cchBuffer );
DWORD GetLongPathName( LPCTSTR lpszShortPath, LPTSTR lpszLongPath, DWORD cchBuffer );
2 Invocación de plataforma -‐ PInvoke Por ejemplo, si tenemos esta declaración del API de Windows:
indicamos que la función se encuentra en la librería “kernel32.dll”
siempre debemos declarar los métodos como extern static
Parámetros adecuados a los Lpos que .NET uLliza. Cuando el API espera una cadena, podemos declararla tanto usando el Lpo string como StringBuilder.
Servicios Windows Aplicaciones ejecutables de larga duración
Se ejecutan en sus propias sesiones de Windows.
Pueden iniciarse automá6camente cuando el equipo arranca.
Se pueden pausar y reiniciar.
No muestran ningún interfaz de usuario.
Servicios Windows Aplicaciones ejecutables de larga duración
Se ejecutan en sus propias sesiones de Windows.
Pueden iniciarse automá6camente cuando el equipo arranca.
Se pueden pausar y reiniciar.
No muestran ningún interfaz de usuario.
Servicios Windows Aplicaciones ejecutables de larga duración
Se ejecutan en sus propias sesiones de Windows.
Pueden iniciarse automá6camente cuando el equipo arranca.
Se pueden pausar y reiniciar.
No muestran ningún interfaz de usuario.
Servicios Windows Aplicaciones ejecutables de larga duración
Se ejecutan en sus propias sesiones de Windows.
Pueden iniciarse automá6camente cuando el equipo arranca.
Se pueden pausar y reiniciar.
No muestran ningún interfaz de usuario.
Servicios Windows Aplicaciones ejecutables de larga duración
Se ejecutan en sus propias sesiones de Windows.
Pueden iniciarse automá6camente cuando el equipo arranca.
Se pueden pausar y reiniciar.
No muestran ningún interfaz de usuario.
Perfectos para ejecutarse en un servidor o donde se necesite una funcionalidad de ejecución larga que no interfiera con los demás usuarios que trabajen en el mismo equipo.
Cómo crear un Servicio Windows Fase 1: creación del servicio
En Visual Studio, seleccionar la opción File -‐> New Project…
En la lista de planLllas C# seleccionar Windows Service, y nombrar el proyecto MyNewService. Al crear un servicio, podemos usar una planLlla de proyecto de Visual Studio denominada Servicio de Windows. Esta planLlla realiza automáLcamente gran parte del trabajo: hace referencia a las clases y los espacios de nombres correctos, configura la herencia de la clase base para los servicios y reemplaza algunos de los métodos que es probable que deseemos reemplazar.
En el menú Edit, elegimos Find and replace, Find in files (teclado: Ctrl+Mayús+F). Cambiamos todas las apariciones de Service1 por MyNewService. Encontraremos casos en Service1.cs, Program.cs y Service1.Designer.cs.
12
3
En la ventana Proper6es, establecemos las propiedades ServiceName y Name en MyNewService, si todavía no están establecidas.
4
En el explorador de soluciones (Solu6on Explorer), cambiamos el nombre de Service1.cs a MyNewService.cs.
5
Cómo crear un Servicio Windows Fase 2: agregar caracterís6cas al servicio
Establecemos cualquiera de las siguientes propiedades para determinar cómo funcionará el servicio.
Cómo crear un Servicio Windows Fase 2: agregar caracterís6cas al servicio
Para agregar caracterís6cas al servicio, veamos un ejemplo en donde vamos a agregar un registro de eventos personalizado al servicio Windows:
public MyNewService() { InitializeComponent(); if (!System.Diagnostics.EventLog.SourceExists("MySource")) { System.Diagnostics.EventLog.CreateEventSource("MySource", "MyNewLog"); } eventLog1.Source = "MySource"; eventLog1.Log = "MyNewLog"; }
1 Añadimos al constructor de MyNewService.cs un registro de eventos personalizado:
protected override void OnStart(string[] args) { eventLog1.WriteEntry("In OnStart"); }
2 En el método OnStart logueamos en el registro de eventos creado en el paso anterior el inicio del servicio:
Una aplicación de servicio está diseñada para ejecutarse de forma prolongada. Por lo tanto, normalmente sondea o supervisa algún elemento del sistema. La supervisión se puede establecer en el método OnStart. Sin embargo, OnStart no lleva a cabo realmente la supervisión. El método OnStart debe volver al sistema operaLvo después de que haya comenzado el funcionamiento del servicio. No debe bloquearse ni ejecutar un bucle infinito. Para establecer un mecanismo de sondeo sencillo, uLlice el componente System.Timers.Timer. En el método OnStart, debería establecer los parámetros en el componente y, a conLnuación, establecer la propiedad Enabled en true. El temporizador acLvaría entonces los eventos periódicamente en el código y, en esos instantes, el servicio podría realizar su control.
Añadimos un Timer al servicio para que la ejecución del mismo no termine inmediatamente:
public partial class MyNewService : ServiceBase { private System.Timers.Timer timer; public MyNewService() { ... this.timer = new System.Timers.Timer(); this.timer.Interval = 5000; this.timer.Elapsed += new ElapsedEventHandler(OnTimedEvent); this.timer.Enabled = true; this.timer.Start(); } }
private OnTimedEvent(object source, ElapsedEventArgs e) { eventLog1.WriteEntry("The Elapsed event was raised at {0}", e.SignalTime); }
protected override void OnStop() { this.timer.Enabled = false; }
protected override void OnStop() { ... eventLog1.WriteEntry("In OnStop"); }
3 En el método OnStop logueamos en el registro de eventos creado el parado del servicio:
Cómo crear un Servicio Windows Fase 3: configurar el estado del servicio
Los servicios informan de su estado al Administrador de control de servicios, para que los usuarios puedan saber si un servicio funciona correctamente. De manera predeterminada, los servicios que heredan de ServiceBase informan de un conjunto limitado de parámetros de estado, incluidos Detenido, En pausa y En ejecución. Si un servicio tarda un poco en iniciarse, puede ser úLl informar de un estado Inicio pendiente. También podemos implementar la configuración de estado Inicio pendiente y Detención pendiente si agregamos código que llama a la función SetServiceStatus de Windows.
Para implementar el estado pendiente del servicio, veamos un ejemplo:
Añadimos la instrucción using al espacio de nombres System.Runtime.InteropServices en el archivo MyNewService.cs.
1
Con6núa en la siguiente página…
Agregamos el código siguiente a MyNewService.cs para declarar los valores de ServiceState y agregamos una estructura (struct) para el estado, que se uLlizará en una llamada de a código no manejado mediante pInvoke:
2 public enum ServiceState { SERVICE_STOPPED = 0x00000001, SERVICE_START_PENDING = 0x00000002, SERVICE_STOP_PENDING = 0x00000003, SERVICE_RUNNING = 0x00000004, SERVICE_CONTINUE_PENDING = 0x00000005, SERVICE_PAUSE_PENDING = 0x00000006, SERVICE_PAUSED = 0x00000007, } [StructLayout(LayoutKind.Sequential)] public struct ServiceStatus { public long dwServiceType; public ServiceState dwCurrentState; public long dwControlsAccepted; public long dwWin32ExitCode; public long dwServiceSpecificExitCode; public long dwCheckPoint; public long dwWaitHint; };
En la clase MyNewService.cs, declaramos la función SetServiceStatus mediante pInvoke: 3 [DllImport(“advapi32.dll”, SetLastError=true)] private static extern bool SetServiceStatus(IntPtr handle, ref ServiceStatus serviceStatus);
Con6núa en la siguiente página…
Para implementar el estado Inicio pendiente, agregamos el siguiente código al principio del método OnStart: 4 // Update the service state to Start Pending. ServiceStatus serviceStatus = new ServiceStatus(); serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING; serviceStatus.dwWaitHint = 100000; SetServiceStatus(this.ServiceHandle, ref serviceStatus);
Agregamos el siguiente código para establecer el estado En ejecución al final del método OnStart: 5// Update the service state to Running. serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING; SetServiceStatus(this.ServiceHandle, ref serviceStatus);;
Cómo crear un Servicio Windows Fase 4: agregar instaladores al servicio
En Visual Studio, en el explorador de soluciones (Solu6on Explorer), abrir el menú contextual de MyNewService.cs y seleccionar Vista de Diseño (Design view).
Hacemos click en el fondo del diseñador para seleccionar el propio servicio, en vez de cualquier elemento de su contenido.
Abrir el menú contextual de la ventana del diseñador y a conLnuación elegimos Agregar instalador (Add installer).
123
Para poder ejecutar un servicio Windows, antes debemos instalarlo, el cuál será registrado por el Administrador de control de servicios. Podemos agregar instaladores al proyecto que controlen los detalles del registro.
De forma predeterminada, se agrega al proyecto una clase de componente que conLene dos instaladores. El componente se denomina ProjectInstaller, y los instaladores que conLene son el instalador para el servicio y el instalador para el proceso asociado al servicio.
En la vista Diseño de ProjectInstaller, elegimos serviceInstaller1. 4En la ventana Propiedades nos aseguramos de que la propiedad ServiceName esté establecida en MyNewService. 5
Con6núa en la siguiente página…
Establecemos texto en la propiedad Descripción, como "Servicio de ejemplo". Este texto aparece en la ventana Servicios y ayuda al usuario a idenLficar el servicio y comprender para qué se usa.
Establecemos la propiedad DisplayName en el texto que deseemos que aparezca en la ventana Servicios en la columna Nombre. Por ejemplo, podemos escribir "Nombre para mostrar de MyNewService”.
Establecemos la propiedad StartType en Automa6c.
6
7
8
Este nombre puede ser diferente de la propiedad ServiceName, que es el nombre usado por el sistema (por ejemplo, al usar el comando net start para iniciar el servicio).
En el diseñador, elegimos serviceProcessInstaller1 y establecemos la propiedad Account en LocalSystem. 9Esto hará que se instale el servicio y se ejecute con una cuenta de servicio local.
La cuenta LocalSystem Lene amplios permisos, incluida la capacidad para escribir en el registro de eventos. ULlice esta cuenta con precaución porque podría aumentar el riesgo de ataques por parte de soRware malintencionado. Para otras tareas, considere la posibilidad de usar la cuenta LocalService, que actúa como un usuario sin privilegios en el equipo local y presenta credenciales anónimas a cualquier servidor remoto. En este ejemplo se produce un error si intenta usar la cuenta LocalService, ya que necesita permiso de escritura en el registro de eventos.
Cómo crear un Servicio Windows Fase 5: establecer parámetros de inicio Un servicio de Windows, al igual que cualquier otro archivo ejecutable, puede aceptar argumentos de línea de comandos o parámetros de inicio.
En el método Main de Program.cs agregamos un argumento para la línea de comandos: 1static void Main(string[] args) {
ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new MyNewService(args) }; ServiceBase.Run(ServicesToRun);
}
Con6núa en la siguiente página…
Modificamos el constructor MyNewService de la siguiente forma: 2
public MyNewService(string[] args) { InitializeComponent(); string eventSourceName = "MySource"; string logName = "MyNewLog"; if (args.Count() > 0) { eventSourceName = args[0]; } if (args.Count() > 1) { logName = args[1]; } eventLog1 = new System.Diagnostics.EventLog(); if (!System.Diagnostics.EventLog.SourceExists(eventSourceName)) { System.Diagnostics.EventLog.CreateEventSource(eventSourceName, logName); } eventLog1.Source = eventSourceName; eventLog1.Log = logName; }
Este código establece el nombre de registro y el origen de eventos según los parámetros de inicio proporcionados, o bien, usa los valores predeterminados si no se proporcionan argumentos.
Para especificar los argumentos de línea de comandos, agregamos el código siguiente a la clase ProjectInstaller en ProjectInstaller.cs:
3protected override void OnBeforeInstall(IDictionary savedState) { string parameter = "MySource1\" \"MyLogFile1”; Context.Parameters["assemblypath"] = "\"" + Context.Parameters["assemblypath"] + "\" \"" + parameter + "\""; base.OnBeforeInstall(savedState); }
Cómo crear un Servicio Windows Fase 6: compilar el servicio
En el explorador de soluciones (Solu6on Explorer), abrimos el menú contextual del proyecto y, a conLnuación, elegimos Proper6es.
1
En la pestaña Applica6on, en la lista objeto de inicio, elegimos MyNewService.Program. 2
En el explorador de soluciones (Solu6on Explorer), abrimos el menú contextual del proyecto y, a conLnuación, elegimos Build para compilar el proyecto (teclado: Ctrl+Mayús+B).
3
Cómo crear un Servicio Windows Fase 7: instalar el servicio
En Windows 7 y Windows Server, abrimos la línea de comandos para desarrolladores en Visual Studio Tools en el menú Inicio. En Windows 8 o Windows 8.1, elegimos el icono de Visual Studio Tools en la pantalla Inicio y ejecutamos la línea de comandos para desarrolladores con credenciales administraLvas.
1
Ahora que ha compilado el servicio Windows, podemos instalarlo. Para instalar un servicio de Windows, debemos tener credenciales administraLvas en el equipo en el que lo vamos a instalar.
En la ventana de símbolo del sistema, nos desplazamos hasta la carpeta que con6ene la salida del proyecto. Por ejemplo, en la carpeta Mis documentos, nos desplazamos hasta Visual Studio 2013\Projects\MyNewService\bin\Debug.
2
Escribimos el siguiente comando: 3installutil.exe MyNewService.exe
Cómo crear un Servicio Windows Fase 8: iniciar y ejecutar el servicio
En Windows, abrimos la pantalla Inicio o el menú Inicio y escribimos services.msc. 1En la ventana Servicios, abrimos el menú contextual del servicio y, a conLnuación, seleccionamos Iniciar.
2Abrimos el menú contextual del servicio y, a conLnuación, elegimos Detener. 3
Para comprobar si el servicio se ha ejecutado correctamente, podemos ir al visor de eventos de Windows y ver si se ha generado el fichero de log MyLogFile1. En él deberíamos ver las 2 acciones (iniciar y detener) que ha realizado el servicio.
Aplicaciones cliente Qué son?
Las aplicaciones cliente, como un navegador web o una aplicación de escritorio, se ejecutan en el ordenador o estación de trabajo local de un usuario y se conectan a un servidor cuando lo requieren.
Cómo crear un Servicio Web Implementación de un servicio WCF
En Visual Studio, seleccionar la opción File -‐> New Project…
En la lista de planLllas C# seleccionar Class Library, y nombrar el proyecto WCFService.
Crear 2 clases: IMathService.cs y MathService.cs
123
Decorar el interfaz IMathService con el atributo [ServiceContract] 4El atributo ServiceContract indica que un interfaz o una clase define un contrato de servicio en una aplicación Windows CommunicaLon FoundaLon (WCF).
[ServiceContract] public interface IMathService { }
Cómo crear un Servicio Web Implementación de un servicio WCF
public int Sum(int a, int b);
Declarar los métodos a publicar en el servicio WCF en el interfaz IMathService. 5En nuestro ejemplo, definiremos solamente un método que realizará la operación de suma.
[OperationContract] public int Sum(int a, int b);
Decorar los métodos declarados en el interfaz IMathService con el atributo [OperationContract]. 6Debemos decorar con el atributo OperationContract aquellos métodos que deseemos sean públicos en el servicio WCF. Puede interesar que todos los métodos de un interfaz no sean publicados en el servicio y por tanto no necesitaríamos decorarlos con OperationContract.
Implementar en la clase MathService.cs el método Sum definido en el interfaz IMathService. 7Hospedar y ejecutar un servicio WCF 8En nuestro ejemplo, vamos a hospedar el servicio WCF en una aplicación de Consola. Veamos la siguiente documentación:
hsps://msdn.microsoR.com/es-‐es/library/ms730935(v=vs.110).aspx
class Program { static void Main(string[] args) { // Step 1 Create a URI to serve as the base address. Uri baseAddress = new Uri("http://localhost:8000/GettingStarted/"); // Step 2 Create a ServiceHost instance ServiceHost selfHost = new ServiceHost(typeof(MathService), baseAddress); try { // Step 3 Add a service endpoint. selfHost.AddServiceEndpoint(typeof(IMathService), new WSHttpBinding(), "MathService"); // Step 4 Enable metadata exchange. ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); smb.HttpGetEnabled = true; selfHost.Description.Behaviors.Add(smb); // Step 5 Start the service. selfHost.Open(); Console.WriteLine("The service is ready."); Console.WriteLine("Press <ENTER> to terminate service."); Console.WriteLine(); Console.ReadLine(); // Close the ServiceHostBase to shutdown the service. selfHost.Close(); } catch (CommunicationException ce) { Console.WriteLine("An exception occurred: {0}", ce.Message); selfHost.Abort(); } } }
class Program { static void Main(string[] args) { // Step 1 Create a URI to serve as the base address. Uri baseAddress = new Uri("http://localhost:8000/GettingStarted/"); // Step 2 Create a ServiceHost instance ServiceHost selfHost = new ServiceHost(typeof(MathService), baseAddress); try { // Step 3 Add a service endpoint. selfHost.AddServiceEndpoint(typeof(IMathService), new WSHttpBinding(), "MathService"); // Step 4 Enable metadata exchange. ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); smb.HttpGetEnabled = true; selfHost.Description.Behaviors.Add(smb); // Step 5 Start the service. selfHost.Open(); Console.WriteLine("The service is ready."); Console.WriteLine("Press <ENTER> to terminate service."); Console.WriteLine(); Console.ReadLine(); // Close the ServiceHostBase to shutdown the service. selfHost.Close(); } catch (CommunicationException ce) { Console.WriteLine("An exception occurred: {0}", ce.Message); selfHost.Abort(); } } }
Los servicios se idenLfican mediante una dirección URL que conLene una dirección base y una URI opcional. La dirección base para nuestro servicio usa el transporte HTTP, localhost, el puerto 8000 y el segmento de URI “Ge�ngStarted”.
class Program { static void Main(string[] args) { // Step 1 Create a URI to serve as the base address. Uri baseAddress = new Uri("http://localhost:8000/GettingStarted/"); // Step 2 Create a ServiceHost instance ServiceHost selfHost = new ServiceHost(typeof(MathService), baseAddress); try { // Step 3 Add a service endpoint. selfHost.AddServiceEndpoint(typeof(IMathService), new WSHttpBinding(), "MathService"); // Step 4 Enable metadata exchange. ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); smb.HttpGetEnabled = true; selfHost.Description.Behaviors.Add(smb); // Step 5 Start the service. selfHost.Open(); Console.WriteLine("The service is ready."); Console.WriteLine("Press <ENTER> to terminate service."); Console.WriteLine(); Console.ReadLine(); // Close the ServiceHostBase to shutdown the service. selfHost.Close(); } catch (CommunicationException ce) { Console.WriteLine("An exception occurred: {0}", ce.Message); selfHost.Abort(); } } }
Los servicios se idenLfican mediante una dirección URL que conLene una dirección base y una URI opcional. La dirección base para nuestro servicio usa el transporte HTTP, localhost, el puerto 8000 y el segmento de URI “Ge�ngStarted”.
Crear una instancia de la clase ServiceHost para hospedar el servicio.
class Program { static void Main(string[] args) { // Step 1 Create a URI to serve as the base address. Uri baseAddress = new Uri("http://localhost:8000/GettingStarted/"); // Step 2 Create a ServiceHost instance ServiceHost selfHost = new ServiceHost(typeof(MathService), baseAddress); try { // Step 3 Add a service endpoint. selfHost.AddServiceEndpoint(typeof(IMathService), new WSHttpBinding(), "MathService"); // Step 4 Enable metadata exchange. ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); smb.HttpGetEnabled = true; selfHost.Description.Behaviors.Add(smb); // Step 5 Start the service. selfHost.Open(); Console.WriteLine("The service is ready."); Console.WriteLine("Press <ENTER> to terminate service."); Console.WriteLine(); Console.ReadLine(); // Close the ServiceHostBase to shutdown the service. selfHost.Close(); } catch (CommunicationException ce) { Console.WriteLine("An exception occurred: {0}", ce.Message); selfHost.Abort(); } } }
Los servicios se idenLfican mediante una dirección URL que conLene una dirección base y una URI opcional. La dirección base para nuestro servicio usa el transporte HTTP, localhost, el puerto 8000 y el segmento de URI “Ge�ngStarted”.
Crear una instancia de la clase ServiceHost para hospedar el servicio.
Crear una nueva instancia de ServiceEndpoint.Un extremo de servicio consta de una dirección, un enlace y un contrato de servicio. Por tanto, el constructor ServiceEndpoint toma el Lpo de interfaz del contrato de servicio, un enlace y una dirección. El contrato de servicio es IMathService. El enlace uLlizado en este ejemplo es WSHspBinding, que es un enlace integrado que se emplea para conectarse a extremos que son conformes a las especificaciones de WS-‐*. La dirección se anexa a la dirección base para idenLficar el extremo.La dirección especificada en este código es “Calculator”, por lo que la dirección completa del extremo es “hsp://localhost:8000/Ge�ngStartedService/Calculator”
class Program { static void Main(string[] args) { // Step 1 Create a URI to serve as the base address. Uri baseAddress = new Uri("http://localhost:8000/GettingStarted/"); // Step 2 Create a ServiceHost instance ServiceHost selfHost = new ServiceHost(typeof(MathService), baseAddress); try { // Step 3 Add a service endpoint. selfHost.AddServiceEndpoint(typeof(IMathService), new WSHttpBinding(), "MathService"); // Step 4 Enable metadata exchange. ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); smb.HttpGetEnabled = true; selfHost.Description.Behaviors.Add(smb); // Step 5 Start the service. selfHost.Open(); Console.WriteLine("The service is ready."); Console.WriteLine("Press <ENTER> to terminate service."); Console.WriteLine(); Console.ReadLine(); // Close the ServiceHostBase to shutdown the service. selfHost.Close(); } catch (CommunicationException ce) { Console.WriteLine("An exception occurred: {0}", ce.Message); selfHost.Abort(); } } }
Los servicios se idenLfican mediante una dirección URL que conLene una dirección base y una URI opcional. La dirección base para nuestro servicio usa el transporte HTTP, localhost, el puerto 8000 y el segmento de URI “Ge�ngStarted”.
Crear una instancia de la clase ServiceHost para hospedar el servicio.
Crear una nueva instancia de ServiceEndpoint.Un extremo de servicio consta de una dirección, un enlace y un contrato de servicio. Por tanto, el constructor ServiceEndpoint toma el Lpo de interfaz del contrato de servicio, un enlace y una dirección. El contrato de servicio es IMathService. El enlace uLlizado en este ejemplo es WSHspBinding, que es un enlace integrado que se emplea para conectarse a extremos que son conformes a las especificaciones de WS-‐*. La dirección se anexa a la dirección base para idenLficar el extremo.La dirección especificada en este código es “Calculator”, por lo que la dirección completa del extremo es “hsp://localhost:8000/Ge�ngStartedService/Calculator”
Habilitar el intercambio de metadatos para poder generar los proxies en las aplicaciones cliente.
class Program { static void Main(string[] args) { // Step 1 Create a URI to serve as the base address. Uri baseAddress = new Uri("http://localhost:8000/GettingStarted/"); // Step 2 Create a ServiceHost instance ServiceHost selfHost = new ServiceHost(typeof(MathService), baseAddress); try { // Step 3 Add a service endpoint. selfHost.AddServiceEndpoint(typeof(IMathService), new WSHttpBinding(), "MathService"); // Step 4 Enable metadata exchange. ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); smb.HttpGetEnabled = true; selfHost.Description.Behaviors.Add(smb); // Step 5 Start the service. selfHost.Open(); Console.WriteLine("The service is ready."); Console.WriteLine("Press <ENTER> to terminate service."); Console.WriteLine(); Console.ReadLine(); // Close the ServiceHostBase to shutdown the service. selfHost.Close(); } catch (CommunicationException ce) { Console.WriteLine("An exception occurred: {0}", ce.Message); selfHost.Abort(); } } }
Los servicios se idenLfican mediante una dirección URL que conLene una dirección base y una URI opcional. La dirección base para nuestro servicio usa el transporte HTTP, localhost, el puerto 8000 y el segmento de URI “Ge�ngStarted”.
Crear una instancia de la clase ServiceHost para hospedar el servicio.
Crear una nueva instancia de ServiceEndpoint.Un extremo de servicio consta de una dirección, un enlace y un contrato de servicio. Por tanto, el constructor ServiceEndpoint toma el Lpo de interfaz del contrato de servicio, un enlace y una dirección. El contrato de servicio es IMathService. El enlace uLlizado en este ejemplo es WSHspBinding, que es un enlace integrado que se emplea para conectarse a extremos que son conformes a las especificaciones de WS-‐*. La dirección se anexa a la dirección base para idenLficar el extremo.La dirección especificada en este código es “Calculator”, por lo que la dirección completa del extremo es “hsp://localhost:8000/Ge�ngStartedService/Calculator”
Habilitar el intercambio de metadatos para poder generar los proxies en las aplicaciones cliente.
Abrir ServiceHost para escuchar los mensajes entrantes
Cómo consumir un Servicio Web Implementación de una aplicación cliente Windows Forms
En Visual Studio, seleccionar la opción File -‐> New Project…
En la lista de planLllas C# seleccionar Applica6on Windows Forms, y nombrar el proyecto por WCFServiceConsumer.UI.WinForms.
Añadir un 1 botón y 2 controles de Lpo numeric up down.
123
Añadir una referencia al servicio web publicado anteriormente. 4En el menú contextual del proyecto WebServiceConsumer.UI.WinForms seleccionar Add Service Reference… y escribir la url http://localhost:8000/GettingStarted/.
Invocar al servicio web haciendo uso del proxy creado por Visual Studio en el paso anterior. 5Al pulsar el botón debemos invocar al método Sum del servicio web.
Otros puntos de interés Herramientas de profiling, gesLón de librerías mediante Nuget, librerías para
logging, etc.
MicrosoR dispone de un conjunto de librerías que facilitan el desarrollo de aplicaciones empresariales en .NET. Implementan funcionalidad que �picamente debe incorporarse a las aplicaciones empresariales.
Librerías que facilitan el desarrollo del día a día
Microso| Enterprise Library Está desarrollada por el equipo Paserns & PracLces de MicrosoR. Este equipo Lene como misión entregar orientación sobre las mejores pracLcas para el desarrollo de aplicaciones empresariales en .NET.
Nos permiten instalar y actualizar librerías y herramientas en Visual Studio de forma sencilla. Gestores de paquetes
Nuget Es una extensión de Visual Studio que permite la administración, de una forma muy sencilla, de las referencias a otras librerías. Del mismo modo que se pueden agregar o quitar referencias, Nuget es capaz de detectar si existen nuevas versiones en el repositorio y descargar la nueva versión previa aceptación del usuario.
El objeLvo es averiguar el Lempo dedicado a la ejecución de diferentes partes del programa para detectar los puntos problemáLcos y las áreas dónde sea posible llevar a cabo una opLmización del rendimiento (ya sea en velocidad o en consumo de recursos).
Análisis de rendimiento de so|ware
ANTS Performance Profiler Profile and boost the performance of your .NET applicaLons
ANTS Memory Profiler Profile .NET applicaLon memory usage
Permiten que nuestra aplicación muestre mensajes de información de lo que está sucediendo en ella, lo que habitualmente se conoce como un log. Tienen la ventaja de ser dinámicas y, por tanto, configurables.
Librerías para logging
Apache log4net Tool to help the programmer output log statements to a variety of output targets
Referencias u6lizadas en este curso
Head First C#, 3rd edi6on by Jennifer Greene, Andrew
Stellman
Design Pa}erns by Erich Gamma, Richard Helm, Ralph Johson, John Vlissides
Framework Design Guidelines by Krzysztof Cwalina, Brad Abrams