Manual C Sharp
Manual C Sharp
MANUAL C#
Ismael Galan Cazares
Orbith
03/10/2010
Ismael Galan Cazares
Contenido
¿Qué es C#? ............................................................................................................................... 8
Lenguaje Orientado a Objetos ............................................................................................. 9
Objeto ................................................................................................................................... 9
Herencia............................................................................................................................... 9
Clase .................................................................................................................................. 10
Funciones Miembro.......................................................................................................... 10
Campos Estáticos ............................................................................................................ 10
Clase Base ........................................................................................................................ 11
Clase Derivada ................................................................................................................. 11
Clase Abstracta ................................................................................................................ 11
Clase Sealed ..................................................................................................................... 12
Overloading/Sobrecarga ................................................................................................. 12
Herencia Simple ............................................................................................................... 12
Polimorfismo y Funciones Virtuales .............................................................................. 14
Encapsulación y Visibilidad ............................................................................................ 15
Abstracción ........................................................................................................................ 16
Plataforma .NET ....................................................................................................................... 16
.NET Common Language Runtime - CLR ........................................................................ 17
Ambiente/Entorno de Ejecución ......................................................................................... 19
Ensamblaje ............................................................................................................................ 20
Interoperabilidad de Lenguaje ............................................................................................ 20
Atributos ............................................................................................................................. 20
Biblioteca de Clases de la Plataforma .NET .................................................................... 21
Requerimientos de Software .......................................................................................... 21
Lenguaje Intermedio y Metadatos ................................................................................. 22
JITers ..................................................................................................................................... 22
Sistema de Tipo Unificado .................................................................................................. 23
El Sistema Virtual de Objetos - VOS ................................................................................. 23
VOS Type System ................................................................................................................ 24
Metadata ................................................................................................................................ 24
Ismael Galan Cazares
Seguridad .............................................................................................................................. 25
Deployment ........................................................................................................................... 25
Interoperabilidad con código no administrado ..................................................................... 25
Common Language Specification - CLS............................................................................... 25
Virtual Execution System - VES ............................................................................................. 26
Tipos de Datos .......................................................................................................................... 26
Constantes y Campos Solo Lectura .................................................................................. 27
Ejemplo Hello World! ........................................................................................................... 28
Ejemplo Args ......................................................................................................................... 28
Ejemplo Input/Output ........................................................................................................... 30
Ejemplo String Format ......................................................................................................... 30
Función Main ......................................................................................................................... 31
Múltiples Funciones Main........................................................................................................ 31
Preprocesamiento ................................................................................................................ 32
Comentarios ...................................................................................................................... 33
Value Types ...................................................................................................................... 33
Tipos Simples ....................................................................................................................... 33
Integral ................................................................................................................................... 33
Bool......................................................................................................................................... 34
Char ........................................................................................................................................ 34
Floating Point ........................................................................................................................ 34
Tipos Estructura.................................................................................................................... 35
Tipos Enumeración .............................................................................................................. 35
Tipos Base............................................................................................................................. 36
Tipos Referencia .................................................................................................................. 37
Tipo Objeto ............................................................................................................................ 37
Tipo Clase ............................................................................................................................. 37
Interfaces ........................................................................................................................... 37
Delegados.......................................................................................................................... 38
Tipo string .............................................................................................................................. 39
Arreglos .................................................................................................................................. 41
Arreglos Multidimensionales ............................................................................................... 42
Arreglo de Arreglos .............................................................................................................. 43
Ismael Galan Cazares
Arreglos de Objetos ............................................................................................................. 43
Conversión de Arreglos ....................................................................................................... 44
Clase Array ............................................................................................................................ 44
Interface IComparable ......................................................................................................... 45
Interface IComparer ............................................................................................................. 46
IComparer Como Propiedad ............................................................................................... 48
Expresiones Regulares ....................................................................................................... 49
Operador as .......................................................................................................................... 49
Secuencias de Escape ........................................................................................................ 49
Boxing ................................................................................................................................ 50
Conversiones Boxing ....................................................................................................... 50
Conversiones Unboxing ...................................................................................................... 51
Constructores y Destructores ............................................................................................. 51
Constructor Estático............................................................................................................. 53
Métodos ................................................................................................................................. 54
Parámetros ............................................................................................................................ 54
Valores en Parámetros in.................................................................................................... 54
Valores en Parámetros ref .................................................................................................. 55
Valores en Parámetros out ................................................................................................. 57
Ejemplo de Parámetros In, Ref y Out ........................................................................... 57
Redefinición de Métodos (Overriding)........................................................................... 58
Ocultamiento de Métodos (Hiding) ................................................................................ 59
Propiedades .......................................................................................................................... 60
Accessors .............................................................................................................................. 62
Propiedades Estáticas ......................................................................................................... 62
Índices .................................................................................................................................... 63
Eventos .................................................................................................................................. 64
Modificadores ............................................................................................................................ 65
Modificadores de Clase ....................................................................................................... 65
Modificadores Miembro ....................................................................................................... 65
Modificadores de Acceso .................................................................................................... 66
Sentencias de Control ......................................................................................................... 67
Sentencias de Selección ..................................................................................................... 67
Ismael Galan Cazares
Sentencia if ............................................................................................................................ 67
Sentencia switch................................................................................................................... 69
Sentencias de Iteración (repetición) .................................................................................. 71
Sentencia for ......................................................................................................................... 71
Sentencia foreach ................................................................................................................ 72
Sentencia while ..................................................................................................................... 73
Sentencia do ......................................................................................................................... 74
Sentencias de Salto ............................................................................................................. 74
Asignación Definitiva............................................................................................................ 75
Precedencia de Operadores ............................................................................................... 75
typeof .................................................................................................................................. 75
is .......................................................................................................................................... 76
Conversiones .................................................................................................................... 76
Manejo de Excepciones .................................................................................................. 76
Jerarquía de Excepciones .............................................................................................. 77
Trabajar con Excepciones ...................................................................................................... 78
Caller Beware ....................................................................................................................... 78
Caller Confuse ...................................................................................................................... 78
Caller Inform .......................................................................................................................... 78
Chequeo de Overflow .......................................................................................................... 78
Chequeo programático de Overflow.................................................................................. 79
Sentencias para el Manejo de Excepciones .................................................................... 79
try - catch ........................................................................................................................... 79
try - finally .......................................................................................................................... 80
try - catch - finally ............................................................................................................. 81
Lanzamiento de Excepciones ............................................................................................ 82
Relanzamiento de Excepciones ......................................................................................... 83
Creación de Clases Exception ........................................................................................... 83
Componentes ........................................................................................................................ 84
Creación de Componentes ................................................................................................. 84
Compilación de Componentes ........................................................................................... 85
Creación de una Aplicación Cliente............................................................................... 85
Compilación de Clientes.................................................................................................. 85
Ismael Galan Cazares
Namespaces ......................................................................................................................... 86
Envolver Clases en Namespace ........................................................................................ 86
Utilizar Namespace en Aplicaciones Cliente ................................................................... 87
Agregar Múltiples Clases a Un Namespace .................................................................... 88
Namespace y Ensambles ................................................................................................... 90
Uso del Preprocesador ........................................................................................................ 90
Definición de símbolos .................................................................................................... 90
Exclusión de código basado en símbolos .................................................................... 91
Lanzamiento de errores y advertencias ........................................................................ 92
Atributo conditional............................................................................................................... 92
Comentarios de Documentación en XML ......................................................................... 92
Elementos XML ................................................................................................................ 92
Componentes .NET.................................................................................................................. 95
Componentes .NET Privados ............................................................................................. 95
Componentes .NET Compartidos ...................................................................................... 95
Uso de Componentes .NET en Componentes COM ...................................................... 95
Uso de Componentes COM en Componentes .NET ...................................................... 97
Invocación de Servicios ....................................................................................................... 97
Código No Seguro ................................................................................................................ 97
Debugging ............................................................................................................................. 97
Seguridad .............................................................................................................................. 98
Seguridad de acceso al código .......................................................................................... 99
Permisos Estándar ............................................................................................................... 99
Permisos Identidad ............................................................................................................ 100
Seguridad basada en roles ............................................................................................... 100
Función ToString().............................................................................................................. 101
Función Equals() ................................................................................................................ 102
Clase Hashtable ................................................................................................................. 104
Interface IHashCodeProvider ........................................................................................... 104
Función IClonable .............................................................................................................. 105
Interface ICloneable ....................................................................................................... 106
Formato Numérico.............................................................................................................. 107
Formato Estándar String ................................................................................................... 107
Ismael Galan Cazares
Formato Personalizado String .......................................................................................... 108
Reemplazo de Cero o Digito ........................................................................................ 108
Reemplazo de Espacio o Digito ................................................................................... 108
Punto Decimal................................................................................................................. 108
Separador de Grupo ...................................................................................................... 108
Separador de Grupo ...................................................................................................... 108
Porcentaje........................................................................................................................ 108
Notación Exponencial .................................................................................................... 108
Separador de Sección ................................................................................................... 108
Escape y Literales .......................................................................................................... 108
Parseo Numérico ............................................................................................................ 108
Input/Output......................................................................................................................... 108
Lectura y Escritura de Archivos ....................................................................................... 109
Serialización ........................................................................................................................ 109
Threading (Hilos) ................................................................................................................ 110
Ismael Galan Cazares
¿Qué es C#?
Objeto
Un Objeto es una instancia de un tipo de clase.
La instanciación es el acto de crear una instancia de un objeto, la instancia es un objeto,
la instanciación usa el operador new, después la instanciación es posible comunicarnos con
el objeto a través de sus miembros.
Un Objeto es una colección de información relacionada y funcional.
Un objeto se compone de:
Datos que describen el objeto y
Operaciones que pueden ser realizadas por el objeto
Herencia
La Herencia es la habilidad para heredar datos y funcionalidad de un objeto padre, la herencia
es una característica fundamental de un sistema orientado a objetos.
A través de la herencia es posible crear o derivar una nueva clase basada en una clase
existente.
Una clase derivada es la nueva clase que esta siendo creada y la clase base es una de las
cuales la nueva clase es derivada. La nueva clase derivada hereda todos los miembros de la
clase base por consiguiente permite reusar el trabajo previo.
En C# se puede asumir que la clase derivada podría heredar todos los miembros de la clase
base.
La herencia es un ejemplo del diseño orientado a objetos conocido como una relación "is-a"
(es-un), por ejemplo:
"un empleado es una persona".
Al utilizar la herencia la clase base necesita ser diseñada teniendo en mente la herencia, si
los objetos no tienen la estructura apropiada la herencia no podría funcionar correctamente.
Una clase derivada no debería requerir más ni prometer menos que su clase base sobre
cualquiera de sus interfaces heredadas.
Ismael Galan Cazares
Una interfaz de clase es un contrato entre esta y los programadores que usan la clase.
upcasting, cuando un programador tiene una referencia a la clase derivada, el programador
siempre puede tratar a esa clase como si fuera la clase base.
En el lenguaje común en tiempo de ejecución .NET todos los objetos heredan de la última
clase base llamada object y existe sólo una herencia simple de objetos.
Un objeto puede derivar sólo de una clase base.
Clase
Una Clase es una plantilla para un objeto.
Una Clase define las operaciones que un objeto puede realizar y define un valor que
mantiene el estado del objeto, los componentes principales de una clase son: métodos,
eventos y propiedades.
Una instancia de una clase es un objeto, se accede a la funcionalidad de un objeto invocando
sus métodos y accediendo a sus propiedades, eventos y campos.
Una clase utiliza modificadores para especificar la accesibilidad de la clase y sus
componentes, los componentes de una clase son llamados miembros por lo que existen
diferentes tipos de miembros. Una referencia se refiere a una instancia, una instancia es la
creación de un objeto del tipo clase que se está declarando. Una clase utiliza ninguno, uno o
más constructores para ayudar a definir la instancia de una clase. Existe una palabra
reservada llamada thisque sirve para hacer referencia a la clase actual en el ámbito en el cual
es utilizada. Cuando se hace referencia a una variable de instancia que tiene el mismo
nombre de un parámetro se debe utilizar this.name.
Al crear y manipular objetos no es necesario administrar la memoria que estos ocupan ya que
existe un mecanismo que se encarga de esto llamado garbage collector (recolector de
basura), pero es una buena práctica no olvidar liberar los recursos.
Funciones Miembro
Una Función Miembro puede ser un constructor, es decir, una pieza de código que es
invocada en una instancia del objeto.
Campos Estáticos
Un Miembro Estático definine miembros de un objeto que no son asociados con una instancia
de clase específica.
Un Campo Estático es el tipo más simple de un miembro estático, para declarar un campo
estático se utiliza el modificador static.
Un campo estático puede accederse a través del nombre de la clase, en vez de la instancia
de la clase (objeto):
using System;
class MiContador{
//Campo Estático
public static int iContador = 0;
public MiContador(){
iContador++;
}
}
Ismael Galan Cazares
class App{
public static void Main(){
MiContador ContadorA = new MiContador();
Console.WriteLine(MiContador.iContador);
MiContador ContadorB = new MiContador();
Console.WriteLine(MiContador.iContador);
}
}
El ejemplo determina cuantas instancias del objeto han sido creadas.
Clase Base
Una Clase base es un objeto padre de donde se basa un nuevo trabajo.
Clase Derivada
Una Clase derivada es un objeto hijo.
Clase Abstracta
Una Clase Abstracta define las funciones que una clase derivada debe implementar.
Una Clase Abstracta define un contrato en donde las clases derivadas deben definir las
funciones que la clase padre marca utilizando la palabra reservada abstract, además que la
clase padre también se define como abstract.
using System;
abstract public class Persona{//Indica que la clase es abstracta
//Propiedades
public string sNombre;
public int iEdad;
//Constructor
public Persona(string sNombre, int iEdad){
this.sNombre = sNombre;
this.iEdad = iEdad;
}
//Métodos
abstract public string Tipo();//Método que la clase derivada debe implementar
}
//Herencia Simple
public class Empleado : Persona{
public Empleado(string sNombre, int iEdad):base(sNombre, iEdad){}
override public string Tipo(){
return "Empleado";
}
}
class App{
//Aplicación
public static void Main(){
Console.WriteLine("--- Arreglo de Objetos ---");
Clase Sealed
Una Clase sealed se utiliza para prevenir que una clase sea utilizada como una clase base,
su principal uso es para prevenir la derivación no planeada.
sealed class ClaseBase{
ClaseBase(){}
}
class ClaseDerivada : ClaseBase{
}
class Sellada{
public static void Main(){
ClaseDerivada CD = new ClaseDerivada();
}
}
Al compilar el código se muestra el siguiente mensaje:
class App{
//Aplicación
public static void Main(){
Persona Mexicano = new Persona("Gerado Ángeles Nava", 33);
Console.WriteLine("Mexicano.sNombre : " + Mexicano.sNombre);
Console.WriteLine("Mexicano.iEdad : " + Mexicano.iEdad);
double dSueldo = 123.456;
Mexicano.AsignarSueldo(dSueldo);
Console.WriteLine("Mexicano.iSueldo : " +
Mexicano.ObtenerSueldo());
Ismael Galan Cazares
Console.WriteLine("Mexicano.Tipo : " + Mexicano.Tipo());
class App{
//Aplicación
public static void Main(){
Persona Mexicano = new Persona("Gerado Ángeles Nava", 33);
Console.WriteLine("Mexicano.sNombre : " + Mexicano.sNombre);
Console.WriteLine("Mexicano.iEdad : " + Mexicano.iEdad);
Console.WriteLine("Mexicano.Tipo : " + Mexicano.Tipo());
Plataforma .NET
Ambiente/Entorno de Ejecución
El ambiente o entorno provee un modelo de programación simple, seguro, soporta de
herramientas potentes y ayuda con la distribución, empaquetado y soporte:
Modelo de Programación Simple, todos los servicios son ofrecidos a través de un modelo
común que puede ser accedido desde cualquier lenguaje .NET y los servicios pueden ser
escritos en cualquier lenguaje .NET, el entorno o ambiente en gran parte es un lenguaje
agnóstico permitiendo la elección de lenguaje, esto hace el código fácil de reusar para el
programador y los proveedores de bibliotecas.
En el runtime .NET todos los errores son reportados via excepciones.
El entorno contiene las Bibliotecas de Clase Base (Base Class Libraries - BCL) las cuales
proveen las funciones tradicionales fundadas en bibliotecas en tiempo de ejecución, la
funcionalidad del BCL incluye:
Clases colección, tales como consultas, arreglos, pilas y tablas hash.
Clases de acceso a bases de datos
Clases IO (input-output)
Clases WinForms, para crear interfaces de usuario
Clases Network
Fuera de la clase base en tiempo de ejecución, existen muchos otros componentes que
controlan la interfaz de usuario (UI) y realizan otras operaciones sofisticadas.
Seguridad, el entorno del runtime .NET está diseñado para ser un entorno seguro. El runtime
.NET es un entorno administrado o controlado, lo cual significa que el runtime administra la
memoria por el programador a través del recolector de basura.
El runtime .NET es un entorno verificado, en tiempo de ejecución el entorno verifica que la
ejecución del código sea de tipo segura (type-safe).
El sistema de seguridad interactua con el verificador para asegurar que el código realice sólo
lo que tiene permitido hacer, esto es posible especificando un requerimiento de seguridad
para una pieza de código específica.
Soporte de herramientas potentes, Microsoft suministra cuatro lenguajes .NET: VB, VC++, C#
y JScript. La depuración en gran medida es enriquecida por el runtime .NET, el modelo de
ejecución común hace la depuración de lenguajes simple y directa.
Distribución, empaquetado y soporte, El runtime .NET ayuda simplificando la distribución y en
algunos casos no existe el paso tradicional de instalación, porque los paquetes son
distribuidos en un formato genérico, un paquete puede correr en cualquier entorno que
Ismael Galan Cazares
soporte .NET, el entorno separa los componentes de una aplicación por lo que una aplicación
sólo corre con los componentes que son enviados.
Ensamblaje
En el runtime .NET el mecanismo de empaquetado es el ensamble (assembly), cuando el
código es compilado por uno de los compiladores .NET, es convertido a una forma intermedia
conocida como IL.
El ensamble contiene todos los IL, metadatos y otros archivos requeridos para que un
paquete se ejecute en un paquete completo.
Cada ensamble contiene un manifiesto que enumera todos los archivos que están contenidos
en el ensamble, controla que tipos y recursos son expuestos fuera del ensamble y relaciona
las referencias de esos tipos y recursos a los archivos que contienen los tipos y recursos.
El manifiesto también lista otros ensambles que dependen de un ensamble.
Los ensambles se contienen a sí mismo, existe suficiente información en el ensamble para
ser auto-descrito.
Cuando se define un ensamble, el ensamble puede ser contenido en un solo archivo o puede
ser dividido entre varios archivos. Utilizando varios archivos podría hacer posible un escenario
donde las secciones del ensamble sean descargadas sólo como se necesiten.
Interoperabilidad de Lenguaje
Una de las metas del runtime .NET es ser un lenguaje agnóstico, permitiendo que el código
sea utilizado y escrito desde cualquier lenguaje, no sólo las clases pueden ser escritas en
algún lenguaje .NET como VB.NET y ser invocadas desde otro lenguaje .NET como C#, una
clase que fué escrita en VB.NET puede ser utilizada como una clase base escrita en C# y esa
clase podría ser utilizada desde una clase VC++ o JScript, es decir, no importaria en que
clase sea escrita una clase.
Para hacer lo anterior posible existen algunos obstaculos como las propias características del
lenguaje, ya que un lenguaje no podría soportar ciertas cosas que otro si las soporte, por
ejemplo la sobrecarga de operadores.
Para que una clase sea utilizada desde un lenguaje .NET, la clase debe adherir
la Especificación Común de Lenguaje(Common Language Specification - CLS) la cual
describe que características pueden ser visibles en la interfaz pública de la clase, por ejemplo
el CLS prohibe exponer tipos de datos sin signo, porque no todos los lenguajes pueden
utilizarlos.
Atributos
El runtime .NET soporta atributos personalizables, los cuales son en cierto sentido un lugar
para colocar información descriptiva en los metadatos junto con un objeto y entonces recuper
después los datos. Los atributos proveen un mecanismo general para hacer esto y son
utilizados en exceso en todo el tiempo de ejecución para almacenar información que modifica
como el runtime utiliza las clases.
Los atributos son extensibles y permite a los programadores definir atributos y utilizarlos.
Los atributos se especifican encerrandolos entre corchetes:
[Version("14/09/2005", Comentario="1.0.1.0")]
Los atributos son anotaciones que se colocan en elementos de código fuente,
como clases, miembros, parámetros, etc.
Ismael Galan Cazares
Los atributos puede ser utilizados para: cambiar el comportamiento del runtime, proveer
información acerca de un objeto, llevar información organizacional al diseñador.
El atributo información es almacenado con los metadatos del elemento y pueden ser
facilmente recuperados en tiempo de ejecución a través de un proceso conocido
como reflection.
C# utiliza un Atributo Condicional para controlar cuando las funciones miembro son
invocadas.
Por convención los atributos se agregan al final del nombre de una clase, con la finalidad de
conocer cuales son clases atributo y cuales son clases normales. Todos los atributos derivan
de System.Attribute.
Procure que el atributo para el elemento sea específico, utilizando los identificadores
siguientes:
Identificador Descripción
assembly ensamble
module Módulo
type clase o estructura
method Método
property porpiedad
event Evento
field Campo
param parámetro
return valor de regreso
Los atributos que son aplicados a ensambles o módulos deben colocarse después de
cualquier cláusula using y antes de cualquier código.
El código no administrado no tiene las ventajas que tiene el código administrado, como
recolección de basura, sistema de tipo unificado y metadatos.
Código administrado invocando funciones DLL no administradas, cuando la aplicación
necesita una interfaz para una DLL en C y la empresa que escribe la DLL no adopta .NET
será necesario invocar esa DLL desde una aplicación .NET.
Código administrado usando componentes COM, es posible lograr esto creando un wrapper
.NET para el componente COM, así que el cliente administrado trabaja con clases .NET
Código no administrado usando servicios .NET, cuando se desea acceder a .NET desde
código no administrado.
Tipos de Datos
C# soporta el conjunto de tipos de datos usual, para cada tipo de dato que C# soporta, existe
una correspondencia tipo de lenguaje común en tiempo de ejecución .NET subyacente.
Todos los tipos runtime pueden encontrarse en el namespace System del lenguaje común en
tiempo de ejecución .NET.
Tipo Bytes Tipo runtime Descripción
byte 1 Byte Unsigned byte
Ismael Galan Cazares
sbyte 1 SByte Signed byte
short 2 Int16 Signed short
ushort 2 UInt16 Unsigned short
int 4 Int32 Signed integer
uint 4 UInt32 Unsigned int
long 8 Int64 Signed big integer
ulong 8 UInt64 Unsigned big integer
float 4 Single Floating point number
double 8 double Double-precision floating point number
decimal 8 Decimal Fixed-precision number
string String Unicode string
char Char Unicode character
bool Boolean Boolean value
Los tipos de datos son separados en value types y reference types. Los value types son
asignados en estructuras de pilas o en línea. Los reference types son asignados al
aglomerado.
Las referencias y tipos de valores son derivados de la última clase base objet, de esta manera
en caso de que un tipo de valor necesite actuar como un object una envoltura hace que el tipo
de valor parezca una referencia asignandolo al aglomerado, y los tipos de valores son
copiados a estos. La envoltura es marcada por lo que el sistema conoce que contiene por
ejemplo int, a este proceso se le conoce como boxing y el proceso de reversa se le conoce
como unboxing
La palabra reservada class es empleada para declarar un tipo referencia (heap allocated), y la
palabra reservadastruct es empleada para declarar un tipo valor, una estructura es utilizada
para objetos ligeros que necesitan actuar como tipos built-in, las clases son utilizadas en
cualquier otro caso.
Por ejemplo un tipo int es un valor tipo y un tipo string es un tipo referencias, esto trabajaria
así:
int i = 2005;
string s = "Septiembre";
I 2005
------------
S o----- Septiembre
>
using System;
class Args{
public static void Main(string[] args){
Console.WriteLine("Argumentos : {0}", args.Length);
for(int itera = 0; itera < args.Length; itera++)
Console.WriteLine("Argumento {0} : {1}", itera, args[itera]);
}
}
Ejemplo de Args con foreach:
using System;
class App{
public static void Main(string[] args){
foreach(string input in args){
Console.WriteLine(input);
}
}
}
using System;, define el namespace System, el cual contiene entre otras la clase Console la
cual es utilizada para comunicarse con la línea de comandos.
using permite al usuario omitir el namespace al utilizar el tipo al que es referenciado en este
caso System, por lo que en vez de escribir:
System.Console.WriteLine();
Solamente se escribe:
Console.WriteLine();
using no puede ser utilizado con un nombre de clase por lo que no es permitido escribir using
System.Console
class Args, Al no existir las funciones globales en C#, se declara una clase llamada Args.
public static void Main(string[] args), La clase Args contiene una función o método Main(), el
cual sirve como punto de partida de la ejecución del componente, este método puede o no ser
declarado con argumentos, en este caso es fundamental declarlos porque deseamos
precisamente leer y escribir estos argumentos proporcionados al invocar el componente.
Al ser un método de arranque debe ser declarado con el modificador static porque no está
asociado con una instancia de un objeto.
El método indica que recibe un arreglo de tipo string llamado args
Console.WriteLine("Argumentos : {0}", args.Length);, invoca el método WriteLine de la
clase Console para escribir en la línea de comando lo que se indica entre los paréntesis.
La primer parte de lo que se encierra entre paréntesis es un string donde es necesario
destacar que{0}, es una notación que indica entre llaves un índice que hace referencia a una
variable asociada a este, en este caso asociada con args.Length
args.Length, Length es un método de la clase args el cual obtiene el número de elementos
que contiene este arreglo.
El ciclo for comienza una iteración desde 0 hasta el número de elementos que contiene el
arreglo args.Length, por cada elemento contenido en el arreglo escribe en la línea de
comandos lo que se indica en ("Argumento {0} : {1}", itera, args[itera]) que como
Ismael Galan Cazares
mencionamos anteriormente {0} hace referencia al orden en que las variables serán escritas,
en este caso corresponde al iterador y {1} corresponde a args[itera], lo cual indica obtener el
elemento en cuestión del arreglo args.
Para compilar el componente utilice csc Args.cs
Para ejecutar el componente sin parámetros escriba en la línea de comando: csc Args
Salida : Argumentos : 0
Para ejecutar el componente con parámetros escriba en la línea de comando:
csc Args p1 p2 p3 p4 p5 p6 ... pn
Por ejemplo: args http : www . informatique . com . mx
Salida :
Argumentos : 8
Argumento 0 : http
Argumento 1 : :
Argumento 2 : www
Argumento 3 : .
Argumento 4 : informatique
Argumento 5 : .
Argumento 6 : com
Argumento 7 : .
Argumento 8 : mx
Ejemplo Input/Output
Es posible leer datos de la consola utilizando el método ReadLine y es posible mostrarlos
utilizando el método Write oWriteLine del objeto Console:
using System;
class inOut{
public static void Main(){
Console.Write("Fecha de Nacimiento: ");
String strFecNac = Console.ReadLine();
Console.WriteLine("FecNac = " + strFecNac);
}
}
Note que importar la directiva System hace posible omitir escribir el namespace, de esta
forma sólo es necesario escribir el nombre del objeto seguido del nombre del método.
Ejemplo String Format
Es posible dar formato a la salida de datos a un tipo string, utilizando la
sintaxis {número} donde número es reemplazado por la variable correspondiente:
using System;
class strFormat{
public static void Main(){
Console.Write("Nombre: ");
String strNombre = Console.ReadLine();
Ismael Galan Cazares
Console.Write("Edad: ");
String strEdad = Console.ReadLine();
Console.Write("Teléfono: ");
String strTel = Console.ReadLine();
Console.Write("Dirección: ");
String strDir = Console.ReadLine();
using System;
class App{
public static void Main(){
Console.WriteLine("Hello world!");
}
}
El ejemplo anterior define a la función Main como void lo cual indica que no regresa un valor,
pero es posible indicar que si regrese un valor escribiendo el tipo de la función como int por
ejemplo, que indica que regresa un valor de tipo entero:
using System;
class App{
public static int Main(){
Console.WriteLine("Hello world!");
return(1);
}
}
También es posible que la función Main reciba parámetros de la línea de comandos, para ello
es necesario especificar un arreglo de strings como parámetro:
using System;
class App{
public static void Main(string[] args){
foreach(string input in args){
Console.WriteLine(input);
}
}
}
Bool
Representa valores booleanos verdadero y falso, por lo que es posible asignar a una variable
un valor booleano o el resultado de una expresión:
bool bContinuar = (a > b);
En C# el valor verdadero no es posible representarlo con algún valor diferente de cero, no hay
una conversión entre el tipo integral a bool que force esta conversión.
Char
Representa un caracter Unicode de 16 bit de tamaño, por ejemplo:
char cSexo = 'M';
También es posible asignar un valor hexadecimal utilizando la secuencia de escape x o un
valor Unicode con lasecuencia de escape u:
char cHexadecimal = 'x0068';
char cUnicode = 'u0068';
No existen conversiones implicitas de char a otro tipo de datos disponible, esto significa por
ejemplo que tratar de convertir una variable char a un tipo de dato integral no es posible en
C#, por lo que se tendrá que hacer uncast explicito:
char cCaracter = (char)65;
int nNumero = (int)'A';
Floating Point
Representan dos tipos de datos, flotantes (float) y dobles (double):
Tipo Valor
float 1.5x10-45 a 3.4x1038 con una precisión de 7 dígitos
double 5.0x10-324 a 1.7x10308 con una precisión de 15-16 dígitos
Al realizar operaciones con Floating Point pueden producirse los siguientes valores:
Cero positivo y negativo
Infinito positivo y negativo
NaN, Not-a-Number
Nota: Si una expresión un valor es de tipo Floating Point todos los otros valores son
convertidos a tipos Floating Point antes de realizar el cálculo.
Decimal
Representa un tipo de alta precisión de 128 bit el cual es posible utilizarlo para calculos
financieros y monetarios. Los valores posibles comprenden los rangos 1.0x10 -28 a
7.9x1028 con una precisión de 28 a 29 dígitos.
No hay conversiones implicitas entre decimales y dobles, se podría generar un overflow o
perder precisión, por lo que es necesario una conversión explícita con un cast.
Ismael Galan Cazares
Cuando se define una variable y se le asigna un valor se utiliza el sufijo m para denotar que
es un valor decimal:
decimal decDecimal = 1.0m
Si se omite la letra m la variable podría ser tratada como double por el compilador antes de
ser asignado.
Tipos Estructura
Un tipo struct puede declarar constructores, constantes, campos, métodos, propiedades,
índices, operadores y tipos anidados. Las estructuras actuan de manera similar a una clase y
con mayores restricciones, por ejemplo no pueden heredar de cualquier otro tipo, ni tampoco
otra clase puede heredar de una estructura.
Las estructuras deberían ser utilizadas sólo para tipos que son realmente una pieza de datos.
La diferencia entre struct y class en C# es que struct es un value type y class es
una reference type.
La principal idea de utilizar struct es para crear objetos ligeros como Point, FileInfo, etc., de
esta manera se conserva memoria porque no hay referencias adicionales que son creadas
como se necesiten por objetos clase.
using System;
struct IP{
public byte b1,b2,b3,b4;
}
class ip{
public static void Main(){
IP miIP;
miIP.b1 = 192;
miIP.b2 = 168;
miIP.b3 = 1;
miIP.b4 = 101;
Console.Write("{0}.{1}.", miIP.b1,miIP.b2);
Console.Write("{0}.{1}", miIP.b3,miIP.b4);
}
}
Tipos Enumeración
Es posible establecer un conjunto de constantes relacionadas, por default los elementos de
una enumeración son de tipo int donde el primer elemento tiene el valor 0 y cada elemento
subsecuente se incrementa en 1. Es posible establecer el valor del primer elemento
simplemente asignando a este el valor deseado, así como es posible especificar el tipo de
dato de los valores contenidos especificandolo después del nombre de la enumeración
aunque están restringidos a los tipos: long, int, short y byte.
Sintaxis:
enum NombreEnumeraciones{
constante1,
constante2,
constante3,
.
.
constanteN
Ismael Galan Cazares
}
Ejemplo:
using System;
public class Enumeracion {
enum enumDias {Sabado, Domingo, Lunes, Martes, Miércoles, Jueves,
Viernes };
enum enumMeses
{Enero,Febrero,Marzo,Abril,Mayo,Junio,Julio,Agosto,Septiembre,_
Octubre,Noviembre,Diciembre};
enum enumFecha {Dia = 21, Mes = 9, Año = 1971};
Console.WriteLine();
Console.WriteLine("Los meses del año, y su valor correspondiente en la enumeración
es:");
Tipos Base
Los Tipos Base para las enumeraciones se especifican listando el tipo base después del
nombre de la enumeración:
enum eDias : int{
Lunes,
Martes,
Miércoles,
Jueves,
Viernes
};
Los tipos base válidos para las enumeraciones
son: byte, sbyte, short, ushort, int, uint, long y ulong.
Si el tipo base no es especificado, el tipo base por default es int.
Ismael Galan Cazares
Tipos Referencia
Es contraste a value types los reference types no almacenan el dato actual que representan,
porque almacenan una referencia al dato actual.
Tipo Objeto
El Tipo Objeto es la Clase Base de todos los tipos, al ser la clase base de todos los tipos es
posible asignarle valores de cualquier tipo.
El Tipo Objeto es utilizado cuando el value type esta boxed, es decir, que está disponible
como un objeto.
Tipo Clase
El Tipo Clase contiene datos miembro, funciones miembro y tipos anidados. Los datos
miembro son constantes, campos y eventos. Las funciones miembro incluyen métodos,
propiedades, índices, operadores, constructores y destructores.
Interfaces
Una interface declara un tipo referencia que tiene sólo miembros abstractos. Sólo existe la
firma pero no tiene implementado todo el código, por lo que no es posible instanciar una
interface, sólo un objeto que deriva de la interface. Para crear una interface se emplea la
palabra reservada interface:
using System;
interface Iuno{
void AccionUno();
}
class App{
public static void Main(){
Implementa I = new Implementa();
I.AccionUno();
}
}
Es posible definir métodos, propiedades e índices en una interface, cuando se define una
Clase es posible derivar de múltiples interfaces, mientras que al definir una interface sólo es
posible derivar de sólo una clase.
Las interfaces están estrechamente relacionadas a clases abstractas, se parecen a una clase
abstracta que tiene todos sus miembros abstractos.
Cuando un objeto implementa una interface, una referencia a la interface puede ser obtenida
por un cast de la interface.
Una clase puede implementar más de una interface.
class NombreClase : InterfaceA, InterfaceB{}
Ismael Galan Cazares
Existe una técnica llamada Implementación de la Interface Explícita y se utiliza para resolver
colisiones con nombres de métodos iguales entre interfaces:
using System;
interface Iuno{
void AccionUno();
}
interface Idos{
void AccionUno();
}
class App{
public static void Main(){
Implementa I = new Implementa();
Iuno uno = (Iuno) I;
uno.AccionUno();
Idos dos = (Idos) I;
dos.AccionUno();
}
}
Es posible ocultar al usuario de la clase la implementación de una interfaz, así como también
es posible crear interfaces basadas de otras interfaces.
Delegados
Los delegados son similares a las interfaces, especifican un contratado entre un caller y
un implementer(implementador).
Un delegado especifica la forma de una función en vez de especificar toda una interface.
Las interfaces se crean en tiempo de compilación y los delegados son creados en tiempo de
ejecución.
Un delegado encapsula un método con cierta firma, básicamente un delegado es un type-
safe y secure version. Un delegado es una implementación de function pointers orientada a
objetos y son utilizados en muchas situaciones donde un componente necesita volver a
invocar el componente que lo esta usando.
Es posible encapsular métodos estáticos e instancias en una instancia delegado.
El principal uso de los delegados es con los eventos no con las clases.
La especificación del delegado determina la forma de la función y crea una instancia del
delegado, se usa la función que coincide con la forma.
Ismael Galan Cazares
Los delegados al ser de naturaleza dinámica se utilizan cuando el usuario desea cambiar el
comportamiento, por ejemplo si deseamos que una clase Ordenamiento soporte diferentes
métodos de ordenación, la ordenación podría ser controlada en base a un delegado que
defina la función de comparación.
Nota los delegados siempre son creados aún si no son usados, pero los delegados podrían
ser creados al vuelo si se reemplazan las funciones estáticas por propiedades, entonces
unicamente se crea el delegado solo si se utiliza la propiedad.
Tipo string
El Tipo string se utiliza para manipular datos string. La clase string deriva directamente
de object y no es posible derivarla.
Todos los strings en C# son instancias del tipo System.String en el CLR.
string es un alias para la clase predefinida System.String y su uso es muy sencillo:
string sWebSite = "http://www.informatique.com.mx";
Para acceder a un caracter, simplemente acceda a su índice:
sWebSite[11];
Es posible hacer un barrido de los caracteres que componen el string utilizando la
propiedad Length que poseen los arreglos y porque es posible acceder a estos tratando
al string como un arreglo:
using System;
class App{
public static void Main(){
string sWebSite = "http://www.informatique.com.mx";
Console.WriteLine("sWebSite contiene : " + sWebSite.Length + "
caracteres");
for(int iElemento = 0; iElemento < sWebSite.Length; iElemento++){
Console.WriteLine("Elemento " + iElemento + " : " +
sWebSite[iElemento]);
}
}
}
Es posible concatenar strings utilizando el operador +.
Si requiere comparar strings por igualdad utilice el operador de comparación ==
Aunque string es un reference type la comparación se realiza comparando los valores no las
referencias.
La clase String es un ejemplo de tipo inmutable, es decir, que los caracteres contenidos en el
string no puede ser modificados por los usuarios del string, todas las operaciones que son
realizadas por la clase String regresan una versión modificada del string en vez de modificar
la instancia en la cual se invoco el método.
La clase String soporta los sisguientes métodos de comparación y búsqueda:
Método Descripción
Compare() Compara dos strings.
Compara dos regiones de strings utilizando una comparación
CompareOrdinal()
ordinal
CompareTo() Compara la instancia actual con otra instancia.
Ismael Galan Cazares
EndsWith() Determina cuando un substring existe al final de un string
StartsWith() Determina cuando un substring existe al principio de un string.
IndexOf() Regresa la posición de la primer ocurrencia de un substring
LastIndexOf() Regresa la posición de la última ocurrencia de un substring
Concatena dos o más strings u objetos, si se pasan objetos la
Concat()
función ToString es invocada
Copia un número específico de caracteres de una ubicación del
CopyTo()
string dentro del arreglo
Regresa un nuevo string con un substring insertado en la
Insert()
ubicación específica
Une un arreglo de strings junto con un separador entre cada
Join()
elemento del arreglo
PadLeft() Alinea a la izquierda un string
PadRight() Alinea a la derecha un string
Remove() Elimina caracteres de un string
Reemplaza todas las instancias de un caracter con caracteres
Replace()
diferentes
Crea un arreglo de strings dividiendo un string en cualquier
Split()
ocurrencia de uno o más caracteres
Substring() Extrae un substring de un string
ToLower() regresa una versión de un string en minúsculas
ToUpper() regresa una versión de un string en mayúsculas
Trim() Elimina espacios en blanco de un string
TrimEnd() Elimina un string de caracteres al final de un string
TrimStart() Elimina un string de caracteres al inicio de un string
object.ToString(), convierte un objeto a una representación string. String.Format() puede ser
utilizada para crear un string basado en los valores de otro string.
La clase StringBuilder soporta las siguientes propiedades y métodos:
Propiedad Descripción
Recupera o establece el número de caracteres
Capacity
que StringBuilder puede contener
Índice StringBuilder utilizado para obtener o establecer un caracter en
[]
la posición específica
Length Recupera o establece la longitud
MaxCapacity Recupera la capacidad máxima del StringBuilder
Método Descripción
Append() Agrega la representación string de un objeto
Agrega la representación string de un objeto, utilizando un
AppendFormat()
formato específico para el objeto
Ismael Galan Cazares
Asegura que StringBuilder tiene suficiente espacio para un
EnsureCapacity()
número de caracteres específico
Inserta la representación string de un objeto específico en una
Insert()
posición específica
Remove() Elimina los caracteres específicos
Reemplaza todas las instancias de un caractes con un nuevo
Replace()
caracter
Arreglos
Un arreglo contiene variables a las cuales se accede a través de índices, todas las variables
contenidas en el arreglo son referidos como elementos los cuales deben ser del mismo tipo,
por lo que el tipo del arreglo.
Los arreglos en C# son referencias a objetos. Un arreglo value type no contiene
instancias boxed.
El valor inicial de un arreglo es null, un arreglo de objetos es creado utilizando new.
Cuando un arreglo es creado inicialmente contiene los valores por default para los tipos que
este contendrá.
Sintaxis:
tipo[] identificador;
Note que para definir un arreglo se utilizan los corchetes [] después del tipo del arreglo.
Ejemplo:
string[] aPersonas;
Es posible inicializar un arreglo al momento de crearlo:
string[] asPersonas = new string[] {"Tim Berners-Lee","Brendan Eich","Dennis Ritchie","James
Gosling"};
Durante la inicialización es posible omitir new tipo[x] y el compilador podría determinar el
tamaño de almacenamiento para el arreglo del número de items en la lista de inicialización:
string[] asPersonas = {"Tim Berners-Lee","Brendan Eich","Dennis Ritchie","James Gosling"};
Cada elemento de un arreglo de ints es un int con el valor 0:
int[] aiNumeros = new int[5];
Cada elemento de un arreglo de strings es un string con el valor null:
string[] asNombres = new string[5];
La dimensión del arreglo puede ser simple o multidimensional, donde cada dimensión
comienza con el índice 0, si requiere hacer un barrido de todos los elementos del arreglo,
comience a partir del índice 0 hasta la longitud del arreglo menos uno (nombreArreglo.Length
- 1 o nIndice < nombreArreglo.Length);
using System;
class Arreglo{
static public void Main(){
string[] aNombres = {"Hugo","Paco","Luis"};
Console.WriteLine(aNombres[0]);
Console.WriteLine(aNombres[1]);
Console.WriteLine(aNombres[2]);
}
}
Ismael Galan Cazares
Otra alternativa al ejemplo anterior es:
int[] aiNumeros = new int[3];
aiNumeros[0] = 4;
aiNumeros[1] = 33;
aiNumeros[2] = 43;
Al declarar el arreglo especifique solamente el número de elementos que este contendrá.
utilice la palabre reservadanew seguido del tipo y entre corchetes el número de elementos
que contendrá.
Es posible ordernar y buscar los elementos de un arreglo gracias a que los arreglos en C#
están basados en el tipoSystem.Array del runtime NET. El método Sort() podría ordenar los
elementos de un arreglo, los métodos IndexOf() yLastIndexOf() y BinarySearch podrían
buscar elementos en un arreglo. El método Reverse podría invertir el orden de los elementos
de un arreglo.
Arreglos Multidimensionales
Los Arreglos Multidimensionales son aquellos que tienen más de una dimensión.
Sintaxis:
tipo[,] identificador;
Ejemplo:
string[,] asBidimensional = new string[2, 4];
Para definir un arreglo multidimensional, simplemente defina arreglos como elementos del
arreglo:
string[,] asMulti = {{"a","1"},{"b","2"},{"c","3"}};
Ejemplo:
using System;
class App{
public static void Main(){
asBidimensional[0,0] = "00";
asBidimensional[0,1] = "01";
asBidimensional[1,0] = "10";
asBidimensional[1,1] = "11";
asBidimensional[2,0] = "20";
Ismael Galan Cazares
asBidimensional[2,1] = "21";
asBidimensional[3,0] = "30";
asBidimensional[3,1] = "31";
Arreglo de Arreglos
Un Arreglo de Arreglos es también conocido como jagged array porque no tiene que ser
rígido.
Por ejemplo:
int[][] aiIDs = new int[3][];
Este ejemplo define un arreglo de arreglo de tipo int donde su dimensión es 3 elementos,
donde estos elementos son arreglos.
Arreglos de Objetos
Un arreglo de objetos es creado utilizando new.
Es posible declarar y manipular arreglos de objetos de la siguiente manera:
using System;
public class Persona{
//Propiedades
public string sNombre;
public int iEdad;
//Constructor
public Persona(string sNombre, int iEdad){
this.sNombre = sNombre;
this.iEdad = iEdad;
}
//Métodos
public string Tipo(){
return "Persona";
}
}
Ismael Galan Cazares
//Herencia Simple
public class Empleado : Persona{
public Empleado(string sNombre, int iEdad):base(sNombre, iEdad){}
public new string Tipo(){
return "Empleado";
}
}
class App{
//Aplicación
public static void Main(){
Persona Mexicano = new Persona("Gerado Ángeles Nava", 33);
Console.WriteLine("Mexicano.sNombre : " + Mexicano.sNombre);
Console.WriteLine("Mexicano.iEdad : " + Mexicano.iEdad);
Console.WriteLine("Mexicano.Tipo : " + Mexicano.Tipo());
class App{
public static void Main(){
Lenguaje[] aLenguaje = new Lenguaje[5];
aLenguaje[0] = new Lenguaje("C",3);
aLenguaje[1] = new Lenguaje("ActionScript",5);
aLenguaje[2] = new Lenguaje("JavaScript",2);
aLenguaje[3] = new Lenguaje("Java",8);
aLenguaje[4] = new Lenguaje("PHP",1);
Array.Sort(aLenguaje);
foreach(Lenguaje len in aLenguaje)
Console.WriteLine(len);
}
}
Salida:
PHP 1
JavaScript 2
C3
ActionScript 5
Java 8
Interface IComparer
Es posible definir múltiples tipos de ordenamientos gracias a que el diseño
del Framework provee esta capacidad.
Cada clase sólo puede implementar una interface a la vez, por lo que solamente se podría
permitir un tipo de ordenamiento, entonces se requiere una clase separada para cada tipo de
ordenamiento que implementen IComparery podría también implementar la
función Comapare():
using System;
using System.Collections;
Ismael Galan Cazares
public class Lenguaje : IComparable{
string nombre;
int id;
public Lenguaje(string nombre, int id){
this.nombre = nombre;
this.id = id;
}
int IComparable.CompareTo(object o){
Lenguaje lenguajeB = (Lenguaje)o;
if(this.id > lenguajeB.id){return 1;}
if(this.id < lenguajeB.id){
return -1;
}else{
return 0;
}
}
public override string ToString(){
return nombre + " " + id;
}
public class OrdenaNombres : IComparer{
public int Compare(object oA, object oB){
Lenguaje lenA = (Lenguaje)oA;
Lenguaje lenB = (Lenguaje)oB;
return String.Compare(lenA.nombre,lenB.nombre);
}
}
}
class App{
public static void Main(){
Lenguaje[] aLenguaje = new Lenguaje[5];
aLenguaje[0] = new Lenguaje("C",3);
aLenguaje[1] = new Lenguaje("ActionScript",5);
aLenguaje[2] = new Lenguaje("JavaScript",2);
aLenguaje[3] = new Lenguaje("Java",8);
aLenguaje[4] = new Lenguaje("PHP",1);
class App{
public static void Main(){
Lenguaje[] aLenguaje = new Lenguaje[5];
aLenguaje[0] = new Lenguaje("C",3);
Ismael Galan Cazares
aLenguaje[1] = new Lenguaje("ActionScript",5);
aLenguaje[2] = new Lenguaje("JavaScript",2);
aLenguaje[3] = new Lenguaje("Java",8);
aLenguaje[4] = new Lenguaje("PHP",1);
Array.Sort(aLenguaje, Lenguaje.Ordena);
ActionScript 5
C3
Java 8
JavaScript 2
PHP 1
Expresiones Regulares
Las Expresiones Regulares proveen un método muy poderoso para hacer funciones de
busquedas y reemplazamiento.
Operador as
El Operador as checa el tipo del operador izquierdo y si puede ser convertido explicitamente a
el operador derecho, se obtiene como resultado el objeto convertido a el operador derecho, si
no puede ser convertido la operación falla y regresa null. Este operador sólo puede se
utilizado con clases.
Secuencias de Escape
Secuencia de Escape Descripción
' Comilla simple
" Comilla doble
\ Diagonal invertida
Nulo
A Alert
B Retroceso
F Form Feed
N Nueva línea
R Retorno de carro
T Tabulador
V Tabulador vertical
Ismael Galan Cazares
Boxing
Boxing es un mecanismo que crea una liga entre los tipos de valores y las tipos de
referencia permitiendo a un tipo de valor ser convertido a un tipo objeto y viceversa.
using System;
class App{
public static void Main(){
int iEdad = 33;
object oNumero = iEdad; //Box
int iNumero = (int)oNumero; //Unbox
//cast necesario porque oNumero podría contener cualquier tipo de
objeto
}
}
Nota, durante la conversión unboxing el tipo debe coincidir exactamente, un valor de
tipo boxed no puede ser unboxed(convertido) a un tipo compatible. Si requiere obtener otro
tipo de valor diferente al que contiene el boxed, en ese caso primero obtenga el valor correcto
y después realice un cast al tipo que requiera: (valorRequerido)
valorRequerido vr = (valorRequerido)(valorBoxed)objeto;
Otra forma de definir el concepto boxing es que este mecanismo permite que los value
types parezcan o tengan la apariencia de reference types.
Conversiones Boxing
Boxing un valor se refiere a la conversión implícita de cualquier tipo de valor al tipo objeto.
Cuando un tipo de valor esboxed se asigna espacio a una instancia de objeto y el valor
del value type es copiado al nuevo objeto.
Observe las siguientes líneas:
int iNumero = 2012;
object oNumero = iNumero; //invocación implicita a una operación
boxing
oNumero = 2005;
Console.WriteLine(iNumero);
Console.WriteLine(oNumero);
}
}
Ismael Galan Cazares
Al ejecutar el código notará que el valor de oNumero es 2005 y el valor de iNumero no cambio
permanece en 2012.
Conversiones Unboxing
Al contrario que Boxing, Unboxing es un mecanismo de una operación explícita, por lo que es
necesario indicar al compilador que tipo de valor deseamos extraer de un objeto, al realizar la
operación Unboxing C# checa que el value type que se requiere este almacenado en la
instancia del objeto, si la verificación es exitosa el valor es Unboxing.
Suponga que tiene una variable de tipo int y asigna el valor de esta variable int a un objeto,
después declara una variable de tipo double y aplica un cast (double) al objeto para asignar
su valor a la variable double, el objeto contiene sólo un valor int y no puede ser asignado a la
variable double porque el CLR dispara una excepción (System.InvalidCastException):
int iNumero = 2012;
object oNumero = iNumero; //invocación implicita a una operación boxing
double dNumero = (double)oNumero; //invocacion explícita (cast)
//CLR dispara la excepción System.InvalidCastException
Constructores y Destructores
Antes de acceder a los métodos o propiedades de una clase, primero se ejecuta el
constructor de la clase el cual contiene código de inicialización, si no se escribe un
constructor para la clase el compilador provee automáticamente un constructor default.
En el runtime .NET el programador no puede controlar la destrucción de objetos.
Un constructor puede invocar un constructor del tipo base utilizando la sintaxis base.
Los constructores son invocados invocados automaticamente sólo cuando una instancia de
un objeto es creada connew.
class NombreClase{
public NombreClase() : base(){} //Constructor que provee el compilador
}
Las características de un constructor son:
Siempre tiene el mismo nombre que la clase.
No tiene declarado un tipo de regreso.
Por lo general tienen el modificador público.
Son utilizados para inicializar varibles.
Si la clase sólo contiene miembros estáticos, es posible crear un constructor private, lo cual
significa que no podrá ser accesible fuera de la calse o que sólo se puede acceder desde la
clase.
No puede ser invocado desde la definición de la clase.
Un objeto no puede ser instanciado desde la definición de la clase.
Al codificar no se está limitado a los parámetros del constructor, es posible enviar argumentos
iniciales para inicializar ciertos miembros.
using System;
class Vehiculo{
//Propiedades:
private int iRueda;
private int iPuerta;
Ismael Galan Cazares
private int iVentana;
private int iHelice;
private int iMotor;
private int iAsiento;
private string sTipo;//Aereo, anfibio, terrestre, espacial
//Constructor:
public Vehiculo(int Rueda, int Puerta, int Ventana, int Helice, _
int Motor, int Asiento, string Tipo){
iRueda = Rueda;
iPuerta = Puerta;
iVentana = Ventana;
iHelice = Helice;
iMotor = Motor;
iAsiento = Asiento;
sTipo = Tipo;
}
//Lectura/escritura de propiedades:
public int Ruedas{
get{return iRueda;}
set{iRueda = value;}
}
//Aplicación:
class AplicConstructor{
public static void Main(){
Vehiculo MiAvion = new Vehiculo(2,1,100,0,3,200,"Aereo");
Console.WriteLine("Ruedas : " + MiAvion.Ruedas);
Console.WriteLine("Puertas : " + MiAvion.Puertas);
Console.WriteLine("Ventanas : " + MiAvion.Ventanas);
Console.WriteLine("Helices : " + MiAvion.Helices);
Console.WriteLine("Motores : " + MiAvion.Motores);
Console.WriteLine("Asientos : " + MiAvion.Asientos);
Console.WriteLine("Tipo : " + MiAvion.Tipo);
}
}
En un sentido estricto en C# no se tienen destructores, pero el termino destructor se refiere a
la liberación de recursos.
Es posible escribir un método que libere recursos después de ser utilizados, pero porque
escribir un método para liberar recursos si existe un destructor:
public ~NombreClase(){
//liberar recursos
}
La razón por la cual se debería escribir un método adicional es por el recolector de basura, el
cual no es invocado inmediatamente después que las variables quedan fuera de ámbito, sólo
se invoca el recolector de basura en ciertos intervalos o condiciones de memoria.
Lo que podría suceder es que los recursos se agoten antes de ser utilizados, entonces es
buena idea proveer un método explícito Release, el cual también puede ser invocado por el
destructor:
public void Release(){
//Liberar recursos
}
public ~NombreClase(){
Release();
}
La invocación del método Release en el destructor no es obligatoria, la colección garbage de
cualquier forma realiza la liberación de cualquier objeto, pero es una buena práctica no olvidar
liberar los recursos.
Constructor Estático
Un Constructor Estático podría ser invocado antes de ser creada la primer instancia de un
objeto, y es útil para configurar el trabajo que necesita hacerse una vez.
En el runtime .NET el usuario no tiene control sobre cuando el constructor estático es
invocado, ya que el runtime sólo garantiza que algo es invocado después del inicio del
Ismael Galan Cazares
programa y antes de ser creada la primer instancia de un objeto, lo que significa que no
puede ser determinada la instancia que es creada en el constructor estático.
Para declarar un constructor estático se utiliza el modificador static:
class NombreClase{
static NombreClase(){
.
.
}
}
Métodos
La mayor parte de la funcionalidad es implementada en los métodos, los métodos son parte
del Tipo (class), pero los métodos no son parte de la instancia (object).
Parámetros
De algún modo se deben pasar valores a un método y también se debe regresar el resultado
de un método, los valores son manipulados en:
Valores en Parámetros in
Se utilizan valores en parámetros para pasar una variable por valor a un método, la variable
del método es inicializada con una copia del valor del caller (quien realizó la invocación).
using System;
public class Fecha{
public string Mayor(int iDiaA,int iMesA,int iAñoA,int iDiaB,int iMesB,int
iAñoB){
int iA = (iDiaA * 10000) + (iMesA + 100) + (iAñoA);
int iB = (iDiaB * 10000) + (iMesB + 100) + (iAñoB);
Console.WriteLine(iA + " > " + iB); //Test Line (Delete)
if(iA > iB){
return iDiaA + "/" + iMesA + "/" + iAñoA;
}else{
return iDiaB + "/" + iMesB + "/" + iAñoB;
}
}
public string Menor(int iDiaA,int iMesA,int iAñoA,int iDiaB,int iMesB,int
iAñoB){
int iA = (iDiaA * 10000) + (iMesA + 100) + (iAñoA);
int iB = (iDiaB * 10000) + (iMesB + 100) + (iAñoB);
Console.WriteLine(iA + " < " + iB); //Test Line (Delete)
if(iA < iB){
return iDiaA + "/" + iMesA + "/" + iAñoA;
}else{
return iDiaB + "/" + iMesB + "/" + iAñoB;
}
}
}
class AplicFecha{
Ismael Galan Cazares
public static void Main(){
Fecha MiFecha = new Fecha();
Console.WriteLine("La fecha mayor es : " + MiFecha.Mayor(21,9,1971,
21,10,2000));
Console.WriteLine("La fecha menor es : " + MiFecha.Menor(21,9,1971,
21,10,2000));
using System;
class Parametros{
public static void Main(){
Param MiParam = new Param();
Los parámetros out son exactamente como los parámetros ref excepto que una variable sin
inicializar puede ser pasada como parámetro y el caller define un parámetro out en vez de ref.
Ismael Galan Cazares
Valores en Parámetros out
Un parámetro out puede ser utilizado sólo para contener el resultado de un método, es
necesario especificar el modificador out para indicar el tipo de parámetro, a diferencia de los
parámetros ref el caller no necesita inicializar la variable antes de invocar el método:
using System;
class Parametros{
public static void Main(){
Param MiParam = new Param();
int iValorOut; //No se requiere inicilizar el valor
MiParam.ParametroOut(out iValorOut); //Se invoca el método con un
parámetro out
Console.WriteLine("out : " + iValorOut);//Resultado de la invocación del
método
}
}
Ejemplo de Parámetros In, Ref y Out
using System;
class Parametros{
public static void Main(){
Param MiParam = new Param();
class RedefinirMetodos{
public static void Main(){
ClaseBase ClsBase = new ClaseBase();
Ismael Galan Cazares
Console.WriteLine("Clase base : " + ClsBase.Calculo(5,3));
//Se crea una instancia de la clase derivada:
ClaseDerivada ClsDer = new ClaseDerivada();
//Se invoca el método redefinido en la clase derivada:
Console.WriteLine("Clase derivada : " + ClsDer.Calculo(5,3));
}
}
Ocultamiento de Métodos (Hiding)
Es posible ocultar métodos de la clase base, esto se logra haciendo uso de una característica
especial de la redefinición de métodos llamada ocultamiento de métodos y al derivar de la
clase base:
using System;
class ClaseBase{
//Sin código
}
class Hiding{
public static void Main(){
ClaseDerivada MiClaseDerivada = new ClaseDerivada();
MiClaseDerivada.MetodoOculto();
}
}
El código anterior demuestra que es posible derivar una clase que implementa un método que
la clase base no contiene.
Por otro lado si la clase base contiene el método y se trata de derivar una clase que trata de
implemetar un método que si contiene la clase, se produce un error:
using System;
class ClaseBase{
public void MetodoOculto(){
Console.WriteLine("Hiding Methods");
}
}
class Hiding{
Ismael Galan Cazares
public static void Main(){
ClaseDerivada MiClaseDerivada = new ClaseDerivada();
MiClaseDerivada.MetodoOculto();
}
}
El compilador indicará un mensaje similar al siguiente:
Hiding.cs(10,14): warning CS0108: The keyword new is required on
'ClaseDerivada.MetodoOculto()'
because it hides inherited member 'ClaseBase.MetodoOculto()'
Hiding.cs(4,14): (Location of symbol related to previous warning)
El error principal es que no se hace uso del modificador new, ya que si es posible ocultar un
método contenido en la clase base:
using System;
class ClaseBase{
public void MetodoOculto(){//Método Oculto
Console.WriteLine("Hiding Methods");
}
}
class HidingClassMet{
public static void Main(){
ClaseDerivada MiClaseDerivada = new ClaseDerivada();
MiClaseDerivada.MetodoOculto();
}
}
Al hacer uso del modificador new, se le indica al compilador que se está redefiniendo el
método de la clase base y que debería ocultar este método.
Se puede asegurar de invocar el método que redefine la clase derivada utilizando la siguiente
sintaxis:
((ClaseBase)MiClaseDerivada).MetodoOculto();
Propiedades
Las propiedades son convenientes para separar la interfaz de un objeto de su
implementación, en vez de permitir a un usuario acceder directamente a un campo o arreglo,
una propiedad permite especificar a un conjunto de sentencias realizar el acceso mientras se
permita utilizar el campo o arreglo.
class NombreClase{
using System;
class Propiedades{
Ciudadano.Edad = 33;
Console.WriteLine("Edad Ciudadano : " + Ciudadano.Edad);
Ciudadano.Mexicano = true;
Console.WriteLine("Mexicano Ciudadano : " +
Ciudadano.Mexicano);
}
}
Existen dos maneras de exponer el nombre de los atributos:
Campos (fields)
Propiedades (properties)
Los atributos son implementados como variables miembro con acceso público
via accessors (get o set).
Ismael Galan Cazares
Los accessors (get o set) especifican las sentencias que son ejecutadas cuando se requiere
leer o escribir el valor de una propiedad.
Los accessors para la lectura del valor de una propiedad son marcados con la palabra
reservada get y los accessorspara modificar el valor de una propiedad son marcados con la
palabra reservada set.
El siguiente ejemplo muestra como se implentan los accessors para las propiedades:
using System;
class Persona{
private int iSueldo;
public int Sueldo{
get{return iSueldo;}
set{iSueldo = value;}
}
}
class AplicPersona{
public static void Main(){
Persona Empleado = new Persona();
Empleado.Sueldo = 33;
Console.WriteLine("Edad : " + Empleado.Sueldo);
}
}
Note, que se utiliza el parámetro value, ya que el valor actual es almacenado en este que es
accesible dentro de la clase.
Si en vez de utilizar propiedades desea utilizar campos deberá dejar fuera los accessors y
redefinir la variable como:
public int Sueldo;
Accessors
Es posible ocultar los detalles de la estructura de almacenamiento de la clase reordenando
los accessors, en este caso el accessors set es pasado en el nuevo valor para la propiedad
en el parámetro value.
Las operaciones que pueden realizarse con los atributos son:
Implementar get y set, es posible tener acceso al valor de la propiedad para leerlo y escribirlo.
get only, sólo es posible leer el valor de la propiedad.
set only, sólo es posible establecer el valor de la propiedad.
Propiedades Estáticas
Propiedades estáticas no pueden ser declaradas con los
modificadores virtual, abstract u override.
Las propiedades estáticas pueden ser inicializadas hasta que sea necesario hacerlo, el valor
puede ser fabricado cuando se necesite sin almacenarlo.
using System;
class Persona{
int iPiernas;
Ismael Galan Cazares
int iBrazos;
int iOjos;
public Persona(int piernas, int brazos, int ojos){
this.iPiernas = piernas;
this.iBrazos = brazos;
this.iOjos = ojos;
}
public static Persona Piernas{
get{
return(new Persona(2,0,0));
}
}
public static Persona Brazos{
get{
return(new Persona(0,4,0));
}
}
public static Persona Ojos{
get{
return(new Persona(0,0,8));
}
}
}
class App{
public static void Main(){
Persona ET = Persona.Piernas;
Console.WriteLine(ET);
}
}
Índices
Es posible incluir una forma de acceso indexado a la clase tal como si la clase se tratará de
un arreglo, para ello se utiliza la característica de C# indexer, sintaxis:
atributos modificadores declarador{instrucciones}
Los índices o indexers regresan o establecen un string en un índice dado, los indexers no
tienen atributos por lo que utilizan el modificador public.
La parte del declarador consiste del tipo string y la palabra reservada this para denotar
el indexer de la clase:
public string this[int iIndex]{
get{intrucciones}
set{intrucciones}
}
Las reglas de implementación para get y set son las mismas reglas de las propiedades, la
única diferencia es que la lista de parámetros se define libremente entre los corchetes,
también existen restricciones como que es necesario especificar al menos un parámetro y los
modificadores ref y out no están permitidos.
Ejemplo:
Ismael Galan Cazares
using System;
using System.Net;//Directiva namespace para la clase DNS
class ResolverDNS{
IPAddress[] aIPs;
public void Resolver(string strHost){
IPHostEntry IPHE = Dns.GetHostByName(strHost);
aIPs = IPHE.AddressList;
}
public IPAddress this[int iIndex]{
get{return aIPs[iIndex];}
}
public int Contador{
get{return aIPs.Length;}
}
}
class AplicResolverDNS{
public static void Main(){
ResolverDNS MiDNS = new ResolverDNS();
MiDNS.Resolver("www.informatique.com.mx");
Modificadores
Modificadores de Clase
Existen dos tipos de modificadores de clase:
abstract
Una clase abstracta no puede ser inicializada
Sólo clases derivadas que no son abstractas pueden ser inicializadas
Las clases derivadas deben implementar todos los miembros abstractos de la clase base
abstracta
No puede aplicarse un modificador sealed a una clase abstracta
sealed
Clases sealed no pueden ser heredadas
Utilice este modificador para prevenir herencia accidental
Ejemplo:
using System;
}
Nota C# no puede convertir valores numéricos a booleanos, solo puede hacer comparaciones
entre ellos para evaluar el resultado de la expresión el cual es un valor booleano.
using System;
class SeleccionIf{
public static void Main(){
if(1 == 1){
Console.WriteLine("se evaluo verdadero");
}
/* No es soportado por C#
if(0){
Console.WriteLine("?");
}
*/
}
}
Nota el operador de igualdad en C# es ==, si está habituado a otra forma, sera cosa tiempo
acostumbrarse a escribirlo correctamente, en la siguiente tabla se muestran los operadores
válidos en C#:
Operador Evalua
== Verdadero, si ambos valores son los mismos
!= Verdadero, si los valores son diferentes
<, <=, >, >= Verdadero, si el valor cumple con la condición
Ismael Galan Cazares
Los operadores de la tabla son implementados via la sobrecarga de operadores y la
implementación es especifica para el tipo de dato, si se comparan dos variables de diferente
tipo se realiza una conversión implícita que debe existir para que el compilador cree el código
necesario automáticamente. Recuerde que siempre podrá realizar un castexplícito.
Ejemplo
using System;
class Caracteres{
public static void Main(){
string sNombre = "Gerardo Angeles Nava";
if(Char.IsDigit(chLetra)){
Console.WriteLine(chLetra + " es un dígito");
}else{
EsMayuscula(chLetra);
EsMinuscula(chLetra);
}
if(Char.IsDigit(chLetra)){
Console.WriteLine(chLetra + " es un dígito");
}else{
EsMayuscula(chLetra);
EsMinuscula(chLetra);
}
sNombre = "123";
chLetra = sNombre[2];//Extrae el tercer caracter del string
if(Char.IsDigit(chLetra)){
Console.WriteLine(chLetra + " es un dígito");
}else{
EsMayuscula(chLetra);
EsMinuscula(chLetra);
}
}
public static void EsMayuscula(char chCaracter){
if(chCaracter >= 'A' && chCaracter <= 'Z'){
Console.WriteLine(chCaracter + " mayúscula");
}
}
public static void EsMinuscula(char chCaracter){
if(chCaracter >= 'a' && chCaracter <= 'z'){
Console.WriteLine(chCaracter + " minúscula");
}
}
Ismael Galan Cazares
}
En el ejemplo anterior se muestra la aplicación de la sentencia de selección if y el uso del
método IsDigit de la claseChar, también se muestra como determinar si un caracter
correponde a las letras mayúsculas o minúsculas.
Good Practice: nunca asigne valores a variables dentro de una condición que utiliza
operadores lógicos (&&,||,!), porque puede que nunca se le asigne el valor correspondiente a
la variable en caso de que una expresión anterior se evalue verdadera:
if(a == b || (c == (iValor = d))){}
En el ejemplo anterior, si la expresión a == b se evalua verdadera entonces la
variable iValor nunca contendrá el valor d.
Sentencia switch
La sentencia de selección switch tiene una expresión de control y los flujos de código alternos
son ejecutados dependiendo del valor constante asociado con esta expresión.
switch(expresion-de-control){
case expresion-contante:
sentencias;
break;
case expresion-contante:
goto case 2;
case expresion-contante:
goto default;
default:
sentencias;
}
Los tipos de datos permitidos para la expresión de control
son sbyte, byte, short, ushort, uint, long, ulong, char,string o un tipo enumeración
(enumeration).
¿Cómo funciona la sentencia de selección switch?
Se evalua la expresión de control
Si la expresión constante en las etiquetas case coincide con el valor evaluado en la expresión
de control, entonces las sentencias contenidas para ese caso son ejecutadas
Si la expresión constante en las etiquetas case no coincide con el valor evaluado en la
expresión de control, entonces el código contenido en el caso por default es ejecutado
Si la expresión constante en las etiquetas case no coincide con el valor evaluado en la
expresión de control y no existe un caso por default, entonces el control es transferido al final
del bloque switch
Ejemplo:
using System;
class SentenciaSwitch{
public static void Main(){
for(int i = 0; i <= 12; i++){
Mes(i);
}
}
public static void Mes(int iMes){
Ismael Galan Cazares
switch(iMes){
case 1:
Console.WriteLine("Enero");
break;
case 2:
Console.WriteLine("Febrero");
break;
case 3:
Console.WriteLine("Marzo");
break;
case 4:
Console.WriteLine("Abril");
break;
case 5:
Console.WriteLine("Mayo");
break;
case 6:
Console.WriteLine("Junio");
break;
case 7:
Console.WriteLine("Julio");
break;
case 8:
Console.WriteLine("Agosto");
break;
case 9:
Console.WriteLine("Septiembre");
break;
case 10:
Console.WriteLine("Octubre");
break;
case 11:
Console.WriteLine("Noviembre");
break;
case 12:
Console.WriteLine("Diciembre");
break;
default:
Console.WriteLine("Mes no válido");
break;
}
}
}
Es posible utilizar sentencias goto dentro del switch de la siguiente manera:
goto case expresion-contante
goto default
Ejemplo:
using System;
Ismael Galan Cazares
class SentenciaSwitch{
public static void Main(){
int iOpcion = 4;
Opcion(iOpcion);
iOpcion = 2;
Opcion(iOpcion);
iOpcion = 8;
Opcion(iOpcion);
iOpcion = 10;
Opcion(iOpcion);
}
public static void Opcion(int iValor){
switch(iValor){
case 2:
goto case 6;
case 4:
Console.WriteLine(" cuatro");
break;
case 6:
Console.WriteLine(" seis");
break;
case 8:
goto default;
case 10:
Console.WriteLine(" diez");
break;
default:
Console.WriteLine(" por defecto");
break;
}
}
}
Sentencias de Iteración (repetición)
Las Sentencias de Iteración (también conocidas como looping statements) son aquellas que
nos permiten ejecutar un bloque de código repetidamente mientras una condicíon específica
sea verdadera:
for
foreach
while
do
Sentencia for
La Sentencia for se utiliza cuando se conoce previamente cuantas veces ha de repetirse un
bloque de código. Este bloque se repetira mientras la condición evalue una expresión
booleana verdadera, no será posible evaluar otro tipo de expresión.
Sintaxis:
Ismael Galan Cazares
for(inicializador; condición; iterador)
Los componentes de la sentencia for: inicializador, condición, iterador, no son obligatorios.
Es posible salir de un ciclo for a través de las instrucciones:
break
goto
Ejemplo:
using System;
class Factorial{
public static void Main(string[] aArgs){
if(aArgs.Length == 0){
Console.WriteLine("Debe proporcionar un argumento, Ejemplo:
Factorial 5");
return;
}
long lFactorial = 1;
long lCalcular = Int64.Parse(aArgs[0]);
long lAux = 1;
for(lAux = 1; lAux <= lCalcular; lAux++){
lFactorial *= lAux;
//Test Line Console.WriteLine("{0}! * {1}", lAux, lFactorial);
}
Console.WriteLine("{0}! es {1}", lCalcular, lFactorial);
}
}
Sentencia foreach
La Sentencia foreach es un comando para enumerar los elementos de una colección.
foreach(Tipo indentificador in expresión){}
La variable de iteración es declarada por el Tipo, indentificador y expresión correspondiente a
la colección.
La variable de iteración representa el elemento de la colección para cada iteración.
El siguiente ejemplo muestra el uso de for:
using System;
class App{
public static void Main(string[] aArgs){
for(int i = 0; i < aArgs.Length; i++){
Console.WriteLine("Elemento " + i + " = " + aArgs[i]);
}
}
}
El ejemplo anterior implementado con foreach:
using System;
class App{
public static void Main(string[] aArgs){
Ismael Galan Cazares
foreach(String s in aArgs){
Console.WriteLine(s);
}
}
}
No es posible asignar un nuevo valor a la variable de iteración. No se puede pasar la variable
de iteración como un parámetro ref o out.
Para que una clase soporte la sentencia foreach, la clase debe soportar un método con la
firma GetEnumerator() y la estructura, clase o interface que regresa debe tener un método
público MoveNext y una propiedad pública Current.
En el siguiente ejemplo el método GetEnvironmentVariables() regresa una interfaz de
tipo IDictionary. Es posible acceder a las colecciones Keys y Values de la interfaz IDictionary:
using System;
using System.Collections;
class SentenciaForEach{
public static void Main(){
IDictionary VarsAmb = Environment.GetEnvironmentVariables();
Console.WriteLine("Existen {0} variables de ambiente declaradas",
VarsAmb.Keys.Count);
foreach(String strIterador in VarsAmb.Keys){
Console.WriteLine("{0} = {1}", strIterador,
VarsAmb[strIterador].ToString());
}
}
}
Nota, es necesario tener una precaución extra al decidir el tipo de variable de iteración,
porque un tipo equivocado no puede ser detectado por el compilador, pero si detectado en
tiempo de ejecución y causar una excepción.
Sentencia while
La Sentencia while se utiliza cuando no se conoce previamente cuantas veces ha de repetirse
un bloque de código, por lo que puede ejecutarse 0 o más veces. Este bloque se repetira
mientras la condición evalue una expresión booleana verdadera, no será posible evaluar otro
tipo de expresión.
while(condicional){}
Ejemplo:
using System;
using System.IO;
class SentenciaWhile{
public static void Main(){
if(!File.Exists("test.html")){
Console.WriteLine("El archivo test.html no existe");
return;
}
StreamReader SR = File.OpenText("test.html");
String strLinea = null;
Ismael Galan Cazares
while(null != (strLinea = SR.ReadLine())){
Console.WriteLine(strLinea);
}
SR.Close();
}
}
Es posible utilizar la sentencia break para salir del ciclo o continue para saltar una iteración.
Sentencia do
La diferencia entre la sentencia while y do es que do se evalua después de su primer
iteración, por lo que al menos siempre se ejecuta una vez:
do{
sentencias;
}while(condición);
Es posible salir de un ciclo do a través de la sentencia break y es posible saltar una iteración
utilizando la sentenciacontinue
El siguiente ejemplo le la entrada de la consola toma el primer caracter leido, lo convierte en
un Tipo double y suma su valor mientras la entrada sea 's' o hasta que la entrada sea 'n'.
using System;
class Consola{
public static void Main(){
Consola LeerDatos = new Consola();
LeerDatos.Run();
}
public void Run(){
char chContinuar = 's';
string strDatos;
double dSuma = 0;
do{
Console.Write("Proporcione un número: ");
strDatos = Console.ReadLine();
dSuma += Double.Parse(strDatos);
Console.Write("¿Continuar s/n?");
strDatos = Console.ReadLine();
chContinuar = strDatos[0];
if(chContinuar == 'n') break;
}while(chContinuar == 's');
Console.WriteLine("La suma de los números es: " + dSuma);
}
}
Sentencias de Salto
Las Sentencias de Salto como break, continue, goto y return sirven para ir de una sentencia a
otra
break
Ismael Galan Cazares
La Sentencia break es utilizada para salir de la iteración en curso o sentencia switch y
continuar con la ejecución después de esa sentencia.
continue
La Sentencia continue salta todas las sentencias siguientes en la iteración en curso y
entonces continua la ejecución en la sentencia de iteración (siguiente iteración).
goto
La Sentencia goto puede ser utilizada para saltar directamente a una etiqueta. Una
sentencia goto no puede ser utilizada para saltar adentro de un bloque de sentencias. Su uso
podría ser empleado en sentencias switch o para transferir el control fuera de un loop
anidado.
Nota, como buena práctica no se recomienda el uso de goto.
return
La Sentencia return regresa a la función invocadora y opcionalmente retorna un valor.
Asignación Definitiva
Las reglas de Asignación definitiva previenen la observación del valor de una variable no
asignada, ya que C# no permite utilizar variables que no han sido inicializadas, así como
también no pueden realizarse operaciones con variables de clase que no han sido
inicializadas.
Puede accederse al elemento de un arreglo aún si no ha sido inicializado, ya que el
compilador no puede rastrear la asignación definitiva en todas las situcaciones.
Precedencia de Operadores
Cuando una expresión contiene múltiples operadores, la precedencia de operadores controla
el orden en el cual los elementos de la expresión son evaluados.
Categoría Operador
Primary (x), x.y, f(x), a[x], x++, x--, new, typeof, sizeof, checked, unchecked
Unary +, -, !, ~, ++x, --x, (T)x
Multiplicative *, /, %
Additive +, -
Shift <<, >>
Relational <, >, <=, >=, is
Equality ==, !=
Logical AND &
Logical XOR ^
Logical OR |
Conditional AND &&
Conditional OR ||
Conditional ?:
Assignment =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
typeof
El operador typeof regresa el tipo del objeto, el cual es una instancia de la clase System.Type
Ismael Galan Cazares
Una instancia ya existente puede obtener el tipo de objeto con el método de la
instancia GetType().
is
El operador is es utilizado para determinar cuando una referencia a un objeto puede ser
converitda a un tipo específico o interface.
El operador as es muy similar al operador is, pero en vez de determinar cuando un objeto es
un tipo específico ointerface, as también realiza la conversión explicita a ese tipo o interface y
si no lo puede convertir el operador regresa null.
Utilizar as es más eficiente que utilizar is, porque as sólo necesita checar el tipo del objeto
una vez e is checa el tipo cuando el operador es utilizado y lo checa otra vez cuando la
conversión se realiza.
Utilizando is
if(UnObjeto is UnTipo){
UnTipo ut = (UnTipo) UnObjeto;
}
Utilizando as
UnTipo ut = UnObjeto as UnTipo;
if(ut != null){
sentencias;
}
Conversiones
En C# las conversiones se dividen en conversiones explícitas y conversiones implícitas que
son aquellas que podrían siempre ocurrir:
//conversiones implícitas
sbyte a = 55;
short b = a;
int c = b;
long d = c;
//conversiones explícitas
c = (int) d;
b = (short) c;
a = (sbyte) b;
A continuación se presenta la jerarquía de conversión en C##
Manejo de Excepciones
Las excepciones son el método fundamental de manejo de condiciones de error.
Ejemplo:
using System;
class DivisionCero{
public static void Main(){
int iA = 33;
int iB = 0;
try{
Ismael Galan Cazares
//Sentencia que puede lanzar una excepción
Console.WriteLine("{0}/{1} = {2}", iA ,iB, iA/iB);
}catch(Exception e){
//Manejo de la excepción
Console.WriteLine("La operación {0}/{1} genero la excepcion : {2}", iA, iB,
e);
}
Console.WriteLine("Continua la ejecución del código...");
}
}
El ejemplo encierra el bloque de código que podría lanzar una excepción con try. En caso de
generarse una excepción el runtime .NET detiene la ejecución del código y busca el
bloque try en el cual la excepción tuvo lugar, entonces busca si este bloque tiene relacionado
un bloque catch, puede ser que encuentre más de un bloque catchrelacionado al
bloque try que genero la excepción, por lo que se determina que bloque catch es el que mejor
y ejecuta el código que contiene.
El compilador de C# puede manejar silenciosamente situaciones que podrían producir un
error sin notificarnos explicitamente de ello, por ejemplo una situación como un overflow que
es cuando el cálculo de una operación excede el rango válido de resultados posibles para el
tipo de dato.
El caso del código para calcular un factorial, el compilador no prodruce una advertencia, pero
si trata de obtener elfactorial de 2000 dara por resultado 0, el compilador actuo en modo
silencioso porque por default el compilador tiene deshabilitada la opción de chequeo
de overflow.
Es posible cambiar el comportamiento de chequeo de overflow utilizando un switch al
compilar.
Jerarquía de Excepciones
Todas las excepciones derivan de la clase Exception, la cual es parte del lenguaje común en
tiempo de ejecución (CLR), donde la propiedad catch determina por coincidencia el tipo de
excepción a el nombre de la excepción generada. Un bloque catch con una coincidencia
especifica hacen más general la excepción:
using System;
class ExceptionDivision0{
public static void Main(){
int iA = 33;
int iB = 0;
try{
Console.WriteLine("{0}/{1} = {2}", iA ,iB, iA/iB);
}catch(DivideByZeroException){
Console.WriteLine("Se genero la excepcion :
DivideByZeroException");
}
Console.WriteLine("Continua la ejecución del código...");
}
}
En este ejemplo el bloque catch que atrapa la excepción DivideByZeroException es una
coincidencia más específica, por lo que es la única que será ejecutada, pero si además de
Ismael Galan Cazares
escribir el catch para DivideByZeroException escribe elcatch para Exception, el compilador le
notificara que existe una excepción que atrapa todas las excepciones y esto es
porque Exception ocupa la cima de la jerarquía de todas las excepciones.
Caller Confuse
La segunda forma es atrapar la excepción y tratar de hacer acciones que dejen la operación
como estaba hasta antes de generarse la excepción y entonces relanzar la excepción, esto
usualmente es lo menos que se esperaria del manejo de excepciones ya que un objeto
debería siempre mantener un estado válido después de generarse una excepción.
Se llama Caller Confuse, porque después de generase una excepción, el caller con
frecuencia tiene poca información respecto al entendimiento de los detalles de la excepción o
como podría ser solucionada.
Caller Inform
Las tercer forma Caller Inform agrega información que es devuelta al usuario, la excepción
atrapada es envuelta en una excepción que tiene información adicional:
using System;
class ExcDivZeroInf{
public static void Main(){
int iA = 33;
int iB = 0;
try{
Console.WriteLine("{0}/{1} = {2}", iA ,iB, iA/iB);
}catch(DivideByZeroException e){
Console.WriteLine("Se genero la excepcion :
DivideByZeroException");
throw(new DivideByZeroException("Información
adicional...", e));
}
Console.WriteLine("Continua la ejecución del código...");
}
}
Chequeo de Overflow
Si requerimos controlar el chequeo de overflow para la aplicación completa, el compilador de
C# debe establecerse como checked. Por default el compilador tiene deshabilitada la opción
de chequeo.
Para indicar explicitamente que el compilador cheque el overflow escriba:
csc Factorial.cs /checked+
Ismael Galan Cazares
Una vez que se compilo de con la opción de chequeo de overflow habilitado, al intentar
obtener el factorial de 2000de presenta la ventana Just-In-Time-debbuging notificandonos que
ocurrio una excepción en Factorial.exe:
System.OverflowException
Este tipo de situaciones es posible atraparlas y manejarlas a través de las excepciones que
se producen.
Chequeo programático de Overflow
Existe otra opción si es que no deseamos activar el Chequeo de Overflow para la aplicación
completa y habilitar sólamente partes especificas de código, para ello se utiliza la
sentencia checked:
using System;
class FactorialChecked{
public static void Main(string[] aArgs){
if(aArgs.Length == 0){
Console.WriteLine("Debe proporcionar un argumento, Ejemplo:
Factorial 5");
return;
}
long lFactorial = 1;
long lCalcular = Int64.Parse(aArgs[0]);
long lAux = 1;
for(lAux = 1; lAux <= lCalcular; lAux++){
checked{lFactorial *= lAux;} //Habilitar chequeo de overflow
//Test Line Console.WriteLine("{0}! * {1}", lAux, lFactorial);
}
Console.WriteLine("{0}! es {1}", lCalcular, lFactorial);
}
}
También es posible hacer el caso contrario, es decir, indicar que no se realice el chequeo
de overflow para partes especificas de código, para ello se utiliza la sentencia:
unchecked{sentencias;}
Sentencias para el Manejo de Excepciones
Es posible atrapar, manejar y limpiar las excepciones que se producen utilizando las
sentencias siguientes:
try - catch
try - finally
try - catch - finally
try - catch
Para evitar que se muestre el mensaje que indica que una excepción ocurrio, es
necesario atrapar la excepción y lo mejor de todo es que continue la ejecución del programa,
para ello se utiliza try y catch.
Ismael Galan Cazares
try contiene el código que quizá pueda lanzar una excepción y catch maneja la excepción si
esta ocurre:
try{
//sentencias que pueden lanzar una excepción
}catch(nombreExcepción){
//manejo de la excepción
}
El siguiente ejemplo maneja la excepción FileNotFoundException que se produce cuando se
intenta manipular un archivo que no existe, si esto ocurre se presenta un mensaje que
muestra el nombre del archivo que se intento manipular y no se encontro a través de una
propiedad pública de la excepción llamada FileName.
using System;
using System.IO;
class SentenciaWhile{
public static void Main(){
try{
StreamReader SR = File.OpenText("test.html");
String strLinea = null;
while(null != (strLinea = SR.ReadLine())){
Console.WriteLine(strLinea);
}
SR.Close();
}catch(FileNotFoundException e){//En caso de que el archivo no
exista
Console.WriteLine("No se encontro el archivo : " +
e.FileName);
return;
}
}
}
try - finally
Es posible limpiar el manejo de errores utilizando try y el constructor finally, sin eliminar el
mensaje de error, pero el código contenido en el bloque finally es ejecutado aún después de
ocurrir una excepción.
El siguiente código maneja una variable booleana que indica si se produjo un error,
simplemente poniendola dentro del bloque try, si el código contenido fué ejecutado la variable
booleana es false lo cual indica que no ocurrieron excepciones, si el bloque no se ejecuto la
variable booleana mantiene su valor inicial lo cual significa que si ocurrieron excepciones y
entonces se ejecuta el bloque Finally el cual evalua el valor de la variable booleana y
presenta la indicación correspondiente.
using System;
using System.IO;
class SentenciaTryFinally{
public static void Main(){
bool bExcepcion = true;
try{
Ismael Galan Cazares
StreamReader SR = File.OpenText("test.html");
String strLinea = null;
while(null != (strLinea = SR.ReadLine())){
Console.WriteLine(strLinea);
}
SR.Close();
bExcepcion = false;
}
finally{
if(bExcepcion){
Console.WriteLine(">>> No se encontro el
archivo");
}else{
Console.WriteLine(">>> No ocurrieron
excepciones");
}
}
}
}
Note que en caso de no existir el archivo se produce una excepción y se presenta el mensaje
que indica que ha ocurrido una excepción pero también fué ejecutado el bloque finally, el
código que contiene el bloque finallysiempre es ejecutado ocurra o no una excepción.
Puede emplear la sentencia finally para reestablecer los valores previos a la generación de la
excepción.
try - catch - finally
Combinar try para controlar el código que puede lanzar excepciones, atrapar la excepción
con catch y llevar acabo instrucciones necesarias con finally hacen una mejor solución
cuando ocurren las excepciones.
Es posible utilizar una sentencia catch por cualquier excepción que pudiera ocurrir, es decir,
tener más de un bloquecatch, pero es necesario conocer la jerarquía de las excepciones
porque puede ocurrir que un bloque previo catchsea más general y contenga todas las
excepciones lo cual produciria un error.
using System;
using System.IO;
class SentenciaTryCatchFinally{
public static void Main(){
bool bExcepcion = true;
bool bModificacion = false;
try{
bModificacion = true;
StreamReader SR = File.OpenText("test.htmlX");
String strLinea = null;
while(null != (strLinea = SR.ReadLine())){
Console.WriteLine(strLinea);
}
SR.Close();
bExcepcion = false;
Ismael Galan Cazares
}catch(FileNotFoundException e){//En caso de que el archivo no exista
Console.WriteLine("No se encontro el archivo : " + e.FileName);
return;
}
finally{
if(bExcepcion){
bModificacion = false;//Valor antes de generarse la
excepción
if(!bModificacion){
Console.WriteLine("Entro en modo modificación, _
pero las modificaciones no se realizaron");
}
Console.WriteLine("Causa : No se encontro el archivo");
}else{
Console.WriteLine("No ocurrieron excepciones");
}
}
}
}
Lanzamiento de Excepciones
Para atrapar una excepción con la sentencia catch primero debe generarse la excepción, pero
es posible que a través de codigo se lanze o invoque una excepción:
throw new NombreExcepcion(excepcion);
El poder lanzar o invocar una excepción es util cuando no se ha contemplado cierto escenario
o para nuevos escenarios, al crear una clase podrian crearse también excepciones propias de
esta clase.
A continuación se presenta una tabla que contiene las excepciones estándar que provee
el runtime:
Tipo Descripción
Exception Clase base para todas los objetos exception
Clase base para todos los errores generados en
SystemException
tiempo de ejecución
Lanzada en tiempo de ejecución cuando el índice
IndexOutRangeException
de un arreglo está fuera de rango
Disparada en tiempo de ejecución cuando un
NullreferenceException
objeto null es referenciado
Lanzada por ciertos métodos cuando invocan a
InvalidOperationException métodos que son inválidos para el estado de los
objetos actuales
Clase base de todos los argumentos de las
ArgumentException
excepciones
Lanzada por un método, en caso de que un
ArgumentNullException
argumento sea null cuando no sea permitido
Lanzada por un método cuando un argumento no
ArgumentOutOfRangeException
está en el rango permitido
Ismael Galan Cazares
Clase base para excepciones que son originadas
InteropException
u ocurren en ambientes fuera del CLR
Excepción que contiene información HRESULT
ComException
COM
Excepción que encapsula información del manejo
SEHException
de excepciones destructurada Win32
Relanzamiento de Excepciones
El siguiente código muestra como es posible atrapar una excepción, manejarla y se volverla a
invocar:
using System;
class FactorialCheckedReThrow{
public static void Main(string[] aArgs){
if(aArgs.Length == 0){
Console.WriteLine("Debe proporcionar un argumento, Ejemplo:
Factorial 5");
return;
}
long lFactorial = 1;
long lCalcular = Int64.Parse(aArgs[0]);
long lAux = 1;
try{
checked{ //Habilitar chequeo de overflow
for(lAux = 1; lAux <= lCalcular; lAux++){
lFactorial *= lAux;
//Test Line Console.WriteLine("{0}! * {1}", lAux, lFactorial);
}
}
}catch(OverflowException){
Console.WriteLine("El factorial {0}! causo una excepción", lCalcular);
throw;
}
Console.WriteLine("{0}! es {1}", lCalcular, lFactorial);
}
}
class AplicClsPersona{
public static void Main(){
ClsPersona Empleado = new ClsPersona();
Empleado.Sueldo = 33;
Console.WriteLine("Edad : " + Empleado.Sueldo);
using System;
namespace informatique.com.mx{
public class iPersona{
private int iSueldo;
public int Sueldo{
get{return iSueldo;}
set{iSueldo = value;}
}
class iAplicClsPersona{
public static void Main(){
iPersona Empleado = new iPersona();
Empleado.Sueldo = 33;
Console.WriteLine("Edad : " + Empleado.Sueldo);
class iAplicClsPersonaAbs{
public static void Main(){
informatique.com.mx.iPersona Empleado = new
informatique.com.mx.iPersona();
Empleado.Sueldo = 33;
Console.WriteLine("Edad : " + Empleado.Sueldo);
namespace informatique.com.mx{
class iVehiculo{
private int iRueda;
private int iPuerta;
private int iVentana;
private int iHelice;
private int iMotor;
private int iAsiento;
private string sTipo;//Aereo, anfibio, terrestre, espacial
//Constructor
public iVehiculo(int Rueda, int Puerta, int Ventana, _
int Helice, int Motor, int Asiento, string Tipo){
iRueda = Rueda;
iPuerta = Puerta;
iVentana = Ventana;
iHelice = Helice;
iMotor = Motor;
iAsiento = Asiento;
sTipo = Tipo;
}
Namespace y Ensambles
Un objeto puede ser utilizado desde un archivo fuente C# sólo si ese objeto puede ser
localizado por el compilador C#, por default el compilador sólo abre el ensamble conocido
como mscorlib.dll, el cual contiene las funciones principales para el CLR.
Para referenciar objetos localizados en otros ensambles, el nombre del archivo de ensamble
debe ser pasado al compilador, esto es posible utilizando un switch al compilar:
/r:nombreEnsamble
Es así como se crea un correlación entre el namespace de un objeto y el nombre del
ensamble en el cual reside, por ejemplo los tipos de namespace en el System.Net residen en
el ensamble System.Net.dll
Compilación Condicional
La Compilación Condicional permite excluir o incluir código, en C# existen dos formas de
hacer esto:
Uso del Preprocesador
Atributo conditional
Uso del Preprocesador
C# el compilador emula el preprocesador, ya que no hay un preprocesador por separado.
El compilador de C# no soporta macros, en cambio soporta las siguientes directivas:
Definición de símbolos
Exclusión de código basado en símbolos
Lanzamiento de errores y advertencias
Definición de símbolos
La Definición de símbolos es utilizada para excluir o incluir código dependiendo si son o no
son definidos ciertos símbolos.
Una forma para definir un símbolo es utilizando la directiva #define en un archivo fuente C#,
está definición deberá realizarse antes de cualquier otra sentencia:
#define DEBUG
#define RELEASE
En este caso #define DEBUG, define un símbolo DEBUG y su ámbito es el archivo donde es
definido, al igual que el símbolo RELEASE.
Ismael Galan Cazares
Otra forma utilizada para definir símbolos es usar el compilador y es de ámbito global para
todos los archivos:
csc /define:DEBUG nombreArchivo.cs
Si se requiere definir múltiples símbolos utilizando el compilador, es necesario separar cada
símbolo con una coma (,)
csc /define:DEBUG,RELEASE,DEMOVERSION nombreArchivo.cs
Si el código fuente incluye directivas de definición de símbolos, es posible deshabilitarlas
utilizando la directiva #undefcuyo ámbito también corresponde al archivo donde es definida:
#undef DEBUG
Exclusión de código basado en símbolos
El principal propósito de los símbolos es la inclusión o exclusión condicional del código,
basado sobre si son o no son definidos los símbolos.
El siguiente código no define símbolos en el archivo fuente:
.
sentencia;
.
#if NOMBRE_SIMBOLO
sentencia;
#else
sentencia;
#endif
.
Pero es posible definir o no los símbolos al compilar la aplicación:
csc /define:NOMBRE_SIMBOLO NombreAplicacion.cs
Las directivas del preprocesador emulado utilizadas para evaluar el símbolo
son: #if, #else y #endif las cuales actuan como su contraparte, la sentencia condicional if C#,
es posible utilizar &&, || y !:
//#define SIMBOLO_A
#define SIMBOLO_B
#define SIMBOLO_C
#if SIMBOLO_A
#undef SIMBOLO_C
#endif
using System;
class NombreClase{
public static void Main(){
#if SIMBOLO_A
.
#elif SIMBOLO_B && SIMBOLO_C
.
#else
.
#endif
}
Ismael Galan Cazares
}
Lanzamiento de errores y advertencias
Existe otro uso de las directivas del preprocesador para lanzar errores del compilador o
advertencias dependiendo de ciertos símbolos, para ello se utilizan las directivas:
#warning
#error
Por ejemplo
#if SIMBOLO_ERROR
#error Presentar el mensaje de error correspondiente
#endif
.
#if SIMBOLO_WARNING
#error Presentar el mensaje de advertencia correspondiente
#endif
Atributo conditional
Un atributo conditional evalua la invocación de una función cuando sierto símbolo es definido
y evalua a nada cuando una versión liberada es construida.
Un atributo conditional debe tener un tipo void de regreso, cualquier otro tipo de regreso no es
permitido.
.
[conditional("NOMBRE_SIMBOLO")]
método A
[conditional("NOMBRE_SIMBOLO")]
método B
.
Comentarios de Documentación en XML
Es posible construir automáticamente la Documentación utilizando comentarios en el código.
La salida que es generada por el compilador es XML puro y puede ser utilizada como entrada
para la documentación de un componente.
La documentación es una parte extremadamente importante del software y en especial de los
componentes por ser utilizados por otros desarrolladores.
Elementos XML
Nota: todo comentario de documentación son tags XML (eXtensible Markup Language).
Para describir un elemento se utiliza el tag <summary></summary>, el cual se escribe en el
código fuente anteponiendo tres diagonales que son indicativo de un comentario de
documentación:
///<summary>Descripción...</summary>
En caso de requerir más una línea para el comentario de documentación utilice el tag:
///<para>
///.
///.
///</para>
En caso de requerir una referencia a otros elementos utilice el tag:
Ismael Galan Cazares
///<see cref="NombreElemento"/>
En caso de requerir una referencia a un tópico de interes utilice:
///<seealso cref="System.Net"/>
Un tag contrario a summary, para un volumen mayor de documentación es:
///<remarks>
Es posible incluir listas utilizando los tags :
///<list type="bullet">
/// <item>Constructor
/// <see cref="Constructor()"/>
/// .
/// </code>
/// .
///</example>
Para describir los parámetros de regreso utilice:
///<returns>
/// Descripción : Clase que define lo que es y puede hacer una persona
///
///
Ismael Galan Cazares
class Persona{
///La propiedad iSueldo se emplea para obtener y asignar el valor del sueldo de una
persona
private int iSueldo;
public int Sueldo{
get{return iSueldo;}
set{iSueldo = value;}
}
class AplicPersona{
public static void Main(){
Persona Empleado = new Persona();
Empleado.Sueldo = 33;
Console.WriteLine("Edad : " + Empleado.Sueldo);
El compilador de C# por default siempre crea componentes .NET para los ejecutables.
Un Componente .NET es la unidad fundamental reusable y compartida en el CLR, un
componente .NET también es limitante para asegurar la seguridad, permite la distribución de
clases y resolución de tipos. Una aplicación puede contener múltiples componentes .NET
Un componente .NET contiene cuatro partes referentes al número de versión llamado versión
compatible:
major version.minor version.build number.revision
La versión compatible es utilizada por el class loader para decidir cual es la versión del
componente .NET que cargará, en caso de existir diferentes versiones.
Se considera una versión incompatible cuando major version.minor version es diferente de la
versión solicitada.
Se podría considerar una versión compatible cuando el build number es diferente a la versión
solicitada.
Se considera una QFE (Quick Fix Engineering) compatible cuando revision es diferente.
Además del número de versión (versión compatible) se almacena otro número en el
componente llamado informational version, el cual es considerado sólo para propósitos de
documentación y su contenido podría ser SuperControl Build 1880, el contenido representa
algo humano y no para la máquina.
Para indicar al compilador que agregue un version information al componente se utiliza
el switch:
csc /a.version:1.0.1.0 /t:library /out:nombreArchivoFuente.dll nombreArchivoFuente.cs
El switch /a.version crea una biblioteca con el version information 1.0.1.0, esto puede
comprobarse en las propiedades del archivo.dll.
Componentes .NET Privados
Al ligar una aplicación a un componente .NET utilizando
el switch /reference:nombreBiblioteca la información de dependencia registra las herramientas
de desarrollo, incluyendo la versión de las bibliotecas ligadas, este registro se hace en un
manifiesto y el CLR los números de versión contenidos para cargar la versión apropiada de
un componente .NET dependiente en tiempo de ejecución.
Cualquier componente .NET que reside en el directorio de la aplicación es
considerado privado y no es version-checked
[HKEY_CLASSES_ROOTinformatique.com.mx.iPersona]
@="informatique.com.mx.iPersona"
[HKEY_CLASSES_ROOTinformatique.com.mx.iPersonaCLSID]
@="{37504224-213A-3943-845A-E572758E4174}"
[HKEY_CLASSES_ROOTCLSID{37504224-213A-3943-845A-E572758E4174}]
@="informatique.com.mx.iPersona"
[HKEY_CLASSES_ROOTCLSID{37504224-213A-3943-845A-
E572758E4174}InprocServer32]
@="mscoree.dll"
"ThreadingModel"="Both"
"Class"="informatique.com.mx.iPersona"
"Assembly"="iPersona, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
"RuntimeVersion"="v1.1.4322"
[HKEY_CLASSES_ROOTCLSID{37504224-213A-3943-845A-
E572758E4174}InprocServer32.0.0.0]
"Class"="informatique.com.mx.iPersona"
"Assembly"="iPersona, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
"RuntimeVersion"="v1.1.4322"
[HKEY_CLASSES_ROOTCLSID{37504224-213A-3943-845A-E572758E4174}ProgId]
@="informatique.com.mx.iPersona"
[HKEY_CLASSES_ROOTCLSID{37504224-213A-3943-845A-
E572758E4174}Implemented Categories_
{62C8FE65-4EBB-45E7-B440-6E39B2CDBF29}]
El motor de ejecución mscoree.dll es invocado cuando una instancia del objeto (componente
registrado) es requerida, más no la biblioteca por si sóla.
El motor de ejecución es responsable de proveer la CCW (COM Callable Wrapper) al objeto.
Una vez registrado el componente puede ser utilizado por lenguajes de programación que
soporten esta vinculación, también es posible emplear la utileria tlbexp la cual permite generar
una biblioteca tipo para el componente .NET
tlbexp nombreComponente.dll /out:nombreBiblioteca.tlb
Ismael Galan Cazares
Esta biblioteca tipo puede ser utilizada en lenguajes de programación que soporten esta
vinculación.
El Componente .NET y todas las clases ya están registradas y se tiene una biblioteca tipo
para ambientes
Uso de Componentes COM en Componentes .NET
Los Clientes .NET pueden interoperar con objetos clásicos COM, para que un componente
utilise COM debe tener una biblioteca tipo para el CLR esto se traduce a los metadatos que
son almacenados con los tipos.
Para que sea posible invocar un componente COM desde un objeto .NET, es necesario
envolver el código unsafe, cuando la envoltura o wrapper es invocada, un RCW (Runtime
Callable Wrapper) es construido desde la información de la biblioteca tipo. Una herramienta
genera el código wrapper basado en la información obtenida de la biblioteca tipo.
La herramienta a utilizar es tlimp (type library import):
tlbimp nombreComponente.dll /out:nombreBiblioteca.dll
Esta herramienta importa el tipo de biblioteca COM, crea y almacena un RCW que puede ser
utilizado en el CLR en el archivo nombreBiblioteca.dll.
Para ver los metadatos para el RCW utilice ildasm.exe, así podrá distinguir el nombre de la
clase que fué generada para el objeto COM original, esta información es una ayuda para
poder escribir el objeto .NET que utiliza el componente COM.
Invocación de Servicios
Se se requiere invocar una función provista por el WIN32 o alguna DLL unmanaged, se
utilizan los Servicios de invocación de plataforma (PInvoke).
PInvoke se encarga de ejecutar la función correcta y también de la colocación de los
argumentos para y desde sus contrapartes unmanaged.
Simplemente utilice el atributo sysimport al definir un método externo:
[sysimport(
dll = nombreDLL,
name = puntoEntrada,
cgarset = conjuntoCaracteres
]
Unicamente el argumento dll es obligatorio y los demás opcionales, aunque si se omite el
atributo name, el nombre de la función de implementación externa debe coincidir con el
nombre del método estático interno.
Código No Seguro
Si requiere de escribir código no seguro, deberá utilizar dos palabras reservadas:
unsafe, denota un contexto no seguro, cuando requiera realizar acciones no seguras se debe
envolver el código correspondiente con este modificador, el cual puede ser aplicado a
constructores, métodos y propiedades.
fixed, al declarar una variable con este modificador previene al recolector de basura de
reacomodarlo.
Debugging
El SDK .NET incorpora dos herramientas de depuración de errores:
CORDBG, depurador de línea de comando
Ismael Galan Cazares
SDK, depurador UI
El depurador SDK no soporta la depuración de código nativo, sólo es posible depurar código
administrado.
No es posible la depuración de una máquina remota
Window register y disassembly aunque se implementan no son funcionales
Antes de depurar el código de una aplicación es necesario crear una versión depurada, la
cual contiene información de depuración no optimizada y un archivo adicional PDB (program
database) para depuración y un estado de información del proyecto es creado.
Para crear una versión depurada son necesarios dos switches al compilar:
csc /optimize- /debug+ nombreArchivoFuente.cs
Estos comandos utilizados al compilar crea dos archivos:
nombreArchivoFuente.exe y
nombreArchivoFuente.pdb
Para configurar la sesión de depuración es necesario seleccionar la aplicación que se desea
depurar y comenzar el depurador SDK ejecutando dbgurt.exe, el cual esta almacenado en el
directorio ProgramFilesNGWSSDKGuiDebug
Una vez que la aplicación depuradora comienza se selecciona el programa que se desea
depurar en donde será también posible especificar argumentos en la línea de comandos,
mismos que son pasados a la aplicación cuando la sesión de depuración inicia.
Es posible establecer diferentes tipos de breakpoint:
File, interrumpe la ejecución cuando una ubicación específica en el archivo fuente se alcanza
Data, interrumpe la ejecución cuando una variable cambia a un valor especifico
Function, interrumpe la ejecución en una ubicación específica dentro de una función
específica
Address, interrumpe la ejecución cuando una dirección de memoria específica se alcanza
Una vez que se interrumpe la ejecución, es posible continuarla utilizando los comandos:
Step Over
Step Into
Step Out
Run to Cursor
Es posible modificar valores de variables simplemente dando doble clic en la columna valor
de aquella variable que se desea modificar, así como también es posible observar las
variables, para ello es necesario dar clic en la columna nombre y escribir el nombre de las
variables que se desean observar.
Las excepciones son un punto excelente de comienzo para una sesión de depuración,
cuando una excepción no es controlada apropiadamente por el código se muestra la ventana
de depuración llamada JIT just in time.
Seguridad
Hoy en día el código viene de distintas fuentes, no solo el que es instalado via un setup por el
servidor, también puede ser instalado via una página web o correo electrónico.
.NET plantea dos posibles soluciones para la seguridad:
Seguridad de acceso al código
Seguridad basada en roles
Ismael Galan Cazares
Seguridad de acceso al código
La Seguridad de acceso al código controla el acceso protegiendo los recursos y operaciones.
El código es confiable en distintos grados, dependiendo su identidad y de donde viene.
Funciones de la seguridad de acceso al código:
El administrador puede definir las políticas de seguridad asignando ciertos permisos para
definir grupos de código.
El código puede requerir que quien invoca (caller) debe tener permisos especificos
La ejecución de código está restringido en tiempo de ejecución, realizando chequeos para
verificar que los permisos otorgados a quien invoca (caller) coincidan con el permiso requerido
para la operación.
El código puede requerir los permisos necesarios de ejecución y los permisos que podrían ser
utilizados, es decir, verificar los permisos indispensables.
Los permisos son definidos para representar ciertos derechos para acceder a distintos
recursos del sistema.
La seguridad de acceso al código otorga permisos cuando un componente es cargado, este
otorgamiento esta basado en el requerimiento del código, definiendo operaciones permitidas
por las políticas de seguridad.
Existen dos puntos importantes de la seguridad de acceso al código, donde el requerimiento
mínimo para beneficiarse de la seguridad de acceso al código es para generar un código de
tipo seguro.
Verificar el tipo de seguridad del código administrado, el runtime forza la restricción de
seguridad del código administrado, para determinar cuando el código es seguro. Es
importante que el runtime sea capaz de checar los permisos de quien invoca de manera
confiable, evadiendo hoyos de seguridad que son creados cuando código menos confiable
invoca código altamente confiable, para ello el código administrado debe ser verificado como
tipo seguro. Cada acceso a tipos se realiza sólo en un sentido permitido.
El código C# es de tipo no seguro, pero el IL y los metadatos son inspeccionados antes de
dar el visto bueno del tipo de seguridad del código.
Permisos que son requeridos por el código, el beneficio de activar el requerimiento de
permisos es conocer cuando se tiene el permiso apropiado para realizar acciones y cuando
no. Es posible prevenir al código de el otorgamiento de permisos adicionales que no son
necesarios. Los permisos mínimos garantizan que el código se ejecute con los recursos justos
cuando el código requiere de muchos permisos sin que falle.
La categoria de los permisos es:
Required, permiso que el código necesita para ejecutarse correctamente.
Optional, permisos que no son obligatorios para la ejecución correcta del código, pero que
podría ser bueno tenerlos.
Refused, permiso que se necesita para que el código nunca se otorgue, aunque la política de
seguridad lo permita, se utiliza para restringir vulnerabilidades potenciales.
Permisos Estándar
Los Permisos Estándar son:
EnvironmentPermission, clase que define permisos de acceso a variables de ambiente, donde
son posibles dos tipos de acceso, de sólo lectura y escritura al valor de una variable de
Ismael Galan Cazares
ambiente. El tipo de acceso escritura incluye permisos para crear y eliminar variables de
ambiente.
FileDialogPermission, controla el acceso a archivos basado en el sistema de archivos de
diálogo. El usuario debe autorizar el acceso al archivo via el cuadro de diálogo.
FileIOPermission, es posible especificar tres tipos de acceso a archivos de entrada y
salida: lectura, escritura yadición, el acceso lectura incluye acceder a la información del
archivo, el tipo escritura incluye eliminar y sobreescribir, el acceso adición no permite leer
otros bits.
IsolatedStoragePermission, controla el acceso a almacenamientos aislados, este acceso
permite utilización, tamaño de almacenamiento, tiempo de expiración y almacenamiento de
datos.
ReflectionPermission, controla la capacidad de leer el tipo de información de tipos miembro no
públicos y controla el uso de Reflection.Emit
RegistryPermission, Control de lectura, creación y escritura en el registry
SecurityPermission, colección de permisos simples que son utilizados por el sistema de
seguridad, es posible controlar la ejecución de código, sobreescritura de chequeos de
seguridad, invocación de código no administrado, serialización, etc.
UIPermission, define el acceso a varios aspectos de la interfaz de usuario, incluyendo el uso
de windows, acceso a eventos y uso del portapapeles.
Permisos Identidad
Los Permisos Identidad son:
PubilsherIdentityPermission, la firma de componentes .NET provee resistencia de software
publisher
StrongNameIdentityPermission, define el nombre del componente criptograficamente, ya que
el nombre compromete la identidad.
ZoneIdentityPermission, define la zona de donde el código tiene origen, un URL puede
pertenecer a sólo una zona
SiteIdentityPermission, permisos derivados basados en el sitio web de donde el código tiene
origen
URLIdentityPermission, permisos derivados basados en URL de donde el código tiene origen
Seguridad basada en roles
La Seguridad basada en roles representa a un usuario o agente que actua en representación
de un usuario dado. Las aplicaciones .NET hacen decisiones basadas en la identidad
principal o su role como miembro.
Un role es un nombre para un conjunto de usuarios quienes comparten los mismos
privilegios.
Un principal puede ser un miembro de múltiples roles y de esta manera se puede utilizar
un role para determinar si ciertas acciones requeridas quizá sean realizadas por un principal.
Un principal no necesariamente es un usuario, también puede ser un agente.
Existen tres tipos de principal:
Generic principals, representa usuarios no autentificados.
Windows principals, relación de usuarios windows y sus roles, el acceso a recursos de otro
usuario es permitido.
Ismael Galan Cazares
Custom principals, definido por una aplicación. Pueden extender la noción básica de la
identidad y los roles delprincipal. La restricción es que la aplicación debe proveer un módulo
de autentificación de los tipos que elprincipal puede implementar.
La clase Principalpermission provee consistencia con la seguridad de acceso, permitiendo
al runtime realizar la autorización en un sentido similar al chequeo de la seguridad de acceso
al código, pero es posible acceder directamente a la información de identidad principal y
realizar chequeos de role e identidad en el código cuando sea necesario.
Función ToString()
Analice el siguiente ejemplo:
using System;
class Empleado{
string usr;
string pwd;
public Empleado(string login, string pwd){
this.usr = login;
this.pwd = pwd;
}
}
class App{
public static void Main(){
Empleado empleado = new Empleado("gangeles","123");
Console.WriteLine("Empleado : " + empleado);
}
}
Salida: Empleado : Empleado
La salida fue el nombre de la clase Empleado ya que es la representación más cercana que
encontro.
Es posible especificar algo con mayor sentido para ello se necesita redefinir la
función ToString():
using System;
class Empleado{
string usr;
string pwd;
public Empleado(string login, string pwd){
this.usr = login;
this.pwd = pwd;
}
public override string ToString(){
return("Usuario : " + usr + ", Password : " + pwd);
}
}
class App{
public static void Main(){
Empleado empleado = new Empleado("gangeles","123");
Console.WriteLine(empleado);
}
}
Ismael Galan Cazares
Salida: Usuario : gangeles, Password : 123
Función Equals()
La función Equals() es utilizada para determinar cuando dos objetos tienen el mismo
contenido.
En el siguiente ejemplo se redefinen las funciones operator==() y operator!=(), para permitir la
sintaxis del operador, estos operadores deben ser redefinidos en pares, no pueden ser
redefinidos separadamente.
Ejemplo:
using System;
class Empleado{
string usr;
string pwd;
public Empleado(string login, string pwd){
this.usr = login;
this.pwd = pwd;
}
public override string ToString(){
return("Usuario : " + usr + ", Password : " + pwd);
}
public override bool Equals(object o){
Empleado empB = (Empleado)o;
if(usr != empB.usr){return false;}
if(pwd != empB.pwd){return false;}
return true;
}
public static bool operator==(Empleado empA, Empleado empB){
return empA.Equals(empB);
}
public static bool operator!=(Empleado empA, Empleado empB){
return !empA.Equals(empB);
}
}
class App{
public static void Main(){
Empleado empleado1 = new Empleado("gangeles","123");
Empleado empleado2 = new Empleado("gangeles","123");
Console.WriteLine("El empleado1 es igual al empleado2:
"+empleado1.Equals(empleado2));
Console.Write("empleado1 == empleado2 : ");
Console.Write(empleado1 == empleado2);
}
}
Salida:
El empleado1 es igual al empleado2 : True
empleado1 == empleado2 : True
Al compilar el ejemplo anterior se presentara un warning indicando que no fue redefinada la
función GetHashCode() ya que los valores que regresa son requeridos para ser relacionados
Ismael Galan Cazares
al valor de regreso de Equals(). Cuando se invoca la función Equals() y dos objetos son
iguales siempre se debe regresar el mismo código hash.
Si no es redefinido el código hash podría ser sólo identico para la misma instancia de un
objeto y una búsqueda para un objeto que es igual pero no la misma instancia podría fallar.
Es posible utilizar un miembro que es único para el código hash, pero si no existe un valor
único el código hashdebería ser creado fuera de los valores contenidos en la función.
Si la clase no tiene un identificador único pero tiene tiene otros campos, podrías ser utilizados
por la función hash:
using System;
class Empleado{
string usr;
string pwd;
public Empleado(string login, string pwd){
this.usr = login;
this.pwd = pwd;
}
public override string ToString(){
return("Usuario : " + usr + ", Password : " + pwd);
}
public override bool Equals(object o){
Empleado empB = (Empleado)o;
if(usr != empB.usr){return false;}
if(pwd != empB.pwd){return false;}
return true;
}
public static bool operator==(Empleado empA, Empleado empB){
return empA.Equals(empB);
}
public static bool operator!=(Empleado empA, Empleado empB){
return !empA.Equals(empB);
}
public override int GetHashCode(){
return usr.GetHashCode() + pwd.GetHashCode();
}
}
class App{
public static void Main(){
Empleado empleado1 = new Empleado("gangeles","123");
Empleado empleado2 = new Empleado("gangeles","123");
Console.WriteLine("El empleado1 es igual al empleado2:
"+empleado1.Equals(empleado2));
Console.Write("empleado1 == empleado2 : ");
Console.Write(empleado1 == empleado2);
}
}
La implementación del código GetHashCode anterior agrega los elementos y los regresa.
Ismael Galan Cazares
Clase Hashtable
La clase Hashtable es muy utilizada para realizar una búsqueda de objetos por una llave. Una
tabla hash trabaja utilizando una función hash, la cual produce un entero llave para una
instancia específica de una clase, donde esta llave es una versión condensada de la
instancia.
Una tabla hash utiliza esta llave para limitar drasticamente el número de objetos que deben
ser buscados para encontrar un objeto específico en una colección de objetos.
Interface IHashCodeProvider
Si requiere definir diferentes códigos hash para un objeto específico, podría hacer esto
implementado la InterfaceIHashCodeProvider para proveer una función alterna hash y
además de que se requiere una coincidencia de la implementación de IComparer, estas
nuevas implementaciones son pasadas al contructor de la Hashtable:
using System;
using System.Collections;
public class Lenguaje : IComparable{
public string nombre;
int id;
public Lenguaje(string nombre, int id){
this.nombre = nombre;
this.id = id;
}
class App{
public static void Main(){
Lenguaje[] aLenguaje = new Lenguaje[5];
aLenguaje[0] = new Lenguaje("C",3);
aLenguaje[1] = new Lenguaje("ActionScript",5);
aLenguaje[2] = new Lenguaje("JavaScript",2);
aLenguaje[3] = new Lenguaje("Java",8);
aLenguaje[4] = new Lenguaje("PHP",1);
class MiClase{
public Saludo saludo;
public MiClase(string s){this.saludo = new Saludo(s);}
public MiClase Clon(){return (MiClase)MemberwiseClone();}
}
class App{
public static void Main(){
MiClase miClase = new MiClase("Hello World!");
MiClase miClon = miClase.Clon();
Console.WriteLine("miClase : " + miClase.saludo.s);
Console.WriteLine("miClon : " + miClon.saludo.s);
miClon.saludo.s = "Hola Mundo";
Console.WriteLine("miClase : " + miClase.saludo.s);
Console.WriteLine("miClon : " + miClon.saludo.s);
}
}
Salida:
miClase : Hello World!
miClon : Hello World!
miClase : Hola Mundo
miClon : Hola Mundo
El resultado anterior es porque la copia hecha por la función MemberWiseClonre() es una
copia, el valor de saludo es el mismo en ambos objetos por lo que se se cambia un valor
dentro del objeto Saludo afecta ambas instancias deMiClase.
Interface ICloneable
Para crear una copia deep, donde una nueva instancia de Saludo es creada para para la
nueva instancia de MiClase, para ello se hace una implementación de la interface ICloneable:
using System;
class Saludo{
public string s;
public Saludo(string s){
this.s = s;
}
}
class App{
public static void Main(){
MiClase miClase = new MiClase("Hello World!");
MiClase miClon = (MiClase) miClase.Clone();
Console.WriteLine("miClase : " + miClase.saludo.s);
Console.WriteLine("miClon : " + miClon.saludo.s);
miClon.saludo.s = "Hola Mundo!";
Console.WriteLine("miClase : " + miClase.saludo.s);
Console.WriteLine("miClon : " + miClon.saludo.s);
}
}
Salida:
miClase : Hello World!
miClon : Hello World!
miClase : Hello World!
miClon : Hola Mundo
La invocación a Memberwiseclone() regresa una nueva instancia de Saludo y su contenido
puede ser modificado sin afectar el contenido de miClase.
Note que en este caso ICloneable requiere implementar la función Clone().
Formato Numérico
Los tipos numéricos son formateados a través de la función miembro Format() del tipo de
dato, la cual puede ser invocada directamente a través de String.Format() la cual invoca a la
función Format() de cada tipo de dato oConsole.WriteLine() la cual invoca a String.Format().
Existen dos tipos de métodos para el formateo específico numérico:
Formato Estándar String
Formato Estándar String, el cual puede ser utilizado para convertir un tipo numérico a una
representación específica string.
Este formato consiste del formato específico del caracter seguido de la secuencia de
precisión específica de digitos, los formatos soportados son:
Formato Descripción Ejemplo Salida
Console.WriteLine("0:C",
C, c Currency $123,345.90
123.8977);
Console.WriteLine("0:D7",
D, d Decimal 0012345
12345);
Scientific Console.WriteLine("0:E",
E, e 3.334590E+004
(exponential) 33345.8977);
Console.WriteLine("0:F",
E, f Fixed-point 3.334590E+004
33345.8977);
Console.WriteLine("0:G",
G, g General 33345.8977
33345.8977);
N, n Number Console.WriteLine("0:N", 33,345.90
Ismael Galan Cazares
33345.8977);
Console.WriteLine("0:X",
X, x Hexadecimal FF
255);
Input/Output
El lenguaje Común en Tiempo de Ejecución .NET provee funciones de entrada/salida en
el namespace System.IO.
La lectura y escritura la realiza la clase Stream, la cual describe como los bytes pueden ser
escritos o leidos. Stream es una clase abstracta que en la práctica las clases derivan
de Stream para ser utilizadas.
Clases disponibles:
Ismael Galan Cazares
FileStream, flujo en un archivo de disco
MemoryStream, flujo que es almacenado en memoria
NetworkStream, flujo en una conexión de red
BufferedStream, implementa un buffer en la cima de otro stream.
using System;
using System.IO;
class App{
public static void Main(){
FileStream f = new FileStream("nuevo.txt", FileMode.Create);
StreamWriter s = new StreamWriter(f);
for(int iNumberLine = 1; iNumberLine <= 10; iNumberLine++){
s.WriteLine("Linea " + iNumberLine);
}
s.Close();
f.Close();
}
}
Salida, Archivo Nuevo.txt cuyo contenido es:
Linea 1
Linea 2
Linea 3
Linea 4
Linea 5
Linea 6
Linea 7
Linea 8
Linea 9
Linea 10
Serialización
La Serialización es el proceso utilizado por el runtime para objetos persistentes en algún
orden de almacenamiento o para transferirlos de un lugar a otro.
La información de los metadatos en un objeto contiene información suficiente para que
el runtime serialice los campos, pero es necesario indicar al runtime hacerlo correctamente a
través de dos atributos [Serializable] el cual es utilizado para marcar un objeto que es posible
serializar y [NonSerialized] que es aplicado para un campo o propiedad para indicar que no
debería ser serializado.
Ismael Galan Cazares
Threading (Hilos)
El namespace System.Threading contiene clases utilizadas para threading y sincronización.
El tipo apropiado de sincronización y/o exclusión depende del diseño del programa, pero C#
soporta exclusión simple utilizando la sentencia lock.
lock utiliza la clase System.Threading.Monitor y provee funcionalidad similar a la invocación
de CriticalSection en Win32.