Documentos de Académico
Documentos de Profesional
Documentos de Cultura
El nombre C Sharp fue inspirado por el signo '#' que se compone de cuatro signos
'+' pegados. Aunque C# forma parte de la plataforma .NET, ésta es una API,
mientras que C# es un lenguaje de programación independiente diseñado para
generar programas sobre dicha plataforma. Ya existe un compilador implementado
que provee el marco Mono - DotGNU, el cual genera programas para distintas
plataformas como Windows Microsoft, Unix, Android, iOS, Windows Phone, Mac
OS y GNU/Linux.
A principios de los 2000 Microsoft había liberado la primera gran versión del
lenguaje. Ha habido muchísimos cambios en los últimos 18 años. En este tiempo,
Java ha liberado 4 grandes versiones, mientras que C# ha liberado 6. Los
lenguajes han tomado caminos diferentes, y C# ha experimentado muchísima
innovación.
C# Versión 1
C# Versión 2
Genéricos
Tipos parciales
Métodos anónimos
Tipos anulables
Iteradores
Covarianza y contravarianza
Aunque Microsoft puede que haya empezado con un lenguaje orientado a objetos
bastante genérico, la versión 2 de C# lo cambió todo enseguida. Se pusieron a la
tarea tras la salida de la versión inicial y fueron a por varias de las frustraciones
que causaba. Con genéricos, tienes tipos y métodos que pueden operar sobre un
tipo arbitrario mientras que aún conservan seguridad de tipos. Así, por ejemplo,
tener una List<T> te permite tener una List<string> o una List<int> y realizar
operaciones seguras de tipo en esas cadenas de caracteres o ints mientras iteras
por ellas.
La versión 2 de C# te permite iterar por los ítems de una Lista (u otros tipos
Enumerable) con un bucle foreach. Tener esto como un elemento de primera clase
del lenguaje mejoró ostensiblemente la legibilidad del código y la capacidad para
poder entenderlo.
C# Versión 3
Propiedades auto-implementadas
Tipos anónimos
Expresiones de consulta - LINQ
Expresiones lambda
Árboles de expresión
Métodos de extensión
C# Versión 4
Tipos dinámicos
Argumentos opcionales y con nombre
Covarianza y contravarianza genérica
Tipos interop embebidos
C# Versión 5
Con la versión 5 de C#, Microsoft liberó una versión con el foco muy puesto en la
innovación del lenguaje. Esta es la lista de las características más importantes:
C# Versión 6
C# Versión 7
Es la versión actual en la fecha que se ha escrito este artículo. Tiene cosas muy
chulas y revolucionarias que ya estaban en el ADN de la versión 6, pero sin el
compilador como servicio. Aquí van las novedades de esta versión:
Variables out
Tuplas y deconstrucción
Coincidencia de patrones
Funciones locales
Extensión de la funcionalidad de miembros con una expresión como cuerpo
aparecida en C# 6
Referencias locales y devoluciones
Microsoft dio solución a problemas que venían desde muy lejos al condensar la
declaración de variables que se pueden a usar con la palabra clave out y al
permitir valores de devolución múltiples vía tuplas. Además, Microsoft le dio un
uso más amplio al lenguaje. .NET ahora va dirigido a cualquier sistema operativo y
tiene la vista puesta de forma firme en la nube y en la portabilidad. Esto es lo que
más ocupa la mente y el tiempo de los diseñadores del lenguaje, además de
pensar en nuevas características. Ha habido 3 versiones secundarias desde C#
7.0: 7.1, 7.2, 7.3.
C# Versión 8
Como con métodos IEnumerable normales, se puede usar "yield return" para
construir el stream.
Facilidad de uso
Esta forma de programación ahorra mucho código, lo cual indica que partes de
código son reutilizables para no volverlas a escribir, con lo cual se afirma que C#
presenta las características necesarias para considerarlo como un lenguaje
orientado a objetos, tales son: encapsulación, herencia y polimorfismo; además
una de las mejoras que presenta este lenguaje con respecto a este tipo de
programación es que para evitar confusiones no existen variables o funciones
globales, sino que se definen dentro de los tipos de datos. En cuanto a la
herencia, esta solo puede ser herencia simple, con lo cual se evitan confusiones
que si fuera herencia múltiple.
8 Juan González - Ryan León – Estiven Peña
Origen, evolución y características
técnicas del lenguaje de programación C#
Administración de memoria:
C# tiene la característica de inicializar los datos o variables declaradas en el
programa, además de que también de forma automática libera la memoria cuando
el mismo programa lo cree conveniente. Es decir tiene constructores y
destructores, y estos actúan automáticamente a menos que se manipulen desde el
código.
Todos los tipos de datos que se definan siempre se derivarán, incluso de forma
implícita, de una clase base común llamada System.Object, por lo que dispondrán
de todos los miembros definidos en ésta clase. La ventaja de que todos los tipos
se deriven de una clase común es que facilita el diseño de colecciones genéricas
que puedan almacenar objetos de cualquier tipo.
Uso de operadores:
Este lenguaje permite de forma automática la manera en que pueden trabajar los
operadores, ya sea de tipo lógico, aritmético, etc. Es decir dependiendo del
contexto de donde se encuentre el operador, el programa detecta que tipo de uso
debe tener el operador.
9 Juan González - Ryan León – Estiven Peña
Origen, evolución y características
técnicas del lenguaje de programación C#
Compatible:
C# no sólo mantiene una sintaxis muy similar a C, C++ o Java que permite incluir
directamente en código escrito en C# fragmentos de código escrito en estos
lenguajes, sino que el runtime de lenguaje común también ofrece la posibilidad de
acceder a código nativo escrito como funciones sueltas no orientadas a objetos
tales como las DLLs de la API Win32.
Otras Características:
Control de conversiones
Control de inicialización de variables
Control de índices en accesos a tablas
Control de desbordamientos
Control de tipos en “punteros a función”
Control en parámetros múltiples
Gestión automática de memoria
Recolector de basura
Liberación recursos determinista
Extensibilidad de modificadores
Versionable: Redefinir virtual con override
Las propiedades del proyecto se organizan en grupos y cada grupo tiene su propia
página de propiedades. Es posible que las páginas varíen para lenguajes y tipos
de proyecto diferentes. En los proyectos de C#, F# y Visual Basic, las propiedades
se exponen en el Diseñador de proyectos. En la siguiente ilustración se muestra la
página Propiedad de compilación de un proyecto de WPF en C#:
±4.94065645841246E−
324 a Coma
double System.Double 64-bit (8-byte)
±1.79769313486232E+ flotante largo
308
−7.9228162514264337
Coma
decimal System.Decimal 593543950335 a
128-bit (16-byte) flotante
+7.9228162514264337
monetario
593543950335
C#, al igual que C++, define un tipo de cadena de caracteres. Dentro de la cadena
de caracteres se pueden usar secuencias de escape. Una cadena de caracteres
puede iniciarse con el símbolo @ seguido por una cadena entre comillas ( " ), en
Enteros
Coma flotante
decimal 9.95M
Caracteres
Cadenas
Secuencias de escape
Alerta (timbre) \a
Retroceso \b
Avance de página \f
Nueva línea \n
Retorno de carro \r
Tabulador horizontal \t
Tabulador vertical \v
Nulo \0
Barra inversa \\
Un identificador puede:
Un identificador no puede:
También puedes declarar una variable sin especificar el tipo de dato, utilizando el
mecanismo de inferencia mediante la palabra clave var donde el compilador
determina el tipo de dato que se le asignará a la variable y sólo es permitida para
variables locales, no para parámetros o datos miembro.
var numero1 = 5;
readonly double E;
E = 2.71828;
Categoría Operadores
Acceso a . Indexación [ ]
miembro
De Para
sbyte byte, ushort, uint, ulong o char
byte Sbyte o char
short sbyte, byte, ushort, uint, ulong o char
ushort sbyte, byte, short o char
int sbyte, byte, short, ushort, uint, ulong o char
uint sbyte, byte, short, ushort, int o char
long sbyte, byte, short, ushort, int, uint, ulong o char
ulong sbyte, byte, short, ushort, int, uint, long o char
char sbyte, byte o short
float sbyte, byte, short, ushort, int, uint, long, ulong, char o decimal
double sbyte, byte, short, ushort, int, uint, long, ulong, char, float o decimal
decimal sbyte, byte, short, ushort, int, uint, long, ulong, char, float o double
Leyenda
Verd
Conversión automática o implícita (A).
e
byte sbyte short ushort int uint long ulong float double decimal char bool
byte E A A A A A A E E E E I
sbyte E A E A E A A E E E E I
short E E E A A A A E E E E I
ushort E E E A A A A E E E E I
int E E E E E A A E E E E I
uint E E E E E A A E E E E I
long E E E E E E E E E E E I
ulong E E E E E E E E E E E I
float E E E E E E E E A E I I
double E E E E E E E E E E I I
decimal E E E E E E E E E E I I
char E E E A A A A A A A A I
bool I I I I I I I I I I I I
2.5. Condicional
En C# contamos con varias de estas estructuras, así que las iremos explicando
con calma una a una, empezando en esta entrega con las estructuras
condicionales.
if (num==10)
{
Console.WriteLine("El número es igual a 10");
}
Los programadores de C ó C++ dirán que la expresión siempre se evaluaría a
true, además de que se asignaría el valor 10 a la variable num. Pero este curso es
de C#, así que los programadores de C ó C++ se han vuelto a equivocar: en C# se
produciría un error, porque la expresión no se evalúa a true o false, sino que tiene
que retornar true o false necesariamente. Es decir, el compilador de C# no evalúa
También puede ocurrir que tengamos que ejecutar una serie de acciones si se da
una condición y otras acciones en caso de que esa condición no se dé. Pues bien,
para eso tenemos la instrucción else. Volviendo a la interpretación lingüística para
favorecer todo esto a los principiantes, sería como un "de lo contrario", es
decir, si te portas bien, te compro un helado y te dejo ver la tele; de lo contrario, te
castigo en tu cuarto y te quedas sin cenar. ¿Quieres un poquito de pseudo-código
para ver esto? Venga, aquí lo tienes:
Si (te portas bien)
{
te compro un helado;
te dejo ver la tele;
}
de lo contrario
{
te castigo en tu cuarto;
te quedas sin cenar;
}
if (num==10)
{
Console.WriteLine("El número es igual a 10");
}
else
{
Console.WriteLine("El número no es igual a 10");
}
O bien:
if (num==10) Console.WriteLine("El número es igual a 10");
else Console.WriteLine("El número no es igual a 10");
También podría suceder que hubiera que enlazar varios if con varios else.
Volvamos con otro ejemplo para ver si nos entendemos: si compras el libro te
regalo el separador, de lo contrario, si compras la pluma te regalo el cargador, de
lo contrario, si compras el cuaderno te regalo un llavero, y, de lo contario, no te
regalo nada. Veamos de nuevo el pseudo-código de esto:
Si (compras el libro)
{
te regalo el separador;
}
de lo contrario si (compras la pluma)
{
te regalo el cargador;
}
de lo contrario si (compras el cuaderno)
{
te regalo un llavero;
}
de lo contrario
{
no te regalo nada;
}
Esto es exactamente lo que ocurre en programación: el compilador no sigue
analizando las demás condiciones en el momento en el que encuentre una que
retorna true. Veamos algo de esto en C#:
if (num==10)
{
Console.WriteLine("El número es igual a 10");
}
else if (num>5)
{
Console.WriteLine("El número es mayor que 5");
}
else if (num>15)
{
Console.WriteLine("El número es mayor que 15");
28 Juan González - Ryan León – Estiven Peña
Origen, evolución y características
técnicas del lenguaje de programación C#
}
else
{
Console.WriteLine("El número no es 10 ni mayor que 5");
}
Instrucción switch
Una instrucción switch funciona de un modo muy similar a una construcción con
if...else if... else. Sin embargo, hay un diferencia que es fundamental: mientras en
las construcciones if...else if... else las condiciones pueden ser distintas en cada
uno de los if ... else if, en un switch se evalúa siempre la misma expresión,
comprobando todos los posibles resultados que esta pueda retornar. Un switch
equivaldría a comprobar las diferentes situaciones que se pueden dar con
respecto a una misma cosa.
comprobemos (opcion)
{
en caso de 1:
te descuento un 10%;
Nada más;
en caso de 2:
te descuento un 5%;
Nada más;
en caso de 3:
te descuento un 2%;
Nada más;
en otro caso:
no te descuento nada;
Nada más;
}
Vamos a verlo en C#:
switch (opcion)
{
case 1:
descuento=10;
break;
case 2:
descuento=5;
break;
29 Juan González - Ryan León – Estiven Peña
Origen, evolución y características
técnicas del lenguaje de programación C#
case 3:
descuento=2;
break;
default:
descuento=0;
break;
}
switch (opcion)
{
case 1:
descuento=10;
break;
case 2:
regalo="Cargador de CD"
case 3:
descuento=5;
break;
default:
descuento=0;
break;
}
switch (opcion)
{
case 1:
descuento=10;
break;
case 2:
case 3:
if (opcion==2) regalo="Cargador de CD";
descuento=5;
break;
default:
descuento=0;
break;
}
Las clases en C# se definen de forma parecida a los registros (struct), sólo que
ahora, además de variables (que representan sus detalles internos, y que
llamaremos sus "atributos"), también incluirán funciones (las acciones que puede
realizar ese objeto, que llamaremos sus "métodos"). Atributos y métodos formarán
parte de "un todo", en vez de estar separados en distintas partes del programa.
Esto es lo que se conoce como "Encapsulación".
Cuando sepamos cuantos datos vamos a guardar (por ejemplo 4), podremos
reservar espacio con la orden "new", así:
Vamos a completar un programa de prueba que use un objeto de esta clase (una
"Puerta"), muestre su estado, la abra y vuelva a mostrar su estado:
// Ejemplo_06_02a.cs
// Primer ejemplo de clases
// Introducción a C#, por Nacho Cabanes
using System;
public class Puerta
{
int ancho; // Ancho en centimetros
Este fuente ya no contiene una única clase (class), como todos nuestros ejemplos
anteriores, sino dos clases distintas:
(Nota: al compilar, puede que obtengas algún "Aviso" -warning- que te dice que
has declarado "alto", "ancho" y "color", pero no las estás utilizando; no es
importante por ahora, puedes ignorar ese aviso).
Valores iniciales...
Ancho: 0
Alto: 0
Color: 0
Abierta: False
Vamos a abrir...
Ancho: 0
Alto: 0
Color: 0
Abierta: True
Se puede ver que en C# (pero no en todos los lenguajes), las variables que
forman parte de una clase (los "atributos") tienen un valor inicial predefinido: 0
para los números, una cadena vacía para las cadenas de texto, "false" para los
datos booleanos.
Vemos también que se accede a los métodos y a los datos precediendo el nombre
de cada uno por el nombre de la variable y por un punto, como hacíamos con los
registros (struct).
Aun así, en nuestro caso no podemos hacer directamente "p.abierta = true" desde
el programa principal, por dos motivos:
Por ejemplo, para conocer y modificar los valores del "ancho" de una puerta,
podríamos crear un método LeerAncho, que nos devolviera su valor, y un método
CambiarAncho, que lo reemplazase por otro valor. No hay un convenio claro sobre
cómo llamar a a estos métodos en español, por lo que es frecuente usar las
palabras inglesas "Get" y "Set" para leer y cambiar un valor, respectivamente. Así,
crearemos funciones auxiliares GetXXX y SetXXX que permitan acceder al valor
de los atributos (en C# existe una forma alternativa de hacerlo, usando
"propiedades", que veremos más adelante):
Así, una nueva versión del programa, que incluya ejemplos de Get y Set,
podría ser:
// Ejemplo_06_02b.cs
cada función: a partir de ahora, sólo Main será "static". Aunque a veces se usan
indistintamente, una clase y un objeto son cosas diferentes. Una clase define un
tipo de objeto, pero no es un objeto en sí. Un objeto es una entidad concreta
basada en una clase y, a veces, se conoce como una instancia de una clase.
Los objetos se pueden crear usando la palabra clave new, seguida del nombre de
la clase en la que se basará el objeto, como en este ejemplo:
C#Copiar
Customer object1 = new Customer();
Cuando se crea una instancia de una clase, se vuelve a pasar al programador una
referencia al objeto. En el ejemplo anterior, object1 es una referencia a un objeto
que se basa en Customer.Esta referencia apunta al objeto nuevo, pero no
contiene los datos del objeto. De hecho, puede crear una referencia de objeto sin
tener que crear ningún objeto:
C#Copiar
Customer object2;
Este código crea dos referencias de objeto que hacen referencia al mismo
objeto. Por lo tanto, los cambios efectuados en el objeto mediante object3 se
“En un sentido los módulos pueden considerarse simplemente como una técnica
mejorada para crear y manejar espacios de nombres” [1] (namespaces). En este
sentido una aplicación importante del concepto de módulo es para la creación de
bibliotecas de clases, es decir, un espacio de nombres que va a contener
diferentes clases.
Atributos: Son las características de los objetos, por ejemplo, los atributos de una
persona son, nombre, apellidos, número de documento, estatura, color de piel,
peso, etcétera.
Una de las premisas de POO, es que la mayoría, sino todos, los atributos de un
objeto deben ser privados, esto para tener seguridad sobre los valores del objeto,
pero entonces...¿cómo acceder a los atributos de una clase?, la
respuesta, encapsulamiento, los métodos de encapsulamiento se utilizan sólo
cuando es apropiado entregar los datos a otro objeto que solicite la información.
2.8. Herencia
En orientación a objetos la herencia es el mecanismo fundamental para
implementar la reutilización y extensibilidad del software. A través de ella los
diseñadores pueden construir nuevas clases partiendo de una jerarquía de clases
ya existente (comprobadas y verificadas) evitando con ello el rediseño, la
remodificación y verificación de la parte ya implementada. La herencia facilita la
creación de objetos a partir de otros ya existentes, obteniendo características
(métodos y atributos) similares a los ya existentes.
Un Coche es un Vehículo que además tiene una Marca y un Modelo. Así yo puedo
hacer:
¿por que se hereda?; si lo vemos del lado de programación es para poder utilizar
métodos, propiedades (campos) y variables de la clase padre en el la clase hijo.
Comencemos con un ejemplo muy simple de herencia, tengo las siguientes clases
que tomare para mi ejemplo.
Tenemos una clase Profesor que hereda de la clase Personal ya echa quedaran
de esta forma:
La clase tendrá tres atributos Id, Nombre y Apellido, y un constructor. Ahora lo que
haremos será que profesor herede de la clase Personal de esta forma:
Para hacer una herencia en c# entre dos clase solo hay que utilizar los dos puntos
seguidos del nombre de la clase padre.
Hoy solo hace falta crear el constructor que me tome los parámetros de la clase
padre de esta forma.
Para decirle que tome los atributos de la clase padre haremos uso de la palabra
clave base y tenemos que colocar los parámetros que tenga la clase padre.
Como puedes ver no tengo atributos en la case hijo, ahora solo tengo que hacer
esto en el Program de la aplicación de consola.
Miremos que en este momento la clase hijo tiene un atributo mas que la clase
padre, lo cual nos da otra característica nueva del hijo que no tiene el padre.
Corramos esto y veamos el cambio.
En la clase padre inicialice esta variable hoy podemos hacer esto en el program.
Este método solo me permitirá sumar dos números pero en la clase Profesor
quiero que me sume tres de esta forma:
Como se puede ver en las imágenes puedo utilizar el método del padre y el que
modifique en el hijo esto se debe a que ahora el método esta sobrecargado,
utilizare el que modifique en el hijo el cual que me suma tres números:
53 Juan González - Ryan León – Estiven Peña
Origen, evolución y características
técnicas del lenguaje de programación C#
Las clases abstractas son aquellas que por sí mismas no se pueden identificar con
algo 'concreto' (no existen como tal en el mundo real), pero sí poseen
determinadas características que son comunes en otras clases que pueden ser
creadas a partir de ellas.
Para que lo comprendas mejor, un ejemplo de clase abstracta sería una llamada
Vehículo: todos ellos realizan acciones similares (arrancar, acelerar, frenar, etc.),
pero sin embargo existen muchos tipos de vehículos diferentes y que se
comportan de forma totalmente distinta (el proceso de arrancarlos no se realiza
siguiendo los mismos pasos, unos tienen que despegar y vuelan como los
aviones, otros se sumergen para desplazarse por debajo del agua como los
submarinos, cada uno de ellos necesita ser frenado de distinto modo...).
Es decir, en el mundo real no existe un objeto 'vehículo' como tal sino que hay
diferentes tipos de vehículo, pero aunque poseen características comunes y
realizan las mismas acciones lo hacen de forma muy diferente (pudiendo además
realizar otras específicas cada uno de ellos).
Así pues, ya que una clase abstracta no representa algo concreto tampoco puede
ser instanciada (no se puede crear un Objeto a partir de ella) pero sí es posible
crear otras clases en base a su definición.
{
private String nombre;
// ----------------------
public Animal() {
}
55 Juan González - Ryan León – Estiven Peña
Origen, evolución y características
técnicas del lenguaje de programación C#
// ----------------------
public String getNombre() {
return this.nombre;
}
// ----------------------
public void setNombre( String nombre ) {
this.nombre = nombre;
}
// ----------------------
public void comer() {
System.out.println( this.getNombre() + " está comiendo...");
}
// ----------------------
public void caminar() {
System.out.println( this.getNombre() + " está caminando...");
}
// ----------------------
// Este método deberá ser compartido por las clases que hereden
}
2.10. Polimorfismo
El polimorfismo suele considerarse el tercer pilar de la programación orientada a
objetos, después de la encapsulación y la herencia. Polimorfismo es una palabra
griega que significa "con muchas formas" y tiene dos aspectos diferentes:
En tiempo de ejecución, los objetos de una clase derivada pueden ser tratados
como objetos de una clase base en lugares como parámetros de métodos y
colecciones o matrices. Cuando ocurre, el tipo declarado del objeto ya no es
idéntico a su tipo en tiempo de ejecución.
Las clases base pueden definir e implementar métodos virtuales, y las clases
derivadas pueden invalidarlos, lo que significa que pueden proporcionar su propia
definición e implementación. En tiempo de ejecución, cuando el código de cliente
llama al método, CLR busca el tipo en tiempo de ejecución del objeto e invoca esa
invalidación del método virtual. Por lo tanto, en el código fuente puede llamar a un
método en una clase base y hacer que se ejecute una versión del método de la
clase derivada.
Crear una jerarquía de clases en la que cada clase de forma específica deriva de
una clase base común.
Usar un método virtual para invocar el método apropiado en una clase derivada
mediante una sola llamada al método de la clase base.
Primero, cree una clase base llamada Shape y clases derivadas como Rectangle,
Circle y Triangle. Dé a la clase Shape un método virtual llamado Draw e invalídelo
en cada clase derivada para dibujar la forma determinada que la clase representa.
Cree un objeto List<Shape> y agregue Circle, Triangle y Rectangle a él. Para
actualizar la superficie de dibujo, use un bucle foreach para iterar por la lista y
llamar al método Draw en cada objeto Shape de la lista. Aunque cada objeto de la
lista tenga un tipo declarado de Shape, se invocará el tipo en tiempo de ejecución
(la versión invalidada del método en cada clase derivada).
using System;
using System.Collections.Generic;
// Virtual method
public virtual void Draw()
{
Console.WriteLine("Performing base class drawing tasks");
}
}
class Program
{
static void Main(string[] args)
{
// Polymorphism at work #1: a Rectangle, Triangle and Circle
// can all be used whereever a Shape is expected. No cast is
// required because an implicit conversion exists from a derived
// class to its base class.
var shapes = new List<Shape>
/* Output:
Drawing a rectangle
Performing base class drawing tasks
Drawing a triangle
Performing base class drawing tasks
Drawing a circle
Performing base class drawing tasks
*/
2.11. Interfaces
En teoría de orientación a objetos, la interfaz de una clase es todo lo que podemos
hacer con ella. A efectos prácticos: todos los métodos, propiedades y variables
públicas (aunque no deberían haber nunca variables públicas, debemos usar
propiedades en su lugar) de la clase conforman su interfaz.
class Contenedor
{
public int Quitar();
public void Meter(int v);
private bool EstaRepetido(int v);
}
Su interfaz está formada por los métodos Quitar y Meter. El método EstaRepetido
no forma parte de la interfaz de dicha clase, ya que es privado.
Así pues: toda clase tiene una interfaz que define que podemos hacer con los
objetos de dicha clase.
En C#, los errores del programa en tiempo de ejecución se propagan a través del
programa mediante un mecanismo denominado excepciones. Las excepciones las
inicia el código que encuentra un error y las detecta el código que puede corregir
dicho error. Las excepciones puede iniciarlas .NET Framework Common
Language Runtime o el código de un programa. Una vez iniciada, una excepción
se propaga hasta la pila de llamadas hasta que encuentra una instrucción catch
para la excepción. Las excepciones no detectadas se controlan mediante un
controlador de excepciones que ofrece el sistema y muestra un cuadro de diálogo.
throw ex;
}
62 Juan González - Ryan León – Estiven Peña
Origen, evolución y características
técnicas del lenguaje de programación C#
Si la instrucción que inicia una excepción no está en un bloque try o si el bloque try
que la encierra no tiene un bloque catch coincidente, el entorno runtime busca una
instrucción try y bloques catch en el método de llamada. El entorno runtime sigue
hasta la pila de llamadas para buscar un bloque catch compatible. Después de
encontrar el bloque catch y ejecutarlo, el control pasa a la siguiente instrucción
después de dicho bloque catch. Una instrucción try puede contener más de un
bloque catch. Se ejecuta la primera instrucción catch que pueda controlar la
excepción; las instrucciones catch siguientes se omiten, aunque sean compatibles.
Por consiguiente, los bloques catch deben ordenarse siempre de más específico
(o más derivado) a menos específico. Por ejemplo:
Ciclo while
La instrucción while ejecuta una instrucción o un bloque de instrucciones mientras
una expresión booleana especificada se evalúa como true. Como esa expresión
se evalúa antes de cada ejecución del bucle, un bucle while se ejecuta cero o
varias veces. Esto es diferente del bucle do que se ejecuta una o varias veces.
En cualquier punto del bloque de instrucciones while, se puede salir del bucle
mediante la instrucción break.
También se puede salir de un bucle while mediante las instrucciones goto, return o
throw.
int n = 0;
while (n < 5)
{
Console.WriteLine(n);
n++;
}
2.13. Arreglos
Antes de comenzar a explicaros con mayor claridad qué es un array quiero
advertir nuevamente a los programadores de C/C++: En C#, aunque parecidos, los
arrays son diferentes tanto semántica como sintácticamente, de modo que te
recomiendo que no pases por alto esta entrega.
Bien, una vez hechas todas las aclaraciones previas, creo que podemos
comenzar. Un array es un indicador que puede almacenar varios valores
simultáneamente. Cada uno de estos valores se identifica mediante un número al
cual se llama índice. Así, para acceder al primer elemento del array habría que
usar el índice cero, para el segundo el índice uno, para el tercero el índice dos, y
así sucesivamente. Que nadie se preocupe si de momento todo esto es un poco
confuso, ya que lo voy a ir desmenuzando poco a poco. Vamos a ver cómo se
declara un array:
tipo[] variable;
Bien, como veis es muy parecido a como se declara una variable normal, sólo que
hay que poner corchetes detrás del tipo. Los programadores de C/C++ habrán
observado inmediatamente la diferencia sintáctica. En efecto, en la declaración de
un array en C# los corchetes se colocan detrás del tipo y no detrás de la variable.
Esta pequeña diferencia sintáctica se debe a una importante diferencia semántica:
aquí los arrays son objetos derivados de la clase System.Array. Por lo tanto, y esto
es muy importante, cuando declaramos un array en C# este aún no se habrá
creado, es decir, no se habrá reservado aún memoria para él. En consecuencia,
los arrays de C# son todos dinámicos, y antes de poder usarlos habrá que
instanciarlos, como si fuera cualquier otro objeto. Veamos un breve ejemplo de lo
que quiero decir:
En efecto, tal como podéis apreciar, el array nombres será utilizable únicamente a
partir de su instanciación. En este ejemplo, el número 3 que está dentro de los
corchetes indica el número total de elementos de que constará el array. No os
equivoquéis, puesto que todos los arrays de C# están basados en cero, esto es, el
primer elemento del array es cero. Por lo tanto, en este caso, el último elemento
sería 2 y no 3, ya que son tres los elementos que lo componen (0, 1 y 2). Veamos
un ejemplo algo más completo y después lo comentamos:
using System;
namespace Arrays
{
class ArraysApp
{
static void Main()
{
string[] nombres; // Declaración del array
ushort num=0;
do
{
try
{
Console.Write("¿Cuántos nombres vas a introducir? ");
num=UInt16.Parse(Console.ReadLine());
}
66 Juan González - Ryan León – Estiven Peña
Origen, evolución y características
técnicas del lenguaje de programación C#
catch
{
continue;
}
} while (num==0);
nombres=new string[num]; // Instanciación del array
for (int i=0; i<num; i++)
{
Console.Write("Escribe el nombre para elemento {0}: ", i);
nombres[i]=Console.ReadLine();
}
Console.WriteLine("Introducidos los {0} nombres", num);
Console.WriteLine("Pulsa INTRO para listarlos");
string a=Console.ReadLine();
for (int i=0; i<num; i++)
{
Console.WriteLine("Elemento {0}: {1}", i, nombres[i]);
}
a=Console.ReadLine();
}
}
}
Veamos ahora la salida en la consola (en rojo, como siempre, lo que se ha escrito
durante la ejecución del programa):
using System;
namespace Arrays2
{
class Arrays2App
{
static void Main()
{
ushort num=3;
do
{
try
{
Console.Write("¿Cuántos nombres vas a introducir? ");
num=UInt16.Parse(Console.ReadLine());
}
catch
{
continue;
}
} while (num==0);
string[] nombres=new string[num]; // Declaración e instanciación del array
for (int i=0; i<num; i++)
using System;
namespace Arrays3
Elemento 0: Juanito
71 Juan González - Ryan León – Estiven Peña
Origen, evolución y características
técnicas del lenguaje de programación C#
Elemento 1: Jaimito
Elemento 2: Joselito
Por otro lado, el hecho de que un array haya sido inicializado no quiere decir que
sea inamovible. Si un array que ya contiene datos se vuelve a instanciar, el array
volverá a estar vacío, y obtendrá las dimensiones de la nueva instanciación.
Bien, todos estos arrays que hemos explicado hasta el momento son arrays
unidimensionales, es decir, que tienen una sola dimensión (un solo índice). Sin
embargo esto no soluciona aún todas las necesidades del programador.
Pongamos, por ejemplo, que queremos almacenar las combinaciones de las ocho
columnas de una quiniela de fútbol en un array.¿Cómo lo hacemos? Pues bien, el
mejor modo es utilizar un array multidimensional.
tipo[,,] variable;
Como ves, hay dos comas dentro de los corchetes, lo cual indica que el array es
tridimensional, puesto que los tres índices del mismo se separan uno de otro por
comas. Veamos un pequeño ejemplo que lo clarifique un poco más:
string[,] alumnos = new string[2,4];
Este array es bidimensional y serviría para almacenar una lista de alumnos por
aula, esto es, tenemos dos aulas (el primer índice del array es 2) y cuatro alumnos
en cada una (el segundo índice es 4). Veamos un poco de código y una tabla para
que os hagáis una idea de cómo se almacena esto:
alumnos[0,0]="Lolo";
alumnos[0,1]="Mario";
alumnos[0,2]="Juan";
alumnos[0,3]="Pepe";
alumnos[1,0]="Lola";
alumnos[1,1]="María";
AULA 0 AULA 1
NOMBRE 0 Lolo Lola
NOMBRE 1 Mario María
NOMBRE 2 Juan Juana
NOMBRE 3 Pepe Pepa
¿Que quieres saber por qué he separado a los chicos de las chicas? Bueno, no es
que sea un retrógrado, es para que se vea mejor todo esto. Mira que sois
detallistas... Bueno, creo que va quedando bastante claro. ¿Y cómo recorremos un
array multidimensional? Pues con bucles anidados. Vamos ya con un ejemplo más
completito de todo esto. Este pequeño programa pregunta al usuario por el
número de columnas que quiere generar de una quiniela de fútbol, y después las
rellena al azar y las muestra en pantalla:
using System;
namespace Quinielas
{
class QuinielasApp
{
static void Main()
{
const char local='1';
const char empate='X';
const char visitante='2';
74 Juan González - Ryan León – Estiven Peña
Origen, evolución y características
técnicas del lenguaje de programación C#
const byte numFilas=14;
byte numColumnas=0;
char[,] quiniela;
byte azar;
Random rnd=new Random(unchecked((int) DateTime.Now.Ticks));
do
{
try
{
Console.WriteLine("Mínimo una columna y máximo ocho");
Console.Write("¿Cuántas columnas quieres generar? ");
numColumnas=Byte.Parse(Console.ReadLine());
}
catch
{
continue;
}
} while (numColumnas<1 || numColumnas>8);
quiniela=new char[numColumnas, numFilas];
for (byte i=0; i<numColumnas; i++)
{
for (byte j=0; j<numFilas; j++)
{
azar=(byte) (rnd.NextDouble()*3D);
switch (azar)
Random rnd=new Random(unchecked((int) DateTime.Now.Ticks));
Bien, el constructor de esta clase tiene dos sobrecargas: una de ellas es sin
argumentos, y la otra acepta un argumento de tipo int, que es la que hemos
usado. ¿Por qué? Porque de lo contrario siempre generaría los mismos números
en cada ejecución del programa, lo cual no sería muy útil en este caso. Como
necesitamos que se generen números distintos tenemos que pasarle números
diferentes en el argumento int del constructor de la clase Random, y el modo más
eficaz de conseguirlo es hacer que ese número dependa del tiempo que lleve
encendido el ordenador. Por otro lado, el número lo generamos al ejecutar el
método NextDouble, el cual nos retorna un número mayor o igual a 0 y menor que
esta es la línea:
azar=(byte) (rnd.NextDouble()*3D);
¿Por qué lo hemos multiplicado por 3D? Pues bien, como queremos números
enteros entre 0 y 2 (o sea, 0, 1 o 2) bastará con multiplicar este número (recuerda
que está entre cero y uno) por 3. ¿Y la D? Ahora voy, hombre. ¿Os acordáis de
los sufijos en los literales, para indicar si se debía considerar si el número era de
un tipo o de otro? Pues aquí está la explicación. Dado que el método NextDouble
retorna un valor double, tenemos que multiplicarlo por otro valor double. Por eso le
ponemos el sufijo "D" al número tres. Después todo ese resultado se convierte a
byte y se asigna a la variable azar, que es la que se comprueba en el switch para
asignar el carácter necesario según su valor a cada elemento del array.
Por lo demás creo que a estas alturas no debería tener que explicaros gran cosa:
tenemos un par de bucles anidados para asignar los valores al array y después
otros dos bucles anidados para recorrer dicho array y mostrar su contenido en la
consola.
...
for (byte i=0; i<numColumnas; i++)
{
for (byte j=0; j<14; j++)
{
azar=(byte) (rnd.NextDouble()*3D);
switch (azar)
{
2.15. Arraylist
Se crea el objeto de
Tipo ArrayList Así:
ListaNaves = new ArrayList();
Con Esto el constructor default crea un ArrayList vacío.
Count: es una propiedad de solo lectura que optiene el número de elementos que
cntiene el ArrayList.
2.16. HashMap
Un HashMap es la implementación de la interface Map, esta interface es un tipo
de Collection que almacena datos asociando una llave a un valor, esta interface
sirve para muchas cosas y tiene ciertas caracteristicas que la definen, por ejemplo,
no permite key duplicados, cada key tiene que estar asociado a un valor como
máximo, si agregas un key que ya existe sobrescribe el valor del key anterior, solo
permite Object types lo que quiere decir que no puedes poner un valor primitivo.
using System.Collections.Generic;
void HashMaps()
{
Dictionary<string, int?> map = new Dictionary<string, int?>();
string s = "test";
map[s] = 1;
int i = map[s].Value;
i = map.Count;
bool b = map.Count == 0;
map.Remove(s);
}
2.17. Genéricos
Los genéricos, y más concretamente en este post los tipos genéricos, son un
mecanismo de C# que nos ayuda a maximizar la reutilización de código. La
reutilización de código se logra a través de el uso de plantillas (templates) de
código en las cuales se insertan marcadores (placeholders) que representarán los
tipos de dato que usaremos en nuestra plantilla.
Sintaxis
La declaración de tipos genéricos se realiza casi como cualquier otro tipo, con la
diferencia de que tenemos que declarar los placeholders entre signos < y >, por
ejemplo:
Para hacer uso de un tipo genérico la sintaxis es más o menos igual a cualquier
tipo por referencia: debemos usar el operador new, el constructor de la clase e
indicarle dentro de < y > los tipos con los que queremos que se reemplaze el
marcador.
Console.WriteLine(cajaDeEntero.Content); // 5
Console.WriteLine(cajaDeString.Content); // Hola mundo
No hay “límite” en cuanto al nombre o cantidad de tipos que podemos usar. Usar
los genéricos permiten dos cosas: Incrementar la reutilización de código
manteniendo el tipado fuerte y reducir el impacto al desempeño en nuestras apps
al evitar el boxing y unboxing, de ahí la importancia de su existencia.
2.18. Linq
LINQ o Language Integrated Query son un conjunto herramientas de Microsoft
para realizar todo tipo de consultas a distintas fuentes de datos: objetos, xmls,
bases de datos, etc... Para ello, usa un tipo de funciones propias, que unifica las
operaciones más comunes en todos los entornos, con esto, se consigue un mismo
lenguaje para todo tipo de tareas con datos.
LINQ nace en el Framework 3.5 y pronto coge una gran aceptación entre el mundo
de .net, tanto es asi, que enseguida salen proveedores de terceros, para el uso de
este lenguaje con JSON, CSVs, o inclusos APIs como la de Twitter y Wikipedia.
LINQ en C#
La sintaxis es parecida a la existente en SQL, pero con la ventaja de que tenemos
la potencia de .net y visual studio a la hora de codificar. Ahora vamos a ver un
sencillo ejemplo, con una consulta linq en c# para objetos (LINQ to objetcs):
Como podemos ver, accedemos a una colección y filtramos todos los elementos
que cumplan que la propiedad 1 sea verdadera. Del resultado de esta consulta,
podemos sacar un listado de elementos con ToList(), el número de ellos con un
count(), extraer los datos a un array, entre otros.
Las palabras claves de este lenguaje de programacion c sharp son los siguientes
nombres no son válidos como identificadores ya que tienen un significado
especial en el lenguaje: abstract, as, base, bool, break, byte, case
, catch, char, checked, class, const, continue, decimal, default, delegate, do,
double, else, enum, event, explicit, extern, false, finally, fixed, float, for, foreach,
goto, if, implicit, in, int, interface, internal, lock, is, long, namespace, new, null,
object, operator, out, override, params, private, protected, public, readonly, ref,
return, sbyte, sealed, short, sizeof, stackalloc, static, string, struct, switch, this,
throw, true, try, typeof, uint, ulong, unchecked, unsafe, ushort, using, virtual, void,
while.
class @class
{
static void @static(bool @bool)
{
if (@bool)
Console.WriteLine("cierto");
else
Console.WriteLine("falso");
}
}
Lo que se ha hecho en el código anterior ha sido usar @ para declarar una clase
de nombre class con un método de nombre static que toma un parámetro de
nombre bool, aún cuando todos estos nombres son palabras reservadas en C#.
Hay que precisar que aunque el nombre que nosotros es cribamos sea por
ejemplo @class, el nombre con el que el compilador va a tratar internamente al
identificador es solamente class.
class A
{
int a; // (1)
int @a; // (2)
public static void Main()
{}
}
Si intentamos compilar este código se producirá un error que nos informará de que
el campo de nombre a ha sido declarado múltiples veces en la clase A.
Esto se debe a que como @ no forma parte en realidad del nombre del
identificador al que precede, las declaraciones marcadas con comentarios como
(1) y (2) son equivalentes.
Hay que señalar por último una cosa respecto al carácter @: sólo puede preceder
al nombre de un identificador, pero no puede estar contenido dentro del mismo. Es
decir, identificadores como i5322@fie.us.es no son válidos.
No importa el orden en que hayan sido definidas las clases ni las funciones
CIL (el lenguaje intermedio de .NET) está estandarizado, mientras que los
bytecodes de java no lo están
Compilación condicional
Conclusión
Al concluir este trabajo nos damos cuenta que nuestro proceso de formación está
basado en un continuo cambio, de conocimiento para el mejoramiento de nuestra
labores (que aplicamos en base a un estudio que se está adquiriendo para mejorar
día a día) y con el objetivo de llegar a ser un buen licenciado en informática, con
las competencias que la materia nos ha suministrado y haciéndonos saber lo
importante que son los lenguajes de programación, ya que a la hora de desarrollar
aplicaciones o programas siempre será tema de controversia, ya que al principio
nunca se sabe por cual lenguaje declinarse, pero todo dependerá del gusto de la
persona con el desarrollo del tiempo y estudiando todos los lenguajes
competentes como ya conocemos unos de los mejores hoy en día del cual se está
93 Juan González - Ryan León – Estiven Peña
Origen, evolución y características
técnicas del lenguaje de programación C#
tratando en este tema que es el C#, es un lenguaje de programación orientado a
objetos desarrollado y estandarizado por Microsoft como parte de su plataforma
.NET.
Bibliografía
https://www.campusmvp.es/recursos/post/historia-del-lenguaje-c-sharp-pasado-
presente-y-evolucion.aspx
https://docs.microsoft.com/es-es/dotnet/csharp/whats-new/csharp-version-history
https://docs.microsoft.com/es-es/dotnet/csharp/programming-guide/classes-and-
structs/using-structs
https://docs.microsoft.com/es-es/dotnet/csharp/programming-guide/
http://programacion1abundiz.blogspot.com/2009/09/generalidades-y-
caracteristicas-c_08.html
http://di002.edv.uniovi.es/~benja/cs/presentaciones/2-
CsCaracteristicasGenerales.pdf
http://www.cartagena99.com/recursos/alumnos/apuntes/Practica
%202.%20Introduccion%20a%20la%20programacion%20visual.pdf
https://prezi.com/svgcz8hk7js5/modo-consola-y-grafico-en-c/
https://es.wikipedia.org/wiki/C_Sharp
https://prezi.com/peupc5qiedn7/entorno-de-visual-c/
https://msdn.microsoft.com/es-ar/library/yht2cx7b(v=vs.80).aspx
https://geeks.ms/etomas/2010/07/14/c-bsico-que-es-la-herencia/
https://informaticapc.com/poo/clases-abstractas.php
https://geeks.ms/etomas/2010/07/07/c-bsico-interfaces/
Anexos