Curso de C#
Introduccin al lenguaje de programacin C#
-
Caractersticas del lenguaje C#
Aspectos Lxicos
E/S bsica
Tipos de datos
Variables y constantes
Operadores y expresiones Estructuras de control
C# (ledo en ingls "C Sharp" y en espaol "C Almohadilla") es el nuevo lenguaje de propsito general diseado por Microsoft para su plataforma .NET.
Aunque es posible escribir cdigo para la plataforma .NET en muchos otros lenguajes,
C# es el nico que ha sido diseado especficamente para ser utilizado en ella, por lo
que programarla usando C# es mucho ms sencillo e intuitivo que hacerlo con
cualquiera de los otros lenguajes ya que C# carece de elementos heredados
innecesarios en .NET. Por esta razn, se suele decir que C# es el lenguaje nativo de .NET
Caractersticas del lenguaje C#
Aunque es pronto para entrar con detenimiento en el lenguaje C# podemos adelantar
las caractersticas ms relevantes de este lenguaje, caractersticas que se describen
con profundidad posteriormente, durante el estudio detallado de los elementos del
lenguaje.
Es autocontenido. Un programa en C# no necesita de ficheros
adicionales al propio cdigo fuente, como los ficheros de cabecera
(.h) de C++, lo que simplifica la arquitectura de los proyectos
software desarrollados con C++.
Es homogneo. El tamao de los tipos de datos bsicos es fijo e
independiente del compilador, sistema operativo o mquina en la
que se compile (no ocurre lo que en C++), lo que facilita la
portabilidad del cdigo.
Es actual. C# incorpora en el propio lenguaje elementos que se han
demostrado ser muy tiles para el desarrollo de aplicaciones como
el tipo bsico decimal que representa valores decimales con 128
bits, lo que le hace adecuado para clculos financieros y
monetarios, incorpora la instruccin foreach, que permite una
cmoda iteracin por colecciones de datos, proporciona el tipo
bsico string, permite definir cmodamente propiedades
(campos de acceso controlado), etc.
Est orientado a objetos. C# soporta todas las caractersticas
propias del paradigma de la programacin orientada a objetos:
encapsulacin, herencia y polimorfismo.
o Encapsulacin: adems de los modificadores de accceso
convencionales: public, private y protected, C# aade el
modificador internal, que limita el acceso al proyecto actual.
o C# slo admite herencia simple.
o Todos los mtodos son, por defecto, sellados, y los mtodos
redefinibles han de marcarse, obligatoriamente, con el
modificador virtual.
Delega la gestin de memoria. Como todo lenguaje de .NET, la
gestin de la memoria se realiza automticamente ya que tiene a
su disposicin el recolector de basura del CLR. Esto hace que el
programador se desentienda de la gestin directa de la memoria
(peticin y liberacin explcita) evitando que se cometan los errores habituales de este tipo de gestin en C++, por ejemplo.
En principio, en C# todo el cdigo incluye numerosas restricciones
para asegurar su seguridad no permite el uso de punteros, por
ejemplo. Sin embargo, y a diferencia de Java, en C# es posible
saltarse dichas restricciones manipulando objetos a travs de
punteros. Para ello basta marcar regiones de cdigo como
inseguras (modificador unsafe) y podrn usarse en ellas punteros
de forma similar a cmo se hace en C++, lo que puede resultar
vital para situaciones donde se necesite una eficiencia y velocidad procesamiento muy grandes.
Emplea un sistema de tipos unificado. Todos los tipos de datos
(incluidos los definidos por el usuario) siempre derivarn, aunque
sea de manera implcita, de una clase base comn llamada
System.Object, por lo que dispondrn de todos los miembros
definidos en sta clase. Esto tambin es aplicable, lgicamente, a
los tipos de datos bsicos.
Proporciona seguridad con los tipos de datos. C# no admiten ni
funciones ni variables globales sino que todo el cdigo y datos han
de definirse dentro de definiciones de tipos de datos, lo que reduce
problemas por conflictos de nombres y facilita la legibilidad del cdigo.
C# incluye mecanismos que permiten asegurar que los accesos a
tipos de datos siempre se realicen correctamente:
o No pueden usarse variables que no hayan sido inicializadas.
o Slo se admiten conversiones entre tipos compatibles
o Siempre se comprueba que los ndices empleados para acceder
a los elementos de una tabla (vector o matriz) se encuentran
en el rango de valores vlidos.
o Siempre se comprueba que los valores que se pasan en una
llamada a mtodos que pueden admitir un nmero indefinido
de parmetros (de un cierto tipo) sean del tipo apropiado.
Proporciona instrucciones seguras. En C# se han impuesto una
serie de restricciones para usar las instrucciones de control ms
comunes. Por ejemplo, toda condicin est controlada por una
expresin condicional, los casos de una instruccin condicional
mltiple (switch) han de terminar con una instruccin break o
goto, etc.
Facilita la extensibilidad de los operadores. C# permite redefinir
el significado de la mayora de los operadores -incluidos los de
conversin, tanto para conversiones implcitas como explcitas-
cuando se aplican a diferentes tipos de objetos.
Permite incorporar modificadores informativos sobre un tipo o
sus miembros. C# ofrece, a travs del concepto de atributos, la
posibilidad de aadir, a los metadatos del mdulo resultante de la
compilacin de cualquier fuente, informacin sobre un tipo o sus
miembros a la generada por el compilador que luego podr ser
consultada en tiempo ejecucin a travs de la biblioteca de
reflexin de .NET. Esto, que ms bien es una caracterstica propia
de la plataforma .NET y no de C#, puede usarse como un
mecanismo para definir nuevos modificadores.
Facilita el mantenimiento (es "versionable"). C# incluye una
poltica de versionado que permite crear nuevas versiones de tipos
sin temor a que la introduccin de nuevos miembros provoquen
errores difciles de detectar en tipos hijos previamente
desarrollados y ya extendidos con miembros de igual nombre a los
recin introducidos.
Apuesta por la compatibilidad. C# mantiene una sintaxis muy
similar a C++ o Java que permite, bajo ciertas condiciones, incluir
directamente en cdigo escrito en C# fragmentos de cdigo escrito
en estos lenguajes.
En resumen, podemos concluir que:
Es un lenguaje orientado al desarrollo de componentes (mdulos
independientes de granularidad mayor que los objetos) ya que los
componentes son objetos que se caracterizan por sus
propiedades, mtodos y eventos y estos aspectos de los
componentes estn presentes de manera natural en C#.
En C# todo son objetos: desaparece la distincin entre tipos
primitivos y objetos de lenguajes como Java o C++ (sin penalizar la
eficiencia como en LISP o Smalltalk).
El software es robusto y duradero: el mecanismo automtico de
recoleccin de basura, la gestin de excepciones, la comprobacin
de tipos, la imposibilidad de usar variables sin inicializar y hacer
conversiones de tipo (castings) no seguras, gestin de versiones,
etc. ayudan a desarrollar software fcilmente mantenible y poco
propenso a errores.
Adems, no hay que olvidar el aspecto econmico: la posibilidad de
utilizar C++ puro (cdigo no gestionado o inseguro), la facilidad de
interoperabilidad (XML, SOAP, COM, DLLs...) junto con un
aprendizaje relativamente sencillo (para los que ya conocen otros
lenguajes de programacin) hace que el dominio y uso del lenguaje junto a otras tecnologas sea muy apreciado.
Aspectos Lxicos
En esta seccin presentaremos las reglas sintcticas bsicas que deben cumplir los
programas escritos en C# y veremos los elementos fundamentales de cualquier
programa en C# (identificadores, comentarios, palabras reservadas, etc.). Se trata, en
definitiva, de la parte instrumental y bsica, adems de imprescindible, de cualquier manual de programacin.
Es costumbre desde la poca dorada del lenguaje C (quiz una de las pocas
costumbres que se mantienen en el mundo de la informtica) que se presente un
lenguaje de programacin empleando un programa que muestra en la consola el
mensaje Hola, mundo! (para ser ms precisos deberamos decir Hello,
world!). Sigamos manteniendo esta costumbre:
Hola, mundo!
/*
Fichero: Saludo.cs
Fecha: Enero de 2004
Autores: F. Berzal, F.J. Cortijo y J.C.Cubero
Comentarios:
Primer programa escrito en C#
*/
using System;
public class SaludoAlMundo
{
public static void Main( )
{
// Mostrar en la consola el mensaje: Hola, mundo!
Console.WriteLine("Hola, mundo!");
Console.ReadLine(); // Enter para terminar.
}
}
Lo primero que hay que resaltar es que C# es un lenguaje sensible a las
maysculas, por lo que, por ejemplo, Main es diferente a main, por lo que deber
prestar atencin a la hora de escribir el cdigo ya que la confusin entre maysculas y minsculas provocar errores de compilacin.
Todas las rdenes acaban con el smbolo del punto y coma (;). Los bloques de rdenes
(parte iterativa de un ciclo, partes dependientes de una instruccin condicional -parte
if y parte else-, cdigo de un mtodo, etc.) se encierran entre llaves { } y no se
escribe el ; despus de la llave de cierre (observar en el ejemplo el mtodo Main).
Si el lector ha programado en C++ no habr tenido dificultad en localizar los
comentarios que hemos insertado en el programa ya que la sintaxis es idntica en
ambos lenguajes: existen comentarios de lnea, cuyo comienzo se especifica con los
caracteres // y comentarios de formato libre, delimitados por /* y */.
C# es un lenguaje orientado a objetos y todo est encapsulado en clases, incluso la
funcin Main que es un mtodo (especial) del objeto aplicacin. En el ejemplo la clase
se llama SaludoAlMundo.
La lnea using System declara que se va a usar el espacio de nombres (namespace)
llamado System. Esta declaracin no es igual a un #include de C#, tan solo evita
escribir el prefijo System cada vez que se use un elemento de ese espacio de
nombres. Por ejemplo, Console es un objeto del espacio de nombres System; en
lugar de escribir su nombre completo (System.Console) podemos escribir solamente
Console al haber declarado que se va a emplear el espacio de nombres System.
Cuando este programa se compile y se proceda a su ejecucin, la primera funcin
(estrictamente hablando, mtodo) en ejecutarse ser Main. Los programadores de
C++ debern tener especial cuidado y no confundirlo con main().
La funcin Main() tiene los siguientes prototipos vlidos:
Si la funcin no devuelve ningn valor, puede usarse:
public static void Main( )
public static void Main(string [] args)
La diferencia est en la posibilidad de suministrar argumentos en la
llamada a la ejecucin del programa. Main() procesan los
argumentos tomndolos de la lista de cadenas args (ms adelante
se detalla cmo).
Si la funcin devuelve un valor al proceso que invoca la ejecucin del
programa, el valor debe ser entero (int) y, como en el caso
anterior, puede usarse:
public static int Main( )
public static int Main(string [] args)
La convencin es que el valor 0 indica que el programa termina
correctamente.
En cuanto a las instrucciones que efectivamente se ejecutan, el mtodo Main() llama
a los mtodos WriteLine() y ReadLine() del objeto Console. El primero se
encargan de mostrar una cadena en la consola (Smbolo de Sistema, en Windows XP) y
el segundo de tomar una cadena de la consola (teclado). Aunque esta ltima
instruccin pueda parecer innecesaria, de no escribirla se mostrara la cadena Hola,
mundo! y se cerrara inmediatamente la consola, por lo que no podramos contemplar
el resultado de la ejecucin. La ltima instruccin detiene la ejecucin del programa
hasta que se introduce una cadena (pulsar ENTER es suficiente) y a continuacin
termina la ejecucin del programa y se cierra la consola. As, cuando usemos aplicaciones de consola siempre terminaremos con esta instruccin.
A continuacn detallaremos ciertos aspectos lxicos importantes de los programas
escritos en C#, algunos de los cuales ya se han comentado brevemente como
explicacin al programa introductorio.
Comentarios
Los comentarios tienen como finalidad ayudar a comprender el cdigo fuente y estn
destinados, por lo tanto, a los programadores. No tienen efecto sobre el cdigo
ejecutable ya que su contenido es ignorado por el compilador (no se procesa). La
sintaxis de los comentarios en C# es idntica a la de C++ y se distinguen dos tipos de comentarios:
Comentarios de lnea. Estn precedidos de la construccin // y su
efecto (mbito) termina en la lnea en la que est inmerso.
Comentarios de formato libre. Estn delimitados por las
construcciones /* y */ y pueden extenderse por varias lneas.
Ejemplos de comentarios
// En una lnea, al estilo de C++
/*
En mltiples lneas, como se viene
haciendo desde "los tiempos de C"
*/
/* Este tipo de comentario ya no es habitual */
Identificadores
Un identificador es un nombre con el que nos referimos a algn elemento de nuestro
programa: una clase, un objeto, una variable, un mtodo, etc. Se imponen algunas restricciones acerca de los nombres que pueden emplearse:
Deben comenzar por una letra letra o con el carcter de subrayado
(_), que est permitido como carcter inicial (como era tradicional
en el lenguaje C).
No pueden contener espacios en blanco.
Pueden contener caracteres Unicode, en particular secuencias de
escape Unicode.
Son sensibles a maysculas/minsculas.
No pueden coincidir con palabras reservadas (a no ser que tengan el
prefijo @ que habilita el uso de palabras clave como identificadores).
Los identificadores con prefijo @ se conocen como identificadores
literales. Aunque el uso del prefijo @ para los identificadores que no
son palabras clave est permitido, no se recomienda por regla de estilo.
Palabras reservadas
Las palabras reservadas son identificadores predefinidos reservados que tienen un
significado especial para el compilador por lo que no se pueden utilizar como
identificadores en un programa a menos que incluyan el carcter @ como prefijo.
Las palabras reservadas en C# son, por orden alfabtico:
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, is, lock, 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, volatile, while
Literales
Un literal es una representacin en cdigo fuente de un valor. Todo literal tiene
asociado un tipo, que puede ser explcito (si se indica en el literal, mediante algn sufijo, por ejemplo) o implcito (se asume uno por defecto).
Los literales pueden ser:
Literales lgicos.
Existen dos valores literales lgicos: true y false. El tipo de un
literal lgico es bool.
Literales enteros.
Permiten escribir valores de los tipos enteros: int, uint, long y
ulong. Los literales enteros tienen dos formatos posibles: decimal
y hexadecimal. Los literales hexadecimales tienen el sufijo 0x.
El tipo de un literal entero se determina como sigue:
o Si no tiene sufijo, su tipo es int.
o Si tiene el sufijo U o u, su tipo es uint o ulong.
o Si tiene el sufijo L o l, su tipo es long o ulong.
o Si tiene el sufijo UL, Ul, uL, ul, LU, Lu, lU o lu es de tipo
ulong.
A la hora de escribir literales de tipo long se recomienda usar L en
lugar de l para evitar confundir la letra l con el dgito 1.
Literales enteros
123 // int
0x7B // hexadecimal
123U // unsigned
123ul // unsigned long
123L // long
Literales reales.
Los literales reales permiten escribir valores de los tipos float,
double y decimal.
El tipo de un literal real se determina como sigue:
o Si no se especifica sufijo, el tipo es double.
o Si el sufijo es F o f es de tipo float.
o Si el sufijo es D o d es de tipo double.
o Si el sufijo es M o m es de tipo decimal.
Hay que tener en cuenta que, en un literal real, siempre son
necesarios dgitos decimales tras el punto decimal. Por ejemplo,
3.1F es un literal real, pero no as 1.F.
Literales reales
1f, 1.5f, 1e10f, 123.456F, 123f y 1.23e2f // float
1d, 1.5d, 1e10d, 123.456D, 123.0 y 123D // double
1m, 1.5m, 1e10m, 123.456M, 123.456m y 12.3E1M //
decimal.
Literales de caracteres.
Un literal de caracteres representa un carcter nico y
normalmente est compuesto por un carcter entre comillas
simples, por ejemplo 'A'.
Una secuencia de escape sencilla representa una codificacin de
caracteres Unicode y est formada por el carcter \ seguido de otro
carcter. Las secuencias vlidas se describe en la siguiente tabla.
Secuencia de
escape
Nombre del
carcter
Codificacin
Unicode
\' Comilla simple 0x0027
\" Comilla doble 0x0022
\\ Barra invertida 0x005C
\0 Null 0x0000
\a Alerta 0x0007
\b Retroceso 0x0008
\f Avance de pgina 0x000C
\n Nueva lnea 0x000A
\r Retorno de carro 0x000D
\t Tabulacin
horizontal 0x0009
\v Tabulacin vertical 0x000B
El tipo de un literal de caracteres es char.
Literales de caracteres
'A' // caracter sencillo
'\u0041' // caracter Unicode
'\x0041' // unsigned short hexadecimal
'\n' // caracter de escape: CR+LF
Literales de cadena.
C# admite dos formatos de literales de cadena: literales de cadena
tpicos y literales de cadena textuales. El tipo de un literal de
cadena es string.
Un literal tpico de cadena consta de cero o ms caracteres entre
comillas dobles y puede incluir secuencias de escape sencillas y secuencias de escape hexadecimales y Unicode.
Literales tipicos de cadena
"!Hola, mundo!" // !Hola, mundo!
"!Hola, \t mundo!" // !Hola, mundo!
"" // La cadena vacia
Un literal de cadena textual consta del carcter @ seguido de un
carcter de comillas dobles, cero o ms caracteres y un carcter de
comillas dobles de cierre. Por ejemplo, @"Hola". En estos literales
los caracteres se interpretan de manera literal y no se procesan las
secuencias de escape, con la nica excepcin de la secuencia \".
Un literal de cadena textual puede estar en varias lneas.
Literales de cadena textuales
@"!Hola, \t mundo!" // !Hola, \t mundo!
"Me dijo \"Hola\" y me asust" // Me dijo "Hola" y
me asust
@"Me dijo ""Hola"" y me asust" // Me dijo "Hola" y
me asust
"\\\\servidor\\share\\file.txt" //
\\servidor\share\file.txt
@"\\servidor\share\file.txt" //
\\servidor\share\file.txt
@"uno // Esta es una
cadena distribuida
dos" // en dos lineas.
Literal null.
Su nico valor es null y su tipo es el tipo null.
rdenes
Delimitadas por punto y coma (;) como en C, C++ y Java. Los bloques { ... } no necesitan punto y coma al final.
E/S bsica
Las operaciones de entrada y salida tienen como objetivo permitir que el usuario pueda
introducir informacin al programa (operaciones de entrada) y que pueda obtener
informacin de ste (operaciones de salida). En definitiva, tratan de la comunicacin entre el usuario y el programa.
La manera ms simple de comunicacin es mediante la consola. La consola ha sido el
modo tradicional de comunicacin entre los programas y el usuario por su simplicidad.
Las aplicaciones basadas en ventanas resultan mucho ms atractivas y cmodas para
el usuario y es ste, sin duda, el tipo de comunicacin que deberemos emplear para
productos finales. Los programas que no requieran una mucha interaccin con el
usuario, no obstante, se construyen y se ponen en explotacin mucho ms rpidamente si se utiliza la consola como medio de comunicacin.
Aplicaciones en modo consola
Estas aplicaciones emplean la consola para representar las secuencias de entrada,
salida (y error) estndar.
Una aplicacin de consola se crea en Visual Studio .NET seleccionando Archivo,
Nuevo y Proyecto. Cuando aparece la ventana Nuevo proyecto se selecciona
Proyectos de Visual C# y Aplicacin de consola:
El acceso a la consola lo facilita la clase Console, declarada en el espacio de nombres
System. Esa clase proporciona la compatibilidad bsica para aplicaciones que leen y
escriben caracteres en la consola. No es necesario realizar ninguna accin para poder
obtener datos de la consola a partir de la entrada estndar (teclado) o presentarlos en
la salida estndar (consola) ya que estos flujos (junto con el del error estndar) se
asocian a la consola de manera automtica, como ocurre en C++, por ejemplo, con
cin, cout y cerr.
Los mtodos bsicos de la clase Console son WriteLine y ReadLine, junto con sus
variantes Write y Read:
WriteLine escribe una lnea en la salida estndar, entendiendo que
escribe el terminador de lnea actual (por defecto la cadena
"\r\n").
La versin ms simple de este mtodo recibe un nico argumento
(una cadena) cuyo valor es el que se muestra:
Console.WriteLine ("!Hola, " + "mundo!");
// Escribe: !Hola, mundo!
Otra versin permite mostrar variables de diferentes tipos (sin
necesidad de convertirlas a string. La llamada tiene un nmero
indeterminado de argumentos: el primero es una cadena de
formato en la que las variables a mostrar se indican con {0}, {1},
etc. y a continuacin se enumeran las variables a mostrar,
entendiendo que la primera se "casa" con {0}, la segunda con {1},
etc. Esta manera de mostrar los datos recuerda a la instruccin
printf de C, que cay en desuso con C++ ...
int TuEdad = 25;
string TuNombre = "Pepe";
Console.WriteLine ("Tienes {0} aos, {1}.", TuEdad,
TuNombre);
// Escribe: Tienes 25 aos, Pepe.
El mtodo Write hace lo mismo que WriteLine aunque no escribe
el terminador de lnea.
ReadLine lee la siguiente lnea de caracteres de la secuencia de
entrada estndar (el teclado, por defecto), eliminando del buffer de
entrada el terminador de lnea. Devuelve la cadena leida, que no
contiene el carcter o los caracteres de terminacin.
Read lee el siguiente carcter de la secuencia de entrada estndar y
devuelve un valor de tipo int. La lectura se realiza del buffer de
entrada y no se termina (no devuelve ningn valor) hasta que se
encuentra al caracter de terminacin (cuando el usuario presion la
tecla ENTER). Si existen datos disponibles en el buffer, la secuencia
de entrada contiene los datos introducidos por el usuario, seguidos del carcter de terminacin.
Veamos un sencillo ejemplo sobre el uso de estos mtodos.
E/S simple
using System;
class PideNombre
{
static void Main(string[] args)
{
Console.Write ("Introduzca su nombre: ");
// 1
string nombre = Console.ReadLine();
// 2
Console.WriteLine ("Su nombre es: " + nombre);
// 3
Console.ReadLine();
// 4
}
}
La instruccin 1 muestra la cadena Introduzca su nombre: pero no avanza a la
siguiente lnea de la consola, por lo que cuando se ejecuta la instruccin 2 lo que
escribe el usuario se muestra a continuacin, en la misma lnea. La cadena que escribe
el usuario se guarda en la variable nombre y se elimina del buffer de entrada el
terminador de lnea. Cuando se valida la entrada (al pulsar ENTER) se avanza a la
siguiente lnea. La instruccin 3 muestra una cadena, resultado de concatenar un
literal y la cadena introducida por el usuario. Finalmente, la instruccin 4 es necesaria
para detener la ejecucin del programa (realmente, la finalizacin del mismo) hasta
que el usuario pulse ENTER. Observar que aunque el mtodo Readline devuelva una
cadena, ste valor devuelto no es usado. En la siguiente figura mostramos dos
ejemplos de ejecucin.
Aplicaciones Windows
Una aplicacin basada en ventanas (aplicacin Windows, en lo que sigue) utilizan
ventanas y componentes especficos para interactuar con el usuario. Las peticiones de
datos se realizan con componentes de entrada de texto (por ejemplo, con un
TextBox) o mediante la seleccin en una lista de posibilidades (por ejemplo, con un
ComboBox). Las salidas pueden realizarse de mltiples maneras, empleando
componentes Label, ventanas de mensajes MessageBox, etc.
Por ejemplo, en la figura siguiente mostramos una aplicacin que responde mostrando
una ventana de mensaje (MessageBox) cuando se pincha sobre el botn titulado
Saludo. Basta con ejecutar este cdigo cada vez que se pinche en dicho botn:
MessageBox.Show ("Hola, mundo!", "Un saludo tpico");
(en realidad, System.Windows.Forms.MessageBox.Show (...);)
Una aplicacin ms compleja podra pedir el nombre del usuario en un componente
TextBox y mostrarlo empleando un componente Label cuando se pincha en el botn
titulado Saludo:
Una aplicacin de ventanas se crea fcilmente en Visual Studio .NET seleccionando
Archivo, Nuevo y Proyecto. En la ventana Nuevo proyecto se selecciona ahora
Proyectos de Visual C# y Aplicacin para Windows.
Tipos de datos
Los tipos de datos ofrecidos por C# al programador forman parte de un sistema
unificado en el que todos los tipos de datos (incluidos los definidos por el usuario)
derivan, aunque sea de manera implcita, de la clase System.Object. Por herencia
dispondrn de todos los miembros definidos en sta clase, en particular los tiles
mtodos Equals(), GetHashCode(), GetType() y ToString() que describiremnos
ms adelante. C# proporciona seguridad con los tipos de datos. C# no admiten ni
funciones ni variables globales sino que todo el cdigo y datos han de definirse dentro
de definiciones de tipos de datos, lo que reduce problemas por conflictos de nombres y
facilita la legibilidad del cdigo. C# incluye mecanismos que permiten asegurar que los
accesos a tipos de datos siempre se realicen correctamente:
No pueden usarse variables que no hayan sido iniciadas.
El tipo asignado restringe los valores que puede almacenar y las
operaciones en las que puede intervenir.
Siempre se comprueba que los ndices empleados para acceder a los
elementos de una tabla (vector o matriz) se encuentran en el rango
de valores vlidos.
Slo se admiten conversiones de tipo entre tipos compatibles y entre
aquellos que se hayan definido explcitamente el mecanismo de
conversin (En C# puede implementarse la manera en que se realiza la conversin implcita y explcita entre tipos)
Los tipos de datos en C# pueden clasificarse en dos grandes categoras:
tipos valor
tipos referencia
y pueden caracterizarse como sigue:
Tipos valor Tipos referencia
La variable contiene un valor La variable contiene una
referencia
El dato se almacena en la
pila El dato se almacena en el heap
El dato siempre tiene valor El dato puede no tener valor null
Una asignacin copia el valor Una asignacin copia la referencia
int i = 123; // tipo valor
string s = "Hello world"; // tipo referencia
El comportamiento cuando se copian o modifican objetos de estos tipos es muy
diferente.
Tipos valor
Los tipos bsicos son tipos valor. Si una variable es de un tipo valor contiene
nicamente un valor del tipo del que se ha declarado. Los tipos predefinidos de C# son
tipos disponibles en la plataforma .NET y que, por comodidad, en C# se emplean
usando un alias. En la tabla siguiente enumeramos los tipos simples detallando su
nombre completo, su alias, una breve descripcin, el nmero de bytes que ocupan y el rango de valores.
Nombre (.NET
Framework) Alias Descripcin
Tamao
(bytes) Rango
System.Sbyte sbyte Bytes con
signo 1 -128 ... 127
System.Int16 short Enteros
cortos 2 -32.768 ... 32.767
System.Int32 int Enteros 4 -2.147.483.648 ...
2.147.483.647
System.Int64 long Enteros
largos 8
-9.223.372.036.854.775.808
...
9.223.372.036.854.775.807
System.Byte byte Bytes (sin
signo) 1 0 ... 255
System.Uint16 ushort Enteros
cortos (sin
signo)
2 0 ... 65.535
System.UInt32 uint Enteros (sin
signo) 4
0 ...
18.446.744.073.709.551.615
System.Uint64 ulong Enteros
largos (sin
signo)
8 0 ...
18.446.744.073.709.551.615
System.Single float Reales (7
decimales) 4
1.5 x 10-45 ... 3.4 x
10+38
System.Double double Reales (15-
16
decimales)
8 5.0 x 10-324 ... 1.7 x
10+308
System.Decimal decimal Reales (28-
29
decimales)
12 1.0 x 10-28 ... 7.9 x
10+28
System.Char char Caracteres
Unicode 2 Cualquier carcter Unicode
System.Boolean bool Valores
lgicos 1 true false
El comportamiento de los datos de tipos valor es el esperado cuando se inician o
reciben un valor por asignacin a partir de otro dato de tipo valor (son independientes).
Tipos referencia
Si un dato es de un tipo referencia contiene la direccin de la informacin, en
definitiva, una referencia al objeto que contiene los datos y/o mtodos. En definitiva, distinguimos:
La referencia o un nombre por el que nos referimos al objeto y que
utilizamos para manipularlo.
El objeto referenciado, que ocupa lugar en memoria (en el heap) y que almacenar el valor efectivo del objeto.
En definitiva: la variable y su contenido "lgico" estn en posiciones de memoria
diferentes. El valor almacenado en una variable de tipo referencia es la direccin de
memoria del objeto referenciado (es una referencia) o tiene el valor null (no
referencia a nada). Observe que pueden existir dos variables que referencien al mismo objeto (pueden existir dos referencias a la misma zona de memoria).
C# proporciona dos tipos referencia predefinidos: object y string. Todos los dems
tipos predefinidos son tipos valor.
El tipo object es el tipo base del cual derivan todos los tipos bsicos predefinidos y
los creados por el usuario. Pueden crearse nuevos tipos referencia usando
declaraciones de clases (class), interfaces (interface) y delegados (delegate), y
nuevos tipos valor usando estructuras struct.
Los objetos de las clases creadas por el usuario son siempre de tipo referencia. El
operador new permite la creacin de instancias de clases definidas por el usuario. new
es muy diferente en C# y en C++:
En C++ indica que se pide memoria dinmica. En C# indica que se llama al constructor de una clase.
El efecto, no obstante, es similar ya que como la variable es de un tipo referencia, al
llamar al constructor se aloja memoria en el heap de manera implcita.
Considere el siguiente fragmento de cdigo, en el que todas las variables son del
mismo tipo: ObjetoDemo).
Tipos referencia
class ObjetoDemo
{
public int Valor;
}
class AppDemoRef
{
static void Main(string[] args)
{
ObjetoDemo o1 = new ObjetoDemo(); // new llama a
un constructor
o1.Valor = 10;
ObjetoDemo o2 = new ObjetoDemo(); // new llama a
un constructor
o2 = o1; // La memoria que ocupaba el objeto
refernciado por "o2"
// se pierde: actuar el recolector de
basura.
PintaDatos ("o1", "o2", o1, o2);
ObjetoDemo o3 = new ObjetoDemo();// new llama a
un constructor
o3.Valor = 10;
ObjetoDemo o4 = o3; // "o4" contiene la misma
direccion de memoria que "o3"
o4.Valor = 20; // Igual que hacer o3.Valor
= 20;
PintaDatos ("o3", "o4", o3, o4);
ObjetoDemo o5 = new ObjetoDemo(); // new llama a
un constructor
o5.Valor = 10;
ObjetoDemo o6 = new ObjetoDemo(); // new llama a
un constructor
o6.Valor = o5.Valor;
PintaDatos ("o5", "o6", o5, o6);
Console.ReadLine();
}
static void PintaDatos (string st1, string st2,
ObjetoDemo ob1, ObjetoDemo ob2)
{
Console.Write ("{0} = {1}, {2} = {3} ", st1,
ob1.Valor, st2, ob2.Valor);
if (ob1==ob2)
Console.WriteLine ("{0} == {1}", st1, st2);
else
Console.WriteLine ("{0} != {1}", st1, st2);
}
}
El tipo string es un tipo especial de tipo referencia. De hecho, parece ms un tipo
valor ante la asignacin. Observe el ejemplo:
string s1 = "Hola";
string s2 = s1;
En este punto s2 referencia al mismo objeto que s1. Sin embargo, cuando el valor de
s1 es modificado, por ejemplo con:
s1 = "Adios";
lo que ocurre es que se crea un nuevo objeto string referenciado por s1. De esta
forma, s1 contiene "Adios" mientras que s2 mantiene el valor "Hola". Esto es as
porque los objetos string son immutables, por lo que, para cambiar lo que
referencia una variable string debe crearse un nuevo objeto string.
Variables y constantes
Variables
Una variable permite el almacenamiento de datos en la memoria. Es una abstraccin
que permite referirnos a una zona de memoria mediante un nombre (su identificador).
Todas las variables tienen asociadas un tipo que determina los valores que pueden
almacenarse y las operaciones que pueden efectuarse con los datos de ese tipo.
Adems, el trmino variable indica que el contenido de esa zona de memoria puede modificarse durante la ejecucin del programa.
Nombres de variables
Los nombres que pueden asignarse a las variables deben regirse por unas normas bsicas:
Pueden contener letras, dgitos y el caracter de subrayado (_).
No pueden empezar con un nmero: deben comenzar por una letra
letra o con el carcter de subrayado (_).
Finalmente, recordar que, como identificador que es, el nombre de una variable es
sensible a las maysculas y no pueden coincidir con una palabra reservada a no ser
que tenga el prefijo @, aunque no es una prctica recomendada.
Declaracin de variables
Antes de usar una variable se debe declarar. La declaracin de una variable indica
al compilador el nombre de la variable y su tipo. Una declaracin permite que se pueda
reservar memoria para esa variable y restringir el espacio (cantidad de memoria) que
requiere, los valores que pueden asignarsele y las operaciones en las que puede intervenir.
La sintaxis de una declaracin es sencilla: tan slo hay que especificar el tipo de la
variable y el nombre que se le asocia. La declaracin debe concluir con el carcter
punto y coma. Por ejemplo, si vamos a emplear una variable para guardar en ella el valor del rea de un crculo debemos:
Darle un nombre significativo: Area
Asociarle un tipo: dado que puede tener decimales y no se requiere
una gran precisin, bastar con el tipo float.
float Area;
Cuando se van a declarar mltiples variables del mismo tipo no es necesario que cada
declaracin se haga por separado, pueden agruparse en la misma lnea compartiendo
el tipo. Por ejemplo, las declaraciones:
float Radio;
float Area;
pueden simplificarse en una lnea:
float Radio, Area;
De la misma manera pueden declararse e inicializarse variables en una sola lnea:
int a=1, b=2, c, d=4;
No existe ninguna zona predeterminada en el cdigo para la declaracin de variables,
la nica restriccin es que la declaracin debe realizarse antes de su uso.
No es conveniente abusar de la declaracin mltiple de variables en una lnea. Desde
el punto de vista de la legibilidad es preferible, por regla general, que cada variable se
declare separadamente y que la declaracin vaya acompaada de un breve comentario:
float Radio; // Radio del circulo del cual se calcula
el area.
float Area; // Area del circulo
Acceso a variables
Una variable se usa para asignarle un valor (acceso de escritura) o para utilizar el valor almacenado (acceso de lectura).
Una vez declarada una variable debe recibir algn valor (es su misin, despus de
todo). Este valor lo puede recibir de algn dispositivo (flujo de entrada) o como
resultado de evaluar una expresin. La manera ms simple de proporcionar un valor a una variable es emplear la instruccin de asignacin:
Radio = 10.0F;
En el ejemplo se asigna el valor (literal entero) 10 a la variable Radio. El valor que
tuviera almacenado la variable Radio se pierde, quedando fijado a 10.
En la misma lnea de la declaracin puede asignarse un valor a la variable, por lo que declaracin e inicializacin:
float Radio; // Declaracion
Radio = 10.0F; // Inicializacion
pueden simplificarse en una sola lnea:
float Radio = 10.0F; // Declaracion e Inicializacion
La manera ms simple de leer el valor de una variable es emplearla como parte de una expresin, por ejemplo, en la parte derecha de una instruccin de asignacin:
Area = 2 * 3.1416F * Radio * Radio;
La variable Radio (su valor) se emplea en la expresin 2 * 3.1416 * Radio *
Radio para calcular el rea de un crculo de radio Radio. Una vez calculado el valor
de la expresin, ste se asigna a la variable Area.
Otra manera de acceder al valor de una variable para lectura es emplearla como el
argumento de una instruccin de escritura WriteLine. Por ejemplo,
Console.WriteLine(Area);
mostrar en la consola el valor de la variable Area.
Leer el valor de una variable no modifica el contenido de la variable.
A modo de resumen, un programa que calcula y muestra el rea de un crulo de radio
10 es el siguiente:
Calculo del rea de un crculo (1)
using System;
class Area1
{
static void Main(string[] args)
{
float Radio = 10.0F;
float Area = 2 * 3.1416F * Radio * Radio;
Console.WriteLine(Area);
Console.ReadLine();
}
}
Como puede parecer evidente, emplear una variable que no ha sido declarada produce
un error en tiempo de compilacin. En C#, adems, hay que asignarle un valor antes
de utilizarla. Si no se hace se genera un error en tiempo de compilacin ya que esta
comprobacin (igual que ocurre en Java) se efecta por el compilador.
void f()
{
int i;
Console.WriteLine(i); // Error: uso de la variable
local no asignada 'i'
}
Constantes
Una constante se define de manera parecida a una variable: modeliza una zona de
memoria que puede almacenar un valor de un tipo determinado. La diferencia reside
en que esa zona de memoria (su contenido) no puede modificarse en la ejecucin del
programa. El valor de la constante se asigna en la declaracin.
Sintcticamente se especifica que un dato es constante al preceder con la palabra
reservada const su declaracin. Por ejemplo, para declarar un a constante de tipo
float llamada PI y asignarle el valor (constante) 3.1416 se escribir:
const float PI = 3.1416F;
Solo se puede consultar el valor de una constante, nunca se debe intentar modificarlo
porque se producira un error en tiempo de compilacin. Por ejemplo, la siguiente instruccin:
Area = 2 * PI * Radio * Radio;
utiliza la constante PI declarada anteriormente, usando su valor para evaluar una
expresin.
Podemos modificar el programa anterior para que utilice la constante PI:
Calculo del rea de un crculo (2)
using System;
class Area2
{
static void Main(string[] args)
{
const float PI = 3.1416F;
float Radio = 10.0F;
float Area = 2 * PI * Radio * Radio;
Console.WriteLine(Area);
Console.ReadLine();
}
}
mbito de variables y constantes
El mbito (del ingls scope) de una variable y/o constante indica en qu partes del
cdigo es lcito su uso.
En C# el mbito abarca desde el lugar de su declaracin hasta donde termina el bloque en el que fue declarada.
En el mbito de una variable no puede declararse otra variable con el mismo nombre
(aunque sea en un bloque interno, algo que si est permitido en C++):
static void Main(string[] args)
{
float Radio = 10.0F;
...
if (Radio > 0){
float Radio = 20.0F; // Error: No se puede
declarar una variable
// local denominada
'Radio' en este mbito.
}
...
}
Operadores y expresiones
Un operador est formado por uno o ms caracteres y permite realizar una
determinada operacin entre uno o ms datos y produce un resultado. Es una manera simblica de expresar una operacin sobre unos operandos.
C# proporciona un conjunto fijo, suficiente y completo de operadores. El significado de
cada operador est perfectamente definido para los tipos predefinidos, aunque algunos
de ellos pueden sobrecargarse, es decir, cambiar su significado al aplicarlos a un tipo definido por el usuario.
C# dispone de operadores aritmticos, lgicos, relacionales, de manipulacin de bits,
asignacin, para acceso a tablas y objetos, etc. Los operadores pueden presentarse por diferentes criterios, por ejemplo, por su funcionalidad:
Categoras Operadores
Aritmticos + - * /
%
Lgicos (booleanos y bit a bit) & | ^ ! ~ &&
||
Concatenacin de cadenas +
Incremento y decremento ++ --
Desplazamiento >
Relacionales == != < > =
Asignacin
= += -= *= /=
%= &=
|= ^= =
Acceso a miembros .
Acceso por ndices []
Conversin de tipos explcita ()
Conditional ? :
Creacin de objetos new
Informacin de tipos as is sizeof
typeof
Control de excepciones de
desbordamiento checked unchecked
Direccionamiento indirecto y
direccin * -> [] &
Los operadores aritmticos de C# son los que se emplean
comnmente en otros lenguajes: + (suma), - (resta), *
(multiplicacin), / (divisin) y % (mdulo o resto de la divisin).
Son operadores binarios y se colocan entre los argumentos sobre
los que se aplican, proporcionando un resultado numrico (Por
ejemplo, 7+3.5, 66 % 4).
Los operadores lgicos proporcionan un resultado de tipo lgico
(bool) y los operadores a nivel de bit actan sobre la
representacin interna de sus operandos (de tipos enteros) y proporcionan resultados de tipo numrico.
Los operadores binarios son: & (operacin Y lgica entre
argumentos lgicos u operacin Y bit a bit entre operandos
numricos), | (operacin O, lgica bit a bit, dependiendo del tipo
de los argumentos) , ^ (O exclusivo, lgico bit a bit), && (Y lgico,
que evala el segundo operando solo cuando es necesario) y || (O
lgico, que evala el segundo operando solo cuando es necesario).
Los operadores unarios son: ! (negacin o complemento de un
argumento lgico) y ~ (complemento bit a bit de un argumento
numrico).
El operador + para la concatenacin de cadenas es un operador
binario. Cuando al menos uno de los operandos es de tipo string
este operador acta uniendo las representaciones de tipo string
de los operandos.
Operadores de incremento y decremento. El operador de
incremento (++) incrementa su operando en 1 mientras que el de
decremento (--) decrementa su operando en 1. Puede aparecer
antes de su operando: ++v (incremento prefijo) o despus: v++
(incremento postfijo).
El incremento prefijo hace que el resultado sea el valor del
operando despus de haber sido incrementado y el postfijo hace
que el resultado sea valor del operando antes de haber sido
incrementado.
Los tipos numricos y de enumeracin poseen operadores de
incremento y decremento predefinidos.
Los operadores de desplazamiento son operadores binarios.
Producen un desplazamiento a nivel de bits de la representacin
interna del primer operando (de un tipo entero), a la izquierda () el nmero de bits especificado por su segundo
operando.
Los operadores relacionales proporcionan un resultado lgico,
dependiendo de si sus argumentos son iguales (==), diferentes
(!=), o del orden relativo entre ellos (, =).
La asignacin simple (=) almacena el valor del operando situado a su
derecha en una variable (posicin de memoria) indicada por el
operando situado a su izquierda.
Los operandos deben ser del mismo tipo o el operando de la
derecha se debe poder convertir implcitamente al tipo del operando de la izquierda).
El operador de asignacin = produce los siguientes resultados:
o En tipos simples el funcionamiento es similar al de C++, copia
el contenido de la expresin de la derecha en el objeto que
recibe el valor.
o En datos struct realiza una copia directa del contenido, como
en C++.
o En clases se copia la referencia, esto es, la direccin del
objeto, provocando que el objeto sea referenciado por ms de una referencia.
Este comportamiento es distinto al que se produce en C++, en
el que se copia el contenido del objeto. Si el objeto contiene
estructuras ms complejas, C++ requiere normalmente la
sobrecarga del operador para personalizar la manera en que se
realiza la copia para que cada instancia de la clase (fuente y
destino) maneje su propia zona de memoria. En C# no se
permite la sobrecarga del operador =
Los otros operadores de esta categora realizan, adems de la asignacin otra operacin previa a la asignacin. Por ejemplo,
a += 22;
equivale a
a = a + 22;
o sea, primero se calcula la expresin a+22 y posteriormente, ese
valor se almacena en a.
De la misma manera actan los dems operadores de asignacin: -
=, *=, /=, %=, &=, |=, ^=, >=.
Para asignar instancias de clases (en el sentido clsico de C++) se
debe redefinir el mtodo MemberwiseCopy() que es heredado por
todas las clases desde System.Object (todas las clases heredan, en ltima instancia de System.Object).
El operador de acceso a miembros es el operador punto (.) y se
emplea para acceder a los miembros (componentes) de una clase,
estructura o espacio de nombres.
El operador de acceso por ndices es el tradicional, formado por la
pareja de caracteres [ y ]. En C# tambin se emplea para
especificar atributos.
El operador de conversin explcita de tipos (casting) es el clsico,
formado por la pareja de caracteres ( y ).
El operador ternario condicional evala una condicin lgica y devuelve uno de dos valores.
Se utiliza en expresiones de la forma:
cond ? expr1 : expr2
de manera que si cond es verdad, se evala expr1 y se devuelve
como resultado; si cond es falsa se evala expr1 y se devuelve
como resultado.
Creacin de objetos (new). El operador new permite crear instancias
de una clase definida por el usuario. Por ejemplo:
ObjetoDemo o1 = new ObjetoDemo() declara una referencia
(llamada o1) a un objeto de la clase ObjetoDemo y crea una
instancia de esa clase, referenciada por o1. En realidad, la creacin
de un objeto implica la llamada a un constructor de la clase.
Control de excepciones de desbordamiento: checked y unchecked
C# proporciona la posibilidad de realizar operaciones de moldeado
(casting) y aritmticas en un contexto verificado. En otras palabras,
el entorno de ejecucin .NET detecta cualquier situacin de
desbordamiento y lanza una excepcin (OverFlowException) si
sta se manifiesta.
En un contexto verificado (checked), si una expresin produce un
valor fuera del rango del tipo de destino, el resultado depende de si
la expresin es constante o no. Las expresiones constantes
producen errores de compilacin, mientras que las expresiones no
constantes se evalan en tiempo de ejecucin y producen excepciones.
Si no se especifican ni checked ni unchecked, las expresiones
constantes utilizan la verificacin de desbordamiento
predeterminada en tiempo de compilacin, que es checked. De lo
contrario, si la expresin no es constante, la verificacin de
desbordamiento en tiempo de ejecucin depende de otros factores
tales como las opciones del compilador y la configuracin del
entorno. En el siguiente ejemplo, el valor por defecto es
unchecked:
using System;
class PruebaDesbordamiento
{
static short x = 32767; // Maximo valor short
static short y = 32767;
public static int UnCh()
{
int z = unchecked((short)(x + y));
return z; // -2
}
public static int UnCh2()
{
int z = (short)(x + y); // Por defecto es
unchecked
return z; // -2
}
public static void Main()
{
Console.WriteLine("Valor -unchecked-: {0}",
UnCh());
Console.WriteLine("Valor por defecto: {0}",
UnCh2());
Console.ReadLine();
}
}
El resultado es:
Valor -unchecked-: -2
Valor por defecto: -2
Si aadimos la funcin:
public static int Ch()
{
int z = checked((short)(x + y));
return z;
}
y la llamada:
Console.WriteLine("Valor -checked- : {0}", Ch());
la ejecucin del programa provoca el lanzamiento de una excepcin
System.OverflowException que detiene la ejecucin del
programa, al no estar controlada.
Operadores especiales: as is typeof
El operador as
El operador as se utiliza para realizar conversiones entre tipos compatibles (al estilo de
los casts dinmicos de C++). El operador as se utiliza en expresiones de la forma:
as type
donde es una expresin de un tipo de referencia, y type es un tipo
de referencia. Si la conversin de tipo no es posible, el resultado es null.
// Ejempo de uso del operador as
using System;
class Clase1 {}
class Clase2 {}
public class Demo
{
public static void Main()
{
object [] Objetos = new object[6];
Objetos[0] = new Clase1();
Objetos[1] = new Clase1();
Objetos[2] = "Hola";
Objetos[3] = 123;
Objetos[4] = 123.4;
Objetos[5] = null;
for (int i=0; i
Console.Write ("{0}:", i);
if (s != null)
Console.WriteLine ( "'" + s + "'" );
else
Console.WriteLine ( "no es string" );
}
Console.ReadLine();
}
}
El resultado es:
0:no es string
1:no es string
2:'Hola'
3:no es string
4:no es string
5:no es string
En el siguiente ejemplo, la funcin DoSomething recibe cualquier argumento, pero
slo cuando es de tipo Car se ejecuta el mtodo Drive sobre el objeto c (de clase
Car).
static void DoSomething(object o)
{
Car c = o as Car;
if (c != null) c.Drive();
}
El operador is
El operador is se utiliza para comprobar en tiempo de ejecucin si el tipo de un objeto
es compatible con un tipo dado. El operador is se utiliza en expresiones de la forma:
is type
donde es una expresin de un tipo de referencia, y type es un tipo
de referencia.
El siguiente ejemplo realiza la misma tarea que comentamos en el ejemplo sobre el
operador as solo que ahora no hay ningn objeto local con referencia explcita sobre el
que se ejecute el mtodo Drive.
static void DoSomething(object o)
{
if (o is Car) ((Car)o).Drive();
}
El operador typeof
El operador typeof devuelve el objeto derivado de System.Type correspondiente al
tipo especificado.
Una expresin typeof se presenta de la siguiente forma:
typeof (tipo)
donde tipo es el tipo cuyo objeto System.Type se desea obtener.
De esta forma se puede hacer reflexin para obtener dinmicamente informacin sobre los tipos (como en Java).
...
Console.WriteLine(typeof(int).FullName);
Console.WriteLine(typeof(System.Int).Name);
Console.WriteLine(typeof(float).Module);
Console.WriteLine(typeof(double).IsPublic);
Console.WriteLine(typeof(Point).MemberType);
...
Un ejemplo en el que se emplean los operadores is, as y typeof para discriminar el
tipo del argumento recibido en una funcin polimrfica y trabajar con l es el siguiente:
// Ejempo de uso de los operadores is, as y typeof
using System;
class Clase1 {}
class Clase2 {}
public class Demo
{
public static void Prueba (object o)
{
Clase1 a;
Clase2 b;
Type t;
if (o is Clase1)
{
Console.WriteLine ("\no es de Clase1");
a = (Clase1)o;
Console.WriteLine ("--> {0}",
typeof(Clase1).FullName);
t = typeof(Clase1);
}
else if (o is Clase2)
{
Console.WriteLine ("\no es de Clase2");
b = o as Clase2;
t = typeof(Clase2);
}
else
{
Console.WriteLine ("\no no es ni de Clase1 ni
de Clase2.");
t = o.GetType();
}
Console.WriteLine ("Su tipo es " + t.FullName);
}
public static void Main()
{
Clase1 c1 = new Clase1();
Clase2 c2 = new Clase2();
Prueba (c1);
Prueba (c2);
Prueba ("Un string");
Console.ReadLine();
}
}
El resultado es:
o es de Clase1
--> Clase1
Su tipo es Clase1
o es de Clase2
Su tipo es Clase2
o no es ni de Clase1 ni de Clase2.
Su tipo es System.String
Precedencia
Tambin podran presentarse por precedencia. En la tabla siguiente los enumeramos de mayor a menor precedencia:
Categoras Operadores
Primarios
Parntesis: (x)
Acceso a miembros: x.y
Llamada a mtodos: f(x)
Acceso con ndices: a[x]
Post-incremento: x++
Post-decremento: x--
Llamada a un constructor: new
Consulta de tipo: typeof
Control de desbordamiento activo: checked
Control de desbordamiento inactivo: unchecked
Unarios
Valor positivo: +
Valor negative: -
No: !
Complemento a nivel de bit: ~
Pre-incremento: ++x
Post-decremento: --x
Conversin de tipo -cast-: (T)x
Multiplicativos
Multiplicacin: *
Divisin: /
Resto: %
Aditivos
Suma: +
Resta: -
Desplazamiento
Desplazamiento de bits a la izquierda: >
Relacionales
Menor: <
Mayor: >
Menor o igual: =
Igualdad o compatibilidad de tipo: is
Conversin de tipo: as
Igualdad ==
Desigualdad !=
Bitwise AND &
Bitwise XOR ^
Bitwise OR |
Logical AND &&
Logical OR ||
Condicional
ternario ?:
Asignacin =, *=, /=, %=, +=, -=, =, &=, ^=,
|=
Asociatividad
Como siempre, es mejor utilizar parntesis para controlar el orden de evaluacin
x = y = z se evala como x = (y = z)
x + y + z se evala como (x + y) + z
Estructuras de control
Las estructuras de control de C# son similares a las de C y C++. La diferencia ms
notable radica en que la instruccin condicional if y los ciclos while y do estn
controlados por una expresin lgica (tipo Boolean).
Esta restriccin hace que las instrucciones sean ms seguras al evitar posibles fuentes
de error, o al menos, facilitan la legibilidad del cdigo. Por ejemplo, en la siguiente instruccin (vlida en C++):
if (a)
la expresin a podra ser una expresin boolean pero tambin de tipo int, char,
float *... y la condicin se evala como true cuando a es distinto de cero (valor
entero 0, carcter 0 puntero nulo, en los ejemplos). En C# se clarifica esta
ambigedad y slo se admiten expresiones lgicas. De esta manera, la instruccin
anterior ser vlida slo cuando a sea una expresin boolean.
A modo de resumen, las caractersticas propias de las estructuras de control de C# son:
goto no puede saltar dentro de un bloque (da igual, de todas formas
no lo usaremos NUNCA).
switch funciona como en Pascal (no como en C).
Se aade una nueva estructura de control iterativa: foreach.
Estructuras condicionales
if, if-else
La estructura condicional tiene la sintaxis clsica, con la diferencia indicada
anteriormente acerca del tipo de la expresin. Si debe ejecutar ms de una instruccin,
se encierran en un bloque, delimitado por las llaves { y }.
Si slo se acta cuando la condicin es cierta:
if (a > 0) if (a > 0)
{
Console.WriteLine ("Positivo");
Console.WriteLine ("Positivo");
ContPositivos++;
}
Si se acta cuando la condicin es falsa se emplea la palabra reservada else:
if (a > 0) if (a > 0)
{
Console.WriteLine ("Positivo");
Console.WriteLine ("Positivo");
else
ContPositivos++;
Console.WriteLine ("No Positivo"); }
else {
Console.WriteLine ("No Positivo");
ContNoPositivos++;
}
Puede escribirse una instruccin condicional dentro de otra instruccin condicional,
lgicamente:
if (a > 0) {
Console.WriteLine ("Positivo");
ContPositivos++;
}
else {
if (a < 0) {
Console.WriteLine ("Negativo");
ContNegativos++;
}
else {
Console.WriteLine ("Cero");
ContCeros++;
}
}
La concordancia entre if y else se establece de manera sencilla: cada else se asocia
al ltimo if que no tenga asociado un bloque else.
switch
La estructura de seleccin mltiple switch funciona sobre cualquier tipo predefinido
(incluyendo string) o enumerado (enum) y debe indicar explcitamente cmo
terminar cada caso (generalmente, con break en situaciones "normales" throw
en situaciones "anormales", aunque es posible -pero no recomendable- emplear goto
case return ):
using System;
class HolaMundoSwitch
{
public static void Main(String[] args)
{
if (args.Length > 0)
switch(args[0])
{
case "Jos":
Console.WriteLine("Hola Jos. Buenos
das");
break;
case "Paco":
Console.WriteLine("Hola Paco. Me alegro de
verte");
break;
default: Console.WriteLine("Hola {0}",
args[0]);
break;
}
else
Console.WriteLine("Hola Mundo");
}
}
Especificar los parmetros al programa en Visual Studio: Utilizar el explorador de
soluciones para configurar las propiedades del proyecto.
Un ejemplo que usa un datos string para controlar la seleccin:
using System;
namespace ConsoleApplication14
{
class Class1
{
static int Test(string label)
{
int res;
switch(label)
{
case null:
goto case "A"; // idem case "B" o case
"A"
case "B":
case "C":
res = 1;
break;
case "A":
res = 2;
break;
default:
res = 0;
break;
}
return res;
}
static void Main(string[] args)
{
Console.WriteLine (Test("")); // 0
Console.WriteLine (Test("A")); // 2
Console.WriteLine (Test("B")); // 1
Console.WriteLine (Test("C")); // 1
Console.WriteLine (Test("?")); // 0
Console.ReadLine();
}
}
}
Estructuras repetitivas
Las estructuras repetitivas de C# (while, do...while, for) no presentan grandes
diferencias respecto a las de otros lenguajes, como C++. La aportacin fundamental es
la de la estructura iterativa en colecciones foreach.
while
int i = 0;
while (i < 5) {
...
i++;
}
do...while
int i = 0;
do {
...
i++;
} while (i < 5);
for
int i;
for (i=0; i < 5; i++) {
...
}
foreach
Un ciclo foreach itera seleccionando todos los miembros de un vector, matriz u otra
coleccin sin que se requiera explicitar los ndices que permiten acceder a los
miembros. El siguiente ejemplo muestra todos los argumentos recibidos por el programa cuando se invoca su ejecucin (argumentos en la lnea de rdenes):
public static void Main(string[] args)
{
foreach (string s in args)
Console.WriteLine(s);
}
El vector (la coleccin) que se utiliza para iterar es args. Es un vector de datos
string. El ciclo foreach realiza tantas iteraciones como cadenas contenga el vector
args, y en cada iteracin toma una y la procesa a travs de la variable de control s.
El ejemplo siguiente realiza la misma funcin:
public static void Main(string[] args)
{
for (int i=0; i < args.Lenght; i++)
Console.WriteLine(args[i]);
}
El ciclo foreach proporciona acceso de slo lectura a los elementos de la coleccin
sobre la que se itera. Por ejemplo, el cdigo de la izquierda no compilar, aunque el de
la derecha s lo har (v es un vector de int):
foreach (int i in v) for (int i=0; i <
v.Length; i++)
i *= 2; v[i] *= 2;
El ciclo foreach puede emplearse en vectores y colecciones. Una coleccin es una
clase que implementa el interfaz IEnumerable. Sobre las colecciones dicutiremos ms
adelante.
Saltos
goto
Aunque el lenguaje lo permita, nunca escribiremos algo como lo que aparece a continuacin:
using System;
namespace DemoGoto
{
class MainClass
{
static void Busca(int val, int[,] vector, out
int fil, out int col)
{
int i, j;
for (i = 0; i < vector.GetLength(0); i++)
for (j = 0; j < vector.GetLength(1); j++)
if (vector[i, j] == val) goto OK;
throw new InvalidOperationException("Valor no
encontrado");
OK:
fil = i; col = j;
}
static void Main(string[] args)
{
int [,] coleccion = new int [2,3]
{{1,0,4},{3,2,5}};
int f,c;
int valor = Convert.ToInt32(args[0]);
Busca (valor, coleccion, out f, out c);
Console.WriteLine ("El valor {0} esta en
[{1},{2}]", valor,f,c);
Console.ReadLine();
}
}
}
break
Lo usaremos nicamente en sentencias switch.
continue
Mejor no lo usamos.
return
Procuraremos emplearlo slo al final de un mtodo para facilitar la legibilidad del cdigo.
Tipos de datos
Tipos bsicos
El sistema unificado de tipos. El tipo Object
Cadenas de caracteres
Vectores y matrices
Estructuras
Enumeraciones
Cuando definimos un objeto debemos especificar su tipo. El tipo determina qu valores
puede almacenar ese objeto (clase y rango) y las operaciones que pueden efectuarse con l.
Como cualquier lenguaje de programacin, C# proporciona una serie de tipos
predefinidos (int, byte, char, string, ...) y mecanismos para que el usuario cree
sus propios tipos (class y struct).
La estructura de tipos de C# es una gran novedad ya que establece una relacin
jerrquica entre stos, de manera que todos los tipos son clases y se construyen por
herencia de la clase base Objet. Esta particularidad hace que la creacin y gestin de
tipos de datos en C# sea una de las principales novedades y potencialidades del lenguaje.
Tipos bsicos
Los tipos de datos bsicos son los tipos de datos ms comnmente utilizados en
programacin.
Los tipos predefinidos en C# estn definidos en el espacio de nombres System, que es
el espacio de nombres ms numeroso (e importante) de la plataforma .NET. Por
ejemplo, para representar nmeros enteros de 32 bits con signo se utiliza el tipo de
dato System.Int32 y a la hora de crear un objeto a de este tipo que represente el
valor 2 se usa la siguiente sintaxis:
System.Int32 a = 2;
Al ser un tipo valor no se utiliza el operador new para crear objetos System.Int32,
sino que directamente se indica el literal que representa el valor a crear, con lo que la
sintaxis necesaria para crear entero de este tipo se reduce considerablemente. Es ms,
dado lo frecuente que es el uso de este tipo tambin se ha predefinido en C# el alias
int para el mismo, por lo que la definicin de variable anterior queda as de
compacta:
int a = 2;
System.Int32 no es el nico tipo de dato bsico incluido en C#. En el espacio de
nombres System se han incluido los siguientes tipos:
C# Tipo en System Caractersticas Smbolo
sbyte System.Sbyte entero, 1 byte con signo
byte System.Byte entero, 1 byte sin signo
short System.Short entero, 2 bytes con signo
ushort System.UShort entero, 2 bytes sin signo
int System.Int32 entero, 4 bytes con signo
uint System.UInt32 entero, 4 bytes sin signo U
long System.Int64 entero, 8 bytes con signo L
ulong System.ULong64 entero, 8 bytes sin signo UL
float System.Single real, IEEE 754, 32 bits F
double System.Double real, IEEE 754, 64 bits D
decimal System.Decimal real, 128 bits (28 dgitos
significativos) M
bool System.Boolean (Verdad/Falso) 1 byte
char System.Char Carcter Unicode, 2 bytes
string System.String Cadenas de caracteres
Unicode " "
object System.Object Cualquier objeto (ningn
tipo concreto)
Los tipos estn definidos de manera muy precisa y no son dependientes del compilador o de la plataforma en la que se usan.
La tabla anterior incorpora la columna Smbolo para indicar cmo debe interpretarse
un literal. Por ejemplo, 28UL debe interpretarse como un entero largo sin signo
(ulong).
Todos los tipos enumerados son tipos valor, excepto string (que no debe confundirse
con un vector de caracteres) y Object que son tipos referencia. Recuerde, no
obstante, que los datos string se comportaban como un tipo valor ante la asgnacin.
El sistema unificado de tipos. El tipo Object
En C# desaparecen las variables y funciones globales: todo el cdigo y todos los
datos de una aplicacin forman parte de objetos que encapsulan datos y
cdigo (como ejemplo, recuerde cmo Main() es un mtodo de una clase). Como en
otros lenguajes orientados a objetos, en C# un tipo puede incluir datos y mtodos.
De hecho, hasta los tipos bsicos predefinidos incluyen mtodos, que, como veremos,
heredan de la clase base object, a partir de la cual se construyen implcita o
explcitamente todos los tipos de datos. Por ejemplo:
int i = 10;
string c = i.ToString();
e incluso: string c = 10.ToString();
Esta manera por la que podemos manipular los datos bsicos refleja la ntima relacin
entre C# y la biblioteca de clase de .NET. De hecho, C# compila sus tipos bsicos
asocindolos a sus correspondientes en .NET; por ejemplo, hace corresponder al tipo
string) con la clase System.String, al tipo int) con la clase System.Int32, etc.
As, se confirma que todo es un objeto en C# (por si an haba alguna duda).
Aunque no comentaremos todos los mtodos disponibles para los tipos bsicos, destacaremos algunos de ellos.
Todos los tipos tienen un mtodo ToString() que devuelve una
cadena (string) que representa su valor textual.
char tiene propiedades acerca de su contenido (IsLetter,
IsNumber, etc.) adems de mtodos para realizar conversiones
(ToUpper(), ToLower(), etc.)
El tipo bsico string dispone, como puede suponerse, de muchos
mtodos especficos, an ms que la clase string de la biblioteca
estndar de C++.
Algunos mtodos estticos y propiedades particularmente interesantes son:
Los tipos numricos enteros tipos tienen las propiedades MinValue y
MaxValue (p.e. int.MaxValue).
Los tipos float y double tienen la propiedad Epsilon, que indica el
mnimo valor positivo que puede representarse en un dato de su
tipo (p.e. float.Epsilon).
Los tipos float y double tienen definidos los valores NaN (no es un
nmero, no est definido), PositiveInfinite y
NegativeInfinity, valores que son pueden ser devueltos al
realizar ciertos clculos.
Muchos tipos, incluyendo todos los tipos numricos, proporcionan el
mtodo Parse() que permite la conversin desde un dato string
(p.e. double d = double.Parse("20.5"))
Conversiones de tipos
Una conversin de tipo (casting) puede ser implcita o explcita.
Implcitas Explcitas
Ocurren automticamente Requieren un casting
Siempre tienen xito Pueden fallar
No se pierde informacin Se puede perder informacin
int x = 123456;
long y = x; // implicita
short z = (short) x; // explicita (riesgo)
float f1 = 40.0F;
long l1 = (long) f1; // explicita (riesgo por
redondeo)
short s1 = (short) l1; // explicita (riesgo por
desbordamiento)
int i1 = s1; // implicita, no hay riesgo
uint i2 = (uint) i1; // explicita (riesgo de error
por signo)
En C# las conversiones de tipo (tanto implcitas como explcitas) en las que
intervengan tipos definidos por el usuario pueden definirse y particularizarse.
Recordemos que pueden emplearse los operadores checked y unchecked para
realizar conversiones (y operaciones aritmticas) en un contexto verificado: el entorno
de ejecucin .NET detecta cualquier situacin de desbordamiento y lanza una
excepcin OverFlowException si sta se manifiesta.
El tipo object
Por el sistema unificado de tipos de C#, todo es un objeto. C# tiene predefinido un
tipo referencia llamado object y cualquier tipo (valor o referencia, predefinido o
definido por el usuario) es en ltima instancia, de tipo object (con otras palabras
puede decirse que hereda todas las caractersticas de ese tipo).
El tipo object se basa en System.Object de .NET Framework. Las variables de tipo
object pueden recibir valores de cualquier tipo. Todos los tipos de datos, predefinidos
y definidos por el usuario, heredan de la clase System.Object. La clase Object es la
superclase fundamental de todas las clases de .NET Framework; la raz de la jerarqua de tipos.
Normalmente, los lenguajes no precisan una clase para declarar la herencia de Object
porque est implcita.
Por ejemplo, dada la siguiente declaracin:
object o;
todas estas instrucciones son vlidas: o = 10; // int
o = "Una cadena para el objeto"; // cadena
o = 3.1415926; // double
o = new int [24]; // vector de int
o = false; // boolean
Dado que todas las clases de .NET Framework se derivan de Object, todos los
mtodos definidos en la clase Object estn disponibles en todos los objetos del
sistema. Las clases derivadas pueden reemplazar, y de hecho reemplazan, algunos de estos mtodos, entre los que se incluyen los siguientes:
public void Object() Inicializa una nueva instancia de la clase
Object. Los constructores llaman a este constructor en clases
derivadas, pero ste tambin puede utilizarse para crear una
instancia de la clase Object directamente.
public bool Equals(object obj) Determina si el objeto
especificado es igual al objeto actual.
protected void Finalize() Realiza operaciones de limpieza
antes de que un objeto sea reclamado automticamente por el
recolector de elementos no utilizados.
public int GetHashCode() Sirve como funcin hash para un tipo
concreto, apropiado para su utilizacin en algoritmos de hash y
estructuras de datos como las tablas hash.
public string ToString() Devuelve un objeto string que
representa al objeto actual. Se emplea para crear una cadena de
texto legible para el usuario que describe una instancia de la clase.
La implementacin predeterminada devuelve el nombre completo
del tipo del objeto Object. En el ltimo ejemplo, si cada vez que
asignamos un valor a o ejecutamos Console.WriteLine
(o.ToString()) o simplemente Console.WriteLine (o);
obtendremos este resultado:
10
Una cadena para el objeto
3,1415926
System.Int32[]
False
public Type GetType() Obtiene el objeto Type que representa el
tipo exacto en tiempo de ejecucin de la instancia actual.
En el ltimo ejemplo, si cada vez que asignamos un valor a o
ejecutamos Console.WriteLine (o.getType()) obtendremos
este resultado:
System.Int32
System.String
System.Double
System.Int32[]
System.Boolean
protected object MemberwiseClone() Crea una copia
superficial del objeto Object actual. No se puede reemplazar este
mtodo; una clase derivada debe implementar la interfaz
ICloneable si una copia superficial no es apropiada.
MemberwiseClone() est protegido y, por tanto, slo es accesible
a travs de esta clase o de una clase derivada. Una copia superficial
crea una nueva instancia del mismo tipo que el objeto original y,
despus, copia los campos no estticos del objeto original. Si el
campo es un tipo de valor, se realiza una copia bit a bit del campo.
Si el campo es un tipo de referencia, la referencia se copia, pero no
se copia el objeto al que se hace referencia; por lo tanto, la
referencia del objeto original y la referencia del punto del duplicado
apuntan al mismo objeto. Por el contrario, una copia profunda de
un objeto duplica todo aquello a lo que hacen referencia los campos del objeto directa o indirectamente.
Polimorfismo -boxing y unboxing-
Boxing (y su operacin inversa, unboxing) permiten tratar a los tipos valor como
objetos (tipo referencia). Los tipos de valor, incluidos los struct y los predefinidos,
como int, se pueden convertir al tipo object (boxing) y desde el tipo object
(unboxing).
La posibilidad de realizar boxing permite construir funciones polimrficas: pueden realizar una operacin sobre un objeto sin conocer su tipo concreto.
void Polim(object o)
{
Console.WriteLine(o.ToString());
}
...
Polim(42);
Polim("abcd");
Polim(12.345678901234M);
Polim(new Point(23,45));
Boxing
Boxing es una conversin implcita de un tipo valor al tipo object. Cuando se realiza
boxing de un valor, se asigna una instancia de objeto y se copia el valor en el nuevo objeto.
Por ejemplo, considere la siguiente declaracin de una variable de tipo de valor:
int i = 123;
La siguiente instruccin aplica implcitamente la operacin de boxing sobre la variable
i: object o = i;
El resultado de esta instruccin es crear un objeto o en la pila que hace referencia a un
valor del tipo int alojado en el heap. Este valor es una copia del valor del tipo de valor
asignado a la variable i. La diferencia entre las dos variables, i y o se muestra en la
siguiente figura:
En definitiva, el efecto del boxing es el de cualquier otro tipo de casting pero:
el contenido de la variable se copia al heap se crea una referencia a sta copia
Aunque no es necesario, tambin es posible realizar el boxing explcitamente como en
el siguiente ejemplo:
int i = 123;
object o = (object) i;
El siguiente ejemplo convierte una variable entera i a un objeto o mediante boxing. A
continuacin, el valor almacenado en la variable i se cambia de 123 a 456. El ejemplo
muestra que el objeto mantiene la copia original del contenido, 123.
// Boxing de una variable int
using System;
class TestBoxing
{
public static void Main()
{
int i = 123;
object o = i; // boxing implicito
i = 456; // Modifica el valor de i
Console.WriteLine("Valor (tipo valor) = {0}",
i);
Console.WriteLine("Valor (tipo object)= {0}",
o);
}
}
El resultado de su ejecucin es: Valor (tipo valor) = 456
Valor (tipo object)= 123
Unboxing
Una vez que se ha hecho boxing sobre un dato y disponemos de un object no puede
hacerse demasiado con l ya que no pueden emplearse mtodos o propiedades del tipo original: el compilador no puede conocer el tipo original sobre el que se hizo boxing.
string s1 = "Hola";
object o = s1; // boxing
...
if (o.Lenght > 0) // ERROR
Una vez que se ha hecho boxing puede deshacerse la conversin (unboxing) haciendo
casting explcito al tipo de dato inicial.
string s2 = (string) o; // unboxing
Afortunadamente es posible conocer el tipo, de manera que si la conversin no es
posible se lanza una excepcin. Pueden utilizarse los operadores is y as para
determinar la correccin de la conversin:
string s2;
if (o is string)
s2 = (string) o; // unboxing
o alternativamente: string s2 = o as string; // conversion
if (s2 != null) // OK, la conversion funciono
Conclusiones
Ventajas del sistema unificado de tipos: las colecciones funcionan sobre cualquier tipo.
Hashtable t = new Hashtable();
t.Add(0, "zero");
t.Add(1, "one");
t.Add(2, "two");
string s = string.Format("Your total was {0} on {1}",
total, date);
Desventajas del sistema unificado de tipos: Eficiencia.
La necesidad de utilizar boxing disminuir cuando el CLR permita genricos (algo
similar a los templates en C++).
Cadenas de caracteres
Una cadena de caracteres no es ms que una secuencia de caracteres Unicode. En
C# se representan mediante objetos del tipo string, que no es ms que un alias del
tipo System.String incluido en la BCL.
El tipo string es un tipo referencia. Representa una serie de caracteres inmutable. Se
dice que una instancia de String es inmutable porque no se puede modificar su valor
una vez creada. Los mtodos que aparentemente modifican una cadena devuelven en
realidad una cadena nueva que contiene la modificacin.
Recuerde la particularidad de este tipo sobre el operador de asignacin: su
funcionamiento es como si fuera un tipo valor. Este es, realmente, el funcionamiento
obtenido con el mtodo Copy(). Si no se desea obtener una copia (independiente)
sino una copia en el sentido de un tipo valor emplee el mtodo Clone().
Puede accederse a cada uno de los caracteres de la cadena mediante ndice, como
ocurre habitualmente en otros lenguajes, siendo la primera posicin asociada al ndice cero. Este acceso, no obstante, slo est permitido para lectura.
string s = "!!Hola, mundo!!";;
for (int i=0; i < s.Length; i++)
Console.Write (s[i]);
Este ejemplo muestra todos los caracteres que componen la cadena, uno a uno. El
ciclo realiza tantas iteraciones como nmero de caracteres forman la cadena (su
longitud) que se consulta usando la propiedad Length.
Por definicin, un objeto String, incluida la cadena vaca (""), es mayor que una
referencia nula y dos referencias nulas son iguales entre s. El carcter null se define
como el hexadecimal 0x00. Puede consultarse si una cadena es vaca empleando la
propiedad esttica (slo lectura) Empty: el valor de este campo es la cadena de
longitud cero o cadena vaca, "". Una cadena vaca no es igual que una cadena cuyo
valor sea null.
Los procedimientos de comparacin y de bsqueda distinguen maysculas de
minsculas de forma predeterminada. Pueden emplearse los mtodos Compare() y
Equals() para realizar referencias combinadas y comparaciones entre valores de
instancias de Object y String. Los operadores relacionales == y != se implementan
con el mtodo Equals().
El mtodo Concat() concatena una o ms instancias de String o las
representaciones de tipo String de los valores de una o ms instancias de Object. El
operador + est sobrecargado para realizar la concatenacin. Por ejemplo, el siguiente
cdigo:
string s1 = "Esto es una cadena... como en C++";
string s2 = "Esto es una cadena... ";
string s3 = "como en C++";
string s4 = s2 + s3;
string s5 = String.Concat(s2, s3);
Console.WriteLine ("s1 = {0}", s1);
Console.WriteLine ("s4 = {0}", s4);
Console.WriteLine ("s5 = {0}", s5);
if ((s1 == s4) && (s1.Equals(s5)))
Console.WriteLine ("s1 == s4 == s5");
produce este resultado: s1 = Esto es una cadena... como en C++
s4 = Esto es una cadena... como en C++
s5 = Esto es una cadena... como en C++
s1 == s4 == s5
Un mtodo particularmente til es Split(), que devuelve un vector de cadenas
resultante de "partir" la cadena sobre la que se aplica en palabras:
string linea;
string [] palabras;
...
palabras = linea.Split (null); // null indica dividir por espacios
En definitiva, la clase String incluye numerosos mtodos, que pueden emplease
para:
Realizar bsquedas en cadenas de caracteres: IndexOf(),
LastIndexOf(),
StartsWith(), EndsWith()
Eliminar e insertar espacios en blanco: Trim(), PadLeft(),
PadRight()
Manipular subcadenas: Insert(), Remove(), Replace(),
Substring(),
Join()
Modificar cadenas de caracteres: ToLower(), ToUpper(),
Format() (al estilo del printf de C, pero seguro).
Vectores y matrices
Un vector (matriz) en C# es radicalmente diferente a un vector (matriz) en C++: ms
que una coleccin de variables que comparten un nombre y accesibles por ndice, en
C# se trata de una instancia de la clase System.Array, y en consecuencia se trata de
una coleccin que se almacena en el heap y que est bajo el control del gestor de memoria.
Todas las tablas que definamos, sea cual sea el tipo de elementos que contengan, son
objetos que derivan de System.Array. Ese espacio de nombres proporciona mtodos
para la creacin, manipulacin, bsqueda y ordenacin de matrices, por lo tanto, sirve como clase base para todas las matrices de la CLR (Common Languag