Curso de Programación en C#

[Comenzando con C#]

(Hoy comenzaremos a ver cosas un poco mas complejas ;-))

Fecha: 10/Abr/2005 (04 de Abril de 2005)
Autor: Alejandro Domingo Velazquez Cruz [email protected]

 

 Por favor no se olviden de calificar este curso, su opinión cuenta, buena o mala será tomada en cuenta

Conversión de Tipos de Datos en C#


Las conversiones nos permiten que una expresión de un tipo sea tratada como una expresión de otro
tipo, dichas conversiones pueden ser implícitas o explícitas, por ejemplo la conversión de un tipo
int a long es implícita, sin embargo la conversión de un tipo long a un tipo int es explícita, esto
debido a que un int puede ser expresado en formato long sin que haya perdida de precisión en la 
operación, sin embargo si intentamos convertir un numero long a int puede haber perdida de precisión
y se necesita una conversión explícita, es como una forma de obligarnos a demostrar que estamos
conscientes de que existe tal perdida de precisión y en verdad es muy útil.

+ Conversión Implícita
	- No requiere sentencias adicionales
	- Puede perder precisión, pero no magnitud

+ Conversión Explícita
	- La define el usuario utilizando la expresión (cast)
	- El operador "as" la convierte a un valor de tipo específico
	- Utilizar operadores "checked" y "uncheked"

Ejemplo:
	int miNumero = 13;
	float miOtroNumero = miNumero;

En este caso no es necesaria una conversión explícita debido a que un número int puede ser expresado
sin ningún problema.

	float miNumero = 13.5;
	int miOtroNumero = (int) miNumero;

En este caso si es necesaria una conversión explícita debido a que un número float no puede ser
expresado en int sin que haya perdida de precisión, en este caso si ejecutaramos la siguiente
instrucción: Console.WriteLine("Numero Float:{0} Numero Int:{1}",miNumero,miOtroNumero); se
imprimiría en pantalla Numero Float: 13.5 Numero Int: 13 ahi podemos apreciar con claridad la
perdida de precisión debido a que se trunca todo aquello que se haya después del punto, cabe
hacer la aclaración que no se redondea, es decir no se eleva al entero más próximo, sino que se
trunca.

Operadores "checked" y "unchecked"


Los operadores checked y unchecked, se utilizan para controlar la verificación de ovewflow, de 
operaciones y conversiones aritméticas. 

+ Expresión Verificada:
	- checked ( expression ) 

+ Expresión no Verificada: 
	- unchecked ( expression )

Estructuras de Datos


+ Declaración:
	struct + nombreEstructura + { miembros };

+ Uso:
	- Primero declaramos la estructura:
		struct coordenada
		{
			int x;
			int y;
		}

	- Después declaramos un objeto de ese tipo:
		coordenada miCoordenada;

	- Y accesamos a los elementos usando el operador . :
		miCoordenada.x = 1;
		miCoordenada.y = 2;

Un tipo de estructura es un tipo de valor y puede crear constantes, campos, métodos, propiedades,
índices, operadores, constructores de instancias, constructores estáticos y tipos anidados.

Diferencias entre clases y estructuras

+ Estructura
	- Contiene datos simples
	- Tipo de Valor

+ Clase
	- Objeto enriquecido con referencias
	- Tipo de Referencia

Ahi pocas diferencias entre estructuras y clases, pero son realmente significativas, las estructuras
sirven para representar conjuntos de datos y pueden contener datos y funciones, sin embargo las
estructuras son tipos de valor y no requieren espacio en la pila, ya que los datos están contenidos
directamente en la estructura, mientras que una variable en una clase contiene una referencia a los
datos, esto es lo que se conoce como objeto.

Enúmerados


Una declaración enum declara un nuevo tipo enumerado e inicia con la palabra clave enum y define 
el nombre, la accesibilidad, el tipo y los miembros del enumerador. Cada tipo de enumerador tiene
un tipo, dicho tipo debe poder representar todos los valores de numerador definidos en la enumeración. 
Un enumerado puede declararse de manera explícita un tipo como byte, sbyte, short, ushort, int, 
uint, long o ulong, cualquier enumerado que no indica de manera explícita su tipo es int.

+ Declaración:
	enum + nombreDelEnumerado + { valores }

+ Ejemplo:
	enum Color{ blanco,rojo,azul,verde };	
	
+ Uso: 
	Color miColor;
	miColor = Color.blanco;
	miColor = (Color) 1;
		

Arreglos


Los arreglos son una colección de elementos o de objetos todos del mismo tipo y que se encuentran
indexados para poder acceder a ellos de una manera sencilla, son realmente faciles de usar, ahi
diferentes tipos de arreglos
Ahi dos formas de declarar arreglos en C#
+ Declaración con tipo y forma pero sin límites
	- int[] unidimensional;
	- int[,] bidimensional;
	- int [][] jagged;
NOTA: Los arreglos del tipo jagged son arreglos de arreglos.

+ Declaración utilizando new con límites o inicializadores
	- unidimensional = new int[20];
	- bidimendional = new int[20,20];
	- jagged = new int[10][];
	- jagged[0] = new int[][10];

Métodos


Los métodos son miembros de las clases y pueden realizar una serie de acciones, o devolver un 
valor ya sea que tengan que calcularlo o no. Pueden recibir o no parametros y pueden devolver
o no devolver parametros.

+ Declaración:
	tipoRetorno + NombreDelMétodo + [Parámetros] + { cuerpo }

+ Ejemplo:
	int Suma(int numero1, int numero 2)
	{
		return numero1 + numero2;
	}

+ Uso:
	[valor de retorno] miMétodo([Parametros]);

+ Ejemplo:
	resultado = Suma(numero1,numero2);
	
Los métodos pueden recibir diversos valores desde el exterior, de hecho pueden recibir tantos valores
como sea necesario, los valores que se le pasan a un método pueden ser por valor o por referencia,
los valores que un método recibe por valor, los recibe como una copia del dato que puede modificar
a su gusto sin que se vean afectadas las demás copias de dicho dato, en cambio los valores que un
método recibe por referencia son las direcciones a donde se encuentra el dato, al cambiar el dato
que ahí donde una de estas referencias apunta cambia el valor para todos aquellos que lo estan utilizando,
un ejemplo muy sencillo de esto es, en el mundo real un paso de valor por referencia se da si tenemos
apuntada la dirección de un amigo, dicha dirección es una referencia al lugar donde vive, es
por eso que si vamos al lugar donde apunta la referencia nos encontraremos en la casa de nuestro amigo,
una vez allí, si rompemos un vidrio cualquier persona que llegue a ese lugar encontrara la ventana rota, 
en cambio con los pasos de parámetro por valor se tiene una copia del objeto en si, es decir,
en el ejemplo anterior en vez de haber tenido una dirección, habría tenido una casa exactamente igual
a la de mi amigo, por lo que si hubiera roto un vidrio, solo mi casa se habría visto afectada.
En C# si pasamos un valor a un método se pasa por valor a menos que se le indique lo contrario.
Debemos recordar que no ahi limite al número de parámetros que puede recibir o devolver un método
pero si no se va a recibir o a devolver ningún valor se puede usar la palabra void para indicarlo.
En C# los métodos son sumamente flexibles, es por esto que podemos devolver múltiples valores y nos
permite sobrecargarlos, las palabras claves ref y out son las que nos permiten que un método retorne más
de un valor al método que lo invoco. La sobrecarga de métodos nos permite que un método se comporte de 
manera diferente en función al tipo de parametros que recibe y/o del número de argumentos que le acompañan.
Ejemplos de sobrecarga de métodos:

int i1=2,i2=3;
float f1=2.14,f2=5.25;
 
int suma( int n1, int n2 ) //Método 1
{
	return n1+n2;
}

float suma( float n1, float n2 ) //Método 2
{
	return n1+n2;
}

float suma( int n1, float n2 ) //Método 3
{
	return n1+n2;
}

resultado = suma(i1+i2); //Llamada 1
resultado = suma(f1+f2); //Llamada 2
resultado = suma(i1+f1); //Llamada 3

En este ejemplo en ninguno de los casos ahi perdida de precisión debido a que el método haciendo uso de la sobrecarga
se adapta a los parametros que recibe y actúa en consecuencia a ello, es decir si el método suma recibe dos
enteros como en la llamada 1 devuelve un número entero empleando para ello el método 1, si recibe dos flotantes
devuelve un flotante utilizando para ello el método 2 y si recibe primero un flotante y luego un entero responde
utilizando el método 3.

Manejo de Excepciones


C# proporciona soporte integrado para el manejo de excepciones o de una forma más formal situaciones anómalas de 
funcionamiento, las cuales pueden ocurrir en cualquier momento durante la ejecución del programa y son manejadas por
el código que se encuentra fuera del flujo normal de control. Todo esto gracias a las palabras clave try, throw, 
catch y finally. C# proporciona una solución estructurada tanto a nivel del sistema como de aplicación. A pesar de
que es muy similar a C++ en cuanto al manejo de excepciones existen varias diferencias, entre ellas que cada excepción
esta representada por una instancia de un tipo de clase derivado de System.Exception. en realidad es algo bastante 
simple:

try
{
	has esto...
	si i = 0 throw una excepción
}

catch
{
	si fallo has esto...
}

finally
{
	haya fallado o no, has esto...
}

Como se puede apreciar el manejo de excepciones es bastante sencillo y fácil de entender aunque no tengamos mucha
experiencia programando, todo aquello que se puso entre las {} del try es un segmento de código en el que puede o no
generarse un error en tiempo de ejecución(excepción), en caso de que haya habido un funcionamiento anómalo en el 
programa(excepción) la ejecución del código entra en el segmento de código catch y ejecuta el bloque de instrucciones
que hemos definido para manejar ese error, finalmente el flujo del programa haya o no habido excepción entra en finally
aqui podemos poner rutinas para marcar los objetos que ya no se utilizarán de manera que el recolector de basura 
pueda liberar la memoria que dichos objetos ocupaban, rutinas que guarden un log de la aplicación para llevar un control
de ¿cuántas veces ha fallado?, ¿porqué fallo?, etc., todo bloque try puede tener uno o más catch para tratar cada una de
las posibles excepciones, pero la flexibilidad de C# va más alla de eso, ya que nos permite lanzar nuestras propias
excepciones, por ejemplo si un método no recibe un valor que debe recibir o recibe un valor que no puede procesar
podemos lanzar nuestra propia excepción. Ejemplo:

using System;

public class ManejoExcepciones
{
	public static void Main()
	{
		try							//Le hacemos saber que puede ocurrir un error
		{
			string s=null;					//Declaramos un string y lo dejamos vacio

			if (s == null)					//Si el string esta vacio
			throw(new ExcepcionCadenaVacia()); 		//Lanzamos un error personalizado
			Console.WriteLine("Esto nunca se imprime");	//Si ahi error el código sale de la ejecución normal
									//es por eso que esta parte nunca se ejecuta
		}
		
		catch( ExcepcionCadenaVacia e )			//Atrapamos nuestro error
		{
			Console.WriteLine("La cadena esta vacia");	//Manejamos el error
		}
		
		finally
		{
			Console.WriteLine("Esto siempre se imprime");	//Esto siempre se ejecutará
		}
	}
}

NOTA IMPORTANTE: El código que se encuentra en los capitulos del curso no es siempre funcional. Para código funcional consulte la sección de ejercicios resueltos.

 


Anterior Índice Siguiente

ir al índice